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 <cmath>
7#include <iostream>
8#include <sstream>
9#include <iomanip>
10#include <typeinfo>
11
12#include "file.hpp"
13#include "eval.hpp"
14#include "ast.hpp"
15#include "bind.hpp"
16#include "util.hpp"
17#include "inspect.hpp"
18#include "operators.hpp"
19#include "environment.hpp"
20#include "position.hpp"
21#include "sass/values.h"
22#include "to_value.hpp"
23#include "ast2c.hpp"
24#include "c2ast.hpp"
25#include "context.hpp"
26#include "backtrace.hpp"
27#include "lexer.hpp"
28#include "prelexer.hpp"
29#include "parser.hpp"
30#include "expand.hpp"
31#include "color_maps.hpp"
32#include "sass_functions.hpp"
33#include "error_handling.hpp"
34#include "util_string.hpp"
35
36namespace Sass {
37
38 Eval::Eval(Expand& exp)
39 : exp(exp),
40 ctx(exp.ctx),
41 traces(exp.traces),
42 force(false),
43 is_in_comment(false),
44 is_in_selector_schema(false)
45 {
46 bool_true = SASS_MEMORY_NEW(Boolean, "[NA]", true);
47 bool_false = SASS_MEMORY_NEW(Boolean, "[NA]", false);
48 }
49 Eval::~Eval() { }
50
51 Env* Eval::environment()
52 {
53 return exp.environment();
54 }
55
56 const sass::string Eval::cwd()
57 {
58 return ctx.cwd();
59 }
60
61 struct Sass_Inspect_Options& Eval::options()
62 {
63 return ctx.c_options;
64 }
65
66 struct Sass_Compiler* Eval::compiler()
67 {
68 return ctx.c_compiler;
69 }
70
71 EnvStack& Eval::env_stack()
72 {
73 return exp.env_stack;
74 }
75
76 sass::vector<Sass_Callee>& Eval::callee_stack()
77 {
78 return ctx.callee_stack;
79 }
80
81 Expression* Eval::operator()(Block* b)
82 {
83 Expression* val = 0;
84 for (size_t i = 0, L = b->length(); i < L; ++i) {
85 val = b->at(i)->perform(op: this);
86 if (val) return val;
87 }
88 return val;
89 }
90
91 Expression* Eval::operator()(Assignment* a)
92 {
93 Env* env = environment();
94 sass::string var(a->variable());
95 if (a->is_global()) {
96 if (!env->has_global(key: var)) {
97 deprecated(
98 msg: "!global assignments won't be able to declare new variables in future versions.",
99 msg2: "Consider adding `" + var + ": null` at the top level.",
100 with_column: true, pstate: a->pstate());
101 }
102 if (a->is_default()) {
103 if (env->has_global(key: var)) {
104 Expression* e = Cast<Expression>(ptr: env->get_global(key: var));
105 if (!e || e->concrete_type() == Expression::NULL_VAL) {
106 env->set_global(key: var, val: a->value()->perform(op: this));
107 }
108 }
109 else {
110 env->set_global(key: var, val: a->value()->perform(op: this));
111 }
112 }
113 else {
114 env->set_global(key: var, val: a->value()->perform(op: this));
115 }
116 }
117 else if (a->is_default()) {
118 if (env->has_lexical(key: var)) {
119 auto cur = env;
120 while (cur && cur->is_lexical()) {
121 if (cur->has_local(key: var)) {
122 if (AST_Node_Obj node = cur->get_local(key: var)) {
123 Expression* e = Cast<Expression>(ptr: node);
124 if (!e || e->concrete_type() == Expression::NULL_VAL) {
125 cur->set_local(key: var, val: a->value()->perform(op: this));
126 }
127 }
128 else {
129 throw std::runtime_error("Env not in sync");
130 }
131 return 0;
132 }
133 cur = cur->parent();
134 }
135 throw std::runtime_error("Env not in sync");
136 }
137 else if (env->has_global(key: var)) {
138 if (AST_Node_Obj node = env->get_global(key: var)) {
139 Expression* e = Cast<Expression>(ptr: node);
140 if (!e || e->concrete_type() == Expression::NULL_VAL) {
141 env->set_global(key: var, val: a->value()->perform(op: this));
142 }
143 }
144 }
145 else if (env->is_lexical()) {
146 env->set_local(key: var, val: a->value()->perform(op: this));
147 }
148 else {
149 env->set_local(key: var, val: a->value()->perform(op: this));
150 }
151 }
152 else {
153 env->set_lexical(key: var, val: a->value()->perform(op: this));
154 }
155 return 0;
156 }
157
158 Expression* Eval::operator()(If* i)
159 {
160 ExpressionObj rv;
161 Env env(environment());
162 env_stack().push_back(x: &env);
163 ExpressionObj cond = i->predicate()->perform(op: this);
164 if (!cond->is_false()) {
165 rv = i->block()->perform(op: this);
166 }
167 else {
168 Block_Obj alt = i->alternative();
169 if (alt) rv = alt->perform(op: this);
170 }
171 env_stack().pop_back();
172 return rv.detach();
173 }
174
175 // For does not create a new env scope
176 // But iteration vars are reset afterwards
177 Expression* Eval::operator()(ForRule* f)
178 {
179 sass::string variable(f->variable());
180 ExpressionObj low = f->lower_bound()->perform(op: this);
181 if (low->concrete_type() != Expression::NUMBER) {
182 traces.push_back(x: Backtrace(low->pstate()));
183 throw Exception::TypeMismatch(traces, *low, "integer");
184 }
185 ExpressionObj high = f->upper_bound()->perform(op: this);
186 if (high->concrete_type() != Expression::NUMBER) {
187 traces.push_back(x: Backtrace(high->pstate()));
188 throw Exception::TypeMismatch(traces, *high, "integer");
189 }
190 Number_Obj sass_start = Cast<Number>(ptr: low);
191 Number_Obj sass_end = Cast<Number>(ptr: high);
192 // check if units are valid for sequence
193 if (sass_start->unit() != sass_end->unit()) {
194 sass::ostream msg; msg << "Incompatible units: '"
195 << sass_end->unit() << "' and '"
196 << sass_start->unit() << "'.";
197 error(msg: msg.str(), pstate: low->pstate(), traces);
198 }
199 double start = sass_start->value();
200 double end = sass_end->value();
201 // only create iterator once in this environment
202 Env env(environment(), true);
203 env_stack().push_back(x: &env);
204 Block_Obj body = f->block();
205 Expression* val = 0;
206 if (start < end) {
207 if (f->is_inclusive()) ++end;
208 for (double i = start;
209 i < end;
210 ++i) {
211 Number_Obj it = SASS_MEMORY_NEW(Number, low->pstate(), i, sass_end->unit());
212 env.set_local(key: variable, val: it);
213 val = body->perform(op: this);
214 if (val) break;
215 }
216 } else {
217 if (f->is_inclusive()) --end;
218 for (double i = start;
219 i > end;
220 --i) {
221 Number_Obj it = SASS_MEMORY_NEW(Number, low->pstate(), i, sass_end->unit());
222 env.set_local(key: variable, val: it);
223 val = body->perform(op: this);
224 if (val) break;
225 }
226 }
227 env_stack().pop_back();
228 return val;
229 }
230
231 // Eval does not create a new env scope
232 // But iteration vars are reset afterwards
233 Expression* Eval::operator()(EachRule* e)
234 {
235 sass::vector<sass::string> variables(e->variables());
236 ExpressionObj expr = e->list()->perform(op: this);
237 Env env(environment(), true);
238 env_stack().push_back(x: &env);
239 List_Obj list;
240 Map* map = nullptr;
241 if (expr->concrete_type() == Expression::MAP) {
242 map = Cast<Map>(ptr: expr);
243 }
244 else if (SelectorList * ls = Cast<SelectorList>(ptr: expr)) {
245 ExpressionObj rv = Listize::perform(node: ls);
246 list = Cast<List>(ptr: rv);
247 }
248 else if (expr->concrete_type() != Expression::LIST) {
249 list = SASS_MEMORY_NEW(List, expr->pstate(), 1, SASS_COMMA);
250 list->append(element: expr);
251 }
252 else {
253 list = Cast<List>(ptr: expr);
254 }
255
256 Block_Obj body = e->block();
257 ExpressionObj val;
258
259 if (map) {
260 for (ExpressionObj key : map->keys()) {
261 ExpressionObj value = map->at(k: key);
262
263 if (variables.size() == 1) {
264 List* variable = SASS_MEMORY_NEW(List, map->pstate(), 2, SASS_SPACE);
265 variable->append(element: key);
266 variable->append(element: value);
267 env.set_local(key: variables[0], val: variable);
268 } else {
269 env.set_local(key: variables[0], val: key);
270 env.set_local(key: variables[1], val: value);
271 }
272
273 val = body->perform(op: this);
274 if (val) break;
275 }
276 }
277 else {
278 if (list->length() == 1 && Cast<SelectorList>(ptr: list)) {
279 list = Cast<List>(ptr: list);
280 }
281 for (size_t i = 0, L = list->length(); i < L; ++i) {
282 Expression* item = list->at(i);
283 // unwrap value if the expression is an argument
284 if (Argument* arg = Cast<Argument>(ptr: item)) item = arg->value();
285 // check if we got passed a list of args (investigate)
286 if (List* scalars = Cast<List>(ptr: item)) {
287 if (variables.size() == 1) {
288 Expression* var = scalars;
289 env.set_local(key: variables[0], val: var);
290 } else {
291 // https://github.com/sass/libsass/issues/3078
292 for (size_t j = 0, K = variables.size(); j < K; ++j) {
293 env.set_local(key: variables[j], val: j >= scalars->length()
294 ? SASS_MEMORY_NEW(Null, expr->pstate()) : scalars->at(i: j));
295 }
296 }
297 } else {
298 if (variables.size() > 0) {
299 env.set_local(key: variables.at(n: 0), val: item);
300 for (size_t j = 1, K = variables.size(); j < K; ++j) {
301 // XXX: this is never hit via spec tests
302 Expression* res = SASS_MEMORY_NEW(Null, expr->pstate());
303 env.set_local(key: variables[j], val: res);
304 }
305 }
306 }
307 val = body->perform(op: this);
308 if (val) break;
309 }
310 }
311 env_stack().pop_back();
312 return val.detach();
313 }
314
315 Expression* Eval::operator()(WhileRule* w)
316 {
317 ExpressionObj pred = w->predicate();
318 Block_Obj body = w->block();
319 Env env(environment(), true);
320 env_stack().push_back(x: &env);
321 ExpressionObj cond = pred->perform(op: this);
322 while (!cond->is_false()) {
323 ExpressionObj val = body->perform(op: this);
324 if (val) {
325 env_stack().pop_back();
326 return val.detach();
327 }
328 cond = pred->perform(op: this);
329 }
330 env_stack().pop_back();
331 return 0;
332 }
333
334 Expression* Eval::operator()(Return* r)
335 {
336 return r->value()->perform(op: this);
337 }
338
339 Expression* Eval::operator()(WarningRule* w)
340 {
341 Sass_Output_Style outstyle = options().output_style;
342 options().output_style = NESTED;
343 ExpressionObj message = w->message()->perform(op: this);
344 Env* env = environment();
345
346 // try to use generic function
347 if (env->has(key: "@warn[f]")) {
348
349 // add call stack entry
350 callee_stack().push_back(x: {
351 .name: "@warn",
352 .path: w->pstate().getPath(),
353 .line: w->pstate().getLine(),
354 .column: w->pstate().getColumn(),
355 .type: SASS_CALLEE_FUNCTION,
356 .env: { .frame: env }
357 });
358
359 Definition* def = Cast<Definition>(ptr: (*env)["@warn[f]"]);
360 // Block_Obj 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(cb: c_function);
364
365 AST2C ast2c;
366 union Sass_Value* c_args = sass_make_list(len: 1, sep: SASS_COMMA, is_bracketed: false);
367 sass_list_set_value(v: c_args, i: 0, value: message->perform(op: &ast2c));
368 union Sass_Value* c_val = c_func(c_args, c_function, compiler());
369 options().output_style = outstyle;
370 callee_stack().pop_back();
371 sass_delete_value(val: c_args);
372 sass_delete_value(val: c_val);
373 return 0;
374
375 }
376
377 sass::string result(unquote(message->to_sass()));
378 std::cerr << "WARNING: " << result << std::endl;
379 traces.push_back(x: Backtrace(w->pstate()));
380 std::cerr << traces_to_string(traces, indent: " ");
381 std::cerr << std::endl;
382 options().output_style = outstyle;
383 traces.pop_back();
384 return 0;
385 }
386
387 Expression* Eval::operator()(ErrorRule* e)
388 {
389 Sass_Output_Style outstyle = options().output_style;
390 options().output_style = NESTED;
391 ExpressionObj message = e->message()->perform(op: this);
392 Env* env = environment();
393
394 // try to use generic function
395 if (env->has(key: "@error[f]")) {
396
397 // add call stack entry
398 callee_stack().push_back(x: {
399 .name: "@error",
400 .path: e->pstate().getPath(),
401 .line: e->pstate().getLine(),
402 .column: e->pstate().getColumn(),
403 .type: SASS_CALLEE_FUNCTION,
404 .env: { .frame: env }
405 });
406
407 Definition* def = Cast<Definition>(ptr: (*env)["@error[f]"]);
408 // Block_Obj body = def->block();
409 // Native_Function func = def->native_function();
410 Sass_Function_Entry c_function = def->c_function();
411 Sass_Function_Fn c_func = sass_function_get_function(cb: c_function);
412
413 AST2C ast2c;
414 union Sass_Value* c_args = sass_make_list(len: 1, sep: SASS_COMMA, is_bracketed: false);
415 sass_list_set_value(v: c_args, i: 0, value: message->perform(op: &ast2c));
416 union Sass_Value* c_val = c_func(c_args, c_function, compiler());
417 options().output_style = outstyle;
418 callee_stack().pop_back();
419 sass_delete_value(val: c_args);
420 sass_delete_value(val: c_val);
421 return 0;
422
423 }
424
425 sass::string result(unquote(message->to_sass()));
426 options().output_style = outstyle;
427 error(msg: result, pstate: e->pstate(), traces);
428 return 0;
429 }
430
431 Expression* Eval::operator()(DebugRule* d)
432 {
433 Sass_Output_Style outstyle = options().output_style;
434 options().output_style = NESTED;
435 ExpressionObj message = d->value()->perform(op: this);
436 Env* env = environment();
437
438 // try to use generic function
439 if (env->has(key: "@debug[f]")) {
440
441 // add call stack entry
442 callee_stack().push_back(x: {
443 .name: "@debug",
444 .path: d->pstate().getPath(),
445 .line: d->pstate().getLine(),
446 .column: d->pstate().getColumn(),
447 .type: SASS_CALLEE_FUNCTION,
448 .env: { .frame: env }
449 });
450
451 Definition* def = Cast<Definition>(ptr: (*env)["@debug[f]"]);
452 // Block_Obj body = def->block();
453 // Native_Function func = def->native_function();
454 Sass_Function_Entry c_function = def->c_function();
455 Sass_Function_Fn c_func = sass_function_get_function(cb: c_function);
456
457 AST2C ast2c;
458 union Sass_Value* c_args = sass_make_list(len: 1, sep: SASS_COMMA, is_bracketed: false);
459 sass_list_set_value(v: c_args, i: 0, value: message->perform(op: &ast2c));
460 union Sass_Value* c_val = c_func(c_args, c_function, compiler());
461 options().output_style = outstyle;
462 callee_stack().pop_back();
463 sass_delete_value(val: c_args);
464 sass_delete_value(val: c_val);
465 return 0;
466
467 }
468
469 sass::string result(unquote(message->to_sass()));
470 sass::string abs_path(Sass::File::rel2abs(path: d->pstate().getPath(), base: cwd(), cwd: cwd()));
471 sass::string rel_path(Sass::File::abs2rel(path: d->pstate().getPath(), base: cwd(), cwd: cwd()));
472 sass::string output_path(Sass::File::path_for_console(rel_path, abs_path, orig_path: d->pstate().getPath()));
473 options().output_style = outstyle;
474
475 std::cerr << output_path << ":" << d->pstate().getLine() << " DEBUG: " << result;
476 std::cerr << std::endl;
477 return 0;
478 }
479
480
481 Expression* Eval::operator()(List* l)
482 {
483 // special case for unevaluated map
484 if (l->separator() == SASS_HASH) {
485 Map_Obj lm = SASS_MEMORY_NEW(Map,
486 l->pstate(),
487 l->length() / 2);
488 for (size_t i = 0, L = l->length(); i < L; i += 2)
489 {
490 ExpressionObj key = (*l)[i+0]->perform(op: this);
491 ExpressionObj val = (*l)[i+1]->perform(op: this);
492 // make sure the color key never displays its real name
493 key->is_delayed(is_delayed__: true); // verified
494 *lm << std::make_pair(x&: key, y&: val);
495 }
496 if (lm->has_duplicate_key()) {
497 traces.push_back(x: Backtrace(l->pstate()));
498 throw Exception::DuplicateKeyError(traces, *lm, *l);
499 }
500
501 lm->is_interpolant(is_interpolant__: l->is_interpolant());
502 return lm->perform(op: this);
503 }
504 // check if we should expand it
505 if (l->is_expanded()) return l;
506 // regular case for unevaluated lists
507 List_Obj ll = SASS_MEMORY_NEW(List,
508 l->pstate(),
509 l->length(),
510 l->separator(),
511 l->is_arglist(),
512 l->is_bracketed());
513 for (size_t i = 0, L = l->length(); i < L; ++i) {
514 ll->append(element: (*l)[i]->perform(op: this));
515 }
516 ll->is_interpolant(is_interpolant__: l->is_interpolant());
517 ll->from_selector(from_selector__: l->from_selector());
518 ll->is_expanded(is_expanded__: true);
519 return ll.detach();
520 }
521
522 Expression* Eval::operator()(Map* m)
523 {
524 if (m->is_expanded()) return m;
525
526 // make sure we're not starting with duplicate keys.
527 // the duplicate key state will have been set in the parser phase.
528 if (m->has_duplicate_key()) {
529 traces.push_back(x: Backtrace(m->pstate()));
530 throw Exception::DuplicateKeyError(traces, *m, *m);
531 }
532
533 Map_Obj mm = SASS_MEMORY_NEW(Map,
534 m->pstate(),
535 m->length());
536 for (auto key : m->keys()) {
537 Expression* ex_key = key->perform(op: this);
538 Expression* ex_val = m->at(k: key);
539 if (ex_val == NULL) continue;
540 ex_val = ex_val->perform(op: this);
541 *mm << std::make_pair(x&: ex_key, y&: ex_val);
542 }
543
544 // check the evaluated keys aren't duplicates.
545 if (mm->has_duplicate_key()) {
546 traces.push_back(x: Backtrace(m->pstate()));
547 throw Exception::DuplicateKeyError(traces, *mm, *m);
548 }
549
550 mm->is_expanded(is_expanded__: true);
551 return mm.detach();
552 }
553
554 Expression* Eval::operator()(Binary_Expression* b_in)
555 {
556
557 ExpressionObj lhs = b_in->left();
558 ExpressionObj rhs = b_in->right();
559 enum Sass_OP op_type = b_in->optype();
560
561 if (op_type == Sass_OP::AND) {
562 // LOCAL_FLAG(force, true);
563 lhs = lhs->perform(op: this);
564 if (!*lhs) return lhs.detach();
565 return rhs->perform(op: this);
566 }
567 else if (op_type == Sass_OP::OR) {
568 // LOCAL_FLAG(force, true);
569 lhs = lhs->perform(op: this);
570 if (*lhs) return lhs.detach();
571 return rhs->perform(op: this);
572 }
573
574 // Evaluate variables as early o
575 while (Variable* l_v = Cast<Variable>(ptr: lhs)) {
576 lhs = operator()(l_v);
577 }
578 while (Variable* r_v = Cast<Variable>(ptr: rhs)) {
579 rhs = operator()(r_v);
580 }
581
582 Binary_ExpressionObj b = b_in;
583
584 // Evaluate sub-expressions early on
585 while (Binary_Expression* l_b = Cast<Binary_Expression>(ptr: lhs)) {
586 if (!force && l_b->is_delayed()) break;
587 lhs = operator()(b_in: l_b);
588 }
589 while (Binary_Expression* r_b = Cast<Binary_Expression>(ptr: rhs)) {
590 if (!force && r_b->is_delayed()) break;
591 rhs = operator()(b_in: r_b);
592 }
593
594 // don't eval delayed expressions (the '/' when used as a separator)
595 if (!force && op_type == Sass_OP::DIV && b->is_delayed()) {
596 b->right(right__: b->right()->perform(op: this));
597 b->left(left__: b->left()->perform(op: this));
598 return b.detach();
599 }
600
601 // specific types we know are final
602 // handle them early to avoid overhead
603 if (Number* l_n = Cast<Number>(ptr: lhs)) {
604 // lhs is number and rhs is number
605 if (Number* r_n = Cast<Number>(ptr: rhs)) {
606 try {
607 switch (op_type) {
608 case Sass_OP::EQ: return *l_n == *r_n ? bool_true : bool_false;
609 case Sass_OP::NEQ: return *l_n == *r_n ? bool_false : bool_true;
610 case Sass_OP::LT: return *l_n < *r_n ? bool_true : bool_false;
611 case Sass_OP::GTE: return *l_n < *r_n ? bool_false : bool_true;
612 case Sass_OP::LTE: return *l_n < *r_n || *l_n == *r_n ? bool_true : bool_false;
613 case Sass_OP::GT: return *l_n < *r_n || *l_n == *r_n ? bool_false : bool_true;
614 case Sass_OP::ADD: case Sass_OP::SUB: case Sass_OP::MUL: case Sass_OP::DIV: case Sass_OP::MOD:
615 return Operators::op_numbers(op_type, *l_n, *r_n, opt: options(), pstate: b_in->pstate());
616 default: break;
617 }
618 }
619 catch (Exception::OperationError& err)
620 {
621 traces.push_back(x: Backtrace(b_in->pstate()));
622 throw Exception::SassValueError(traces, b_in->pstate(), err);
623 }
624 }
625 // lhs is number and rhs is color
626 // Todo: allow to work with HSLA colors
627 else if (Color* r_col = Cast<Color>(ptr: rhs)) {
628 Color_RGBA_Obj r_c = r_col->toRGBA();
629 try {
630 switch (op_type) {
631 case Sass_OP::EQ: return *l_n == *r_c ? bool_true : bool_false;
632 case Sass_OP::NEQ: return *l_n == *r_c ? bool_false : bool_true;
633 case Sass_OP::ADD: case Sass_OP::SUB: case Sass_OP::MUL: case Sass_OP::DIV: case Sass_OP::MOD:
634 return Operators::op_number_color(op_type, *l_n, *r_c, opt: options(), pstate: b_in->pstate());
635 default: break;
636 }
637 }
638 catch (Exception::OperationError& err)
639 {
640 traces.push_back(x: Backtrace(b_in->pstate()));
641 throw Exception::SassValueError(traces, b_in->pstate(), err);
642 }
643 }
644 }
645 else if (Color* l_col = Cast<Color>(ptr: lhs)) {
646 Color_RGBA_Obj l_c = l_col->toRGBA();
647 // lhs is color and rhs is color
648 if (Color* r_col = Cast<Color>(ptr: rhs)) {
649 Color_RGBA_Obj r_c = r_col->toRGBA();
650 try {
651 switch (op_type) {
652 case Sass_OP::EQ: return *l_c == *r_c ? bool_true : bool_false;
653 case Sass_OP::NEQ: return *l_c == *r_c ? bool_false : bool_true;
654 case Sass_OP::LT: return *l_c < *r_c ? bool_true : bool_false;
655 case Sass_OP::GTE: return *l_c < *r_c ? bool_false : bool_true;
656 case Sass_OP::LTE: return *l_c < *r_c || *l_c == *r_c ? bool_true : bool_false;
657 case Sass_OP::GT: return *l_c < *r_c || *l_c == *r_c ? bool_false : bool_true;
658 case Sass_OP::ADD: case Sass_OP::SUB: case Sass_OP::MUL: case Sass_OP::DIV: case Sass_OP::MOD:
659 return Operators::op_colors(op_type, *l_c, *r_c, opt: options(), pstate: b_in->pstate());
660 default: break;
661 }
662 }
663 catch (Exception::OperationError& err)
664 {
665 traces.push_back(x: Backtrace(b_in->pstate()));
666 throw Exception::SassValueError(traces, b_in->pstate(), err);
667 }
668 }
669 // lhs is color and rhs is number
670 else if (Number* r_n = Cast<Number>(ptr: rhs)) {
671 try {
672 switch (op_type) {
673 case Sass_OP::EQ: return *l_c == *r_n ? bool_true : bool_false;
674 case Sass_OP::NEQ: return *l_c == *r_n ? bool_false : bool_true;
675 case Sass_OP::ADD: case Sass_OP::SUB: case Sass_OP::MUL: case Sass_OP::DIV: case Sass_OP::MOD:
676 return Operators::op_color_number(op_type, *l_c, *r_n, opt: options(), pstate: b_in->pstate());
677 default: break;
678 }
679 }
680 catch (Exception::OperationError& err)
681 {
682 traces.push_back(x: Backtrace(b_in->pstate()));
683 throw Exception::SassValueError(traces, b_in->pstate(), err);
684 }
685 }
686 }
687
688 String_Schema_Obj ret_schema;
689
690 // only the last item will be used to eval the binary expression
691 if (String_Schema* s_l = Cast<String_Schema>(ptr: b->left())) {
692 if (!s_l->has_interpolant() && (!s_l->is_right_interpolant())) {
693 ret_schema = SASS_MEMORY_NEW(String_Schema, b->pstate());
694 Binary_ExpressionObj bin_ex = SASS_MEMORY_NEW(Binary_Expression, b->pstate(),
695 b->op(), s_l->last(), b->right());
696 bin_ex->is_delayed(is_delayed__: b->left()->is_delayed() || b->right()->is_delayed()); // unverified
697 for (size_t i = 0; i < s_l->length() - 1; ++i) {
698 ret_schema->append(element: s_l->at(i)->perform(op: this));
699 }
700 ret_schema->append(element: bin_ex->perform(op: this));
701 return ret_schema->perform(op: this);
702 }
703 }
704 if (String_Schema* s_r = Cast<String_Schema>(ptr: b->right())) {
705
706 if (!s_r->has_interpolant() && (!s_r->is_left_interpolant() || op_type == Sass_OP::DIV)) {
707 ret_schema = SASS_MEMORY_NEW(String_Schema, b->pstate());
708 Binary_ExpressionObj bin_ex = SASS_MEMORY_NEW(Binary_Expression, b->pstate(),
709 b->op(), b->left(), s_r->first());
710 bin_ex->is_delayed(is_delayed__: b->left()->is_delayed() || b->right()->is_delayed()); // verified
711 ret_schema->append(element: bin_ex->perform(op: this));
712 for (size_t i = 1; i < s_r->length(); ++i) {
713 ret_schema->append(element: s_r->at(i)->perform(op: this));
714 }
715 return ret_schema->perform(op: this);
716 }
717 }
718
719 // fully evaluate their values
720 if (op_type == Sass_OP::EQ ||
721 op_type == Sass_OP::NEQ ||
722 op_type == Sass_OP::GT ||
723 op_type == Sass_OP::GTE ||
724 op_type == Sass_OP::LT ||
725 op_type == Sass_OP::LTE)
726 {
727 LOCAL_FLAG(force, true);
728 lhs->is_expanded(is_expanded__: false);
729 lhs->set_delayed(false);
730 lhs = lhs->perform(op: this);
731 rhs->is_expanded(is_expanded__: false);
732 rhs->set_delayed(false);
733 rhs = rhs->perform(op: this);
734 }
735 else {
736 lhs = lhs->perform(op: this);
737 }
738
739 // not a logical connective, so go ahead and eval the rhs
740 rhs = rhs->perform(op: this);
741 AST_Node_Obj lu = lhs;
742 AST_Node_Obj ru = rhs;
743
744 Expression::Type l_type;
745 Expression::Type r_type;
746
747 // Is one of the operands an interpolant?
748 String_Schema_Obj s1 = Cast<String_Schema>(ptr: b->left());
749 String_Schema_Obj s2 = Cast<String_Schema>(ptr: b->right());
750 Binary_ExpressionObj b1 = Cast<Binary_Expression>(ptr: b->left());
751 Binary_ExpressionObj b2 = Cast<Binary_Expression>(ptr: b->right());
752
753 bool schema_op = false;
754
755 bool force_delay = (s2 && s2->is_left_interpolant()) ||
756 (s1 && s1->is_right_interpolant()) ||
757 (b1 && b1->is_right_interpolant()) ||
758 (b2 && b2->is_left_interpolant());
759
760 if ((s1 && s1->has_interpolants()) || (s2 && s2->has_interpolants()) || force_delay)
761 {
762 if (op_type == Sass_OP::DIV || op_type == Sass_OP::MUL || op_type == Sass_OP::MOD || op_type == Sass_OP::ADD || op_type == Sass_OP::SUB ||
763 op_type == Sass_OP::EQ) {
764 // If possible upgrade LHS to a number (for number to string compare)
765 if (String_Constant* str = Cast<String_Constant>(ptr: lhs)) {
766 sass::string value(str->value());
767 const char* start = value.c_str();
768 if (Prelexer::sequence < Prelexer::dimension, Prelexer::end_of_file >(src: start) != 0) {
769 lhs = Parser::lexed_dimension(pstate: b->pstate(), parsed: str->value());
770 }
771 }
772 // If possible upgrade RHS to a number (for string to number compare)
773 if (String_Constant* str = Cast<String_Constant>(ptr: rhs)) {
774 sass::string value(str->value());
775 const char* start = value.c_str();
776 if (Prelexer::sequence < Prelexer::dimension, Prelexer::number >(src: start) != 0) {
777 rhs = Parser::lexed_dimension(pstate: b->pstate(), parsed: str->value());
778 }
779 }
780 }
781
782 To_Value to_value(ctx);
783 ValueObj v_l = Cast<Value>(ptr: lhs->perform(op: &to_value));
784 ValueObj v_r = Cast<Value>(ptr: rhs->perform(op: &to_value));
785
786 if (force_delay) {
787 sass::string str("");
788 str += v_l->to_string(opt: options());
789 if (b->op().ws_before) str += " ";
790 str += b->separator();
791 if (b->op().ws_after) str += " ";
792 str += v_r->to_string(opt: options());
793 String_Constant* val = SASS_MEMORY_NEW(String_Constant, b->pstate(), str);
794 val->is_interpolant(is_interpolant__: b->left()->has_interpolant());
795 return val;
796 }
797 }
798
799 // see if it's a relational expression
800 try {
801 switch(op_type) {
802 case Sass_OP::EQ: return SASS_MEMORY_NEW(Boolean, b->pstate(), Operators::eq(lhs, rhs));
803 case Sass_OP::NEQ: return SASS_MEMORY_NEW(Boolean, b->pstate(), Operators::neq(lhs, rhs));
804 case Sass_OP::GT: return SASS_MEMORY_NEW(Boolean, b->pstate(), Operators::gt(lhs, rhs));
805 case Sass_OP::GTE: return SASS_MEMORY_NEW(Boolean, b->pstate(), Operators::gte(lhs, rhs));
806 case Sass_OP::LT: return SASS_MEMORY_NEW(Boolean, b->pstate(), Operators::lt(lhs, rhs));
807 case Sass_OP::LTE: return SASS_MEMORY_NEW(Boolean, b->pstate(), Operators::lte(lhs, rhs));
808 default: break;
809 }
810 }
811 catch (Exception::OperationError& err)
812 {
813 traces.push_back(x: Backtrace(b->pstate()));
814 throw Exception::SassValueError(traces, b->pstate(), err);
815 }
816
817 l_type = lhs->concrete_type();
818 r_type = rhs->concrete_type();
819
820 // ToDo: throw error in op functions
821 // ToDo: then catch and re-throw them
822 ExpressionObj rv;
823 try {
824 SourceSpan pstate(b->pstate());
825 if (l_type == Expression::NUMBER && r_type == Expression::NUMBER) {
826 Number* l_n = Cast<Number>(ptr: lhs);
827 Number* r_n = Cast<Number>(ptr: rhs);
828 l_n->reduce(); r_n->reduce();
829 rv = Operators::op_numbers(op_type, *l_n, *r_n, opt: options(), pstate);
830 }
831 else if (l_type == Expression::NUMBER && r_type == Expression::COLOR) {
832 Number* l_n = Cast<Number>(ptr: lhs);
833 Color_RGBA_Obj r_c = Cast<Color>(ptr: rhs)->toRGBA();
834 rv = Operators::op_number_color(op_type, *l_n, *r_c, opt: options(), pstate);
835 }
836 else if (l_type == Expression::COLOR && r_type == Expression::NUMBER) {
837 Color_RGBA_Obj l_c = Cast<Color>(ptr: lhs)->toRGBA();
838 Number* r_n = Cast<Number>(ptr: rhs);
839 rv = Operators::op_color_number(op_type, *l_c, *r_n, opt: options(), pstate);
840 }
841 else if (l_type == Expression::COLOR && r_type == Expression::COLOR) {
842 Color_RGBA_Obj l_c = Cast<Color>(ptr: lhs)->toRGBA();
843 Color_RGBA_Obj r_c = Cast<Color>(ptr: rhs)->toRGBA();
844 rv = Operators::op_colors(op_type, *l_c, *r_c, opt: options(), pstate);
845 }
846 else {
847 To_Value to_value(ctx);
848 // this will leak if perform does not return a value!
849 ValueObj v_l = Cast<Value>(ptr: lhs->perform(op: &to_value));
850 ValueObj v_r = Cast<Value>(ptr: rhs->perform(op: &to_value));
851 bool interpolant = b->is_right_interpolant() ||
852 b->is_left_interpolant() ||
853 b->is_interpolant();
854 if (op_type == Sass_OP::SUB) interpolant = false;
855 // if (op_type == Sass_OP::DIV) interpolant = true;
856 // check for type violations
857 if (l_type == Expression::MAP || l_type == Expression::FUNCTION_VAL) {
858 traces.push_back(x: Backtrace(v_l->pstate()));
859 throw Exception::InvalidValue(traces, *v_l);
860 }
861 if (r_type == Expression::MAP || l_type == Expression::FUNCTION_VAL) {
862 traces.push_back(x: Backtrace(v_r->pstate()));
863 throw Exception::InvalidValue(traces, *v_r);
864 }
865 Value* ex = Operators::op_strings(b->op(), *v_l, *v_r, opt: options(), pstate, delayed: !interpolant); // pass true to compress
866 if (String_Constant* str = Cast<String_Constant>(ptr: ex))
867 {
868 if (str->concrete_type() == Expression::STRING)
869 {
870 String_Constant* lstr = Cast<String_Constant>(ptr: lhs);
871 String_Constant* rstr = Cast<String_Constant>(ptr: rhs);
872 if (op_type != Sass_OP::SUB) {
873 if (String_Constant* org = lstr ? lstr : rstr)
874 { str->quote_mark(quote_mark__: org->quote_mark()); }
875 }
876 }
877 }
878 ex->is_interpolant(is_interpolant__: b->is_interpolant());
879 rv = ex;
880 }
881 }
882 catch (Exception::OperationError& err)
883 {
884 traces.push_back(x: Backtrace(b->pstate()));
885 // throw Exception::Base(b->pstate(), err.what());
886 throw Exception::SassValueError(traces, b->pstate(), err);
887 }
888
889 if (rv) {
890 if (schema_op) {
891 // XXX: this is never hit via spec tests
892 (*s2)[0] = rv;
893 rv = s2->perform(op: this);
894 }
895 }
896
897 return rv.detach();
898
899 }
900
901 Expression* Eval::operator()(Unary_Expression* u)
902 {
903 ExpressionObj operand = u->operand()->perform(op: this);
904 if (u->optype() == Unary_Expression::NOT) {
905 Boolean* result = SASS_MEMORY_NEW(Boolean, u->pstate(), (bool)*operand);
906 result->value(value__: !result->value());
907 return result;
908 }
909 else if (Number_Obj nr = Cast<Number>(ptr: operand)) {
910 // negate value for minus unary expression
911 if (u->optype() == Unary_Expression::MINUS) {
912 Number_Obj cpy = SASS_MEMORY_COPY(nr);
913 cpy->value( value__: - cpy->value() ); // negate value
914 return cpy.detach(); // return the copy
915 }
916 else if (u->optype() == Unary_Expression::SLASH) {
917 sass::string str = '/' + nr->to_string(opt: options());
918 return SASS_MEMORY_NEW(String_Constant, u->pstate(), str);
919 }
920 // nothing for positive
921 return nr.detach();
922 }
923 else {
924 // Special cases: +/- variables which evaluate to null output just +/-,
925 // but +/- null itself outputs the string
926 if (operand->concrete_type() == Expression::NULL_VAL && Cast<Variable>(ptr: u->operand())) {
927 u->operand(SASS_MEMORY_NEW(String_Quoted, u->pstate(), ""));
928 }
929 // Never apply unary opertions on colors @see #2140
930 else if (Color* color = Cast<Color>(ptr: operand)) {
931 // Use the color name if this was eval with one
932 if (color->disp().length() > 0) {
933 Unary_ExpressionObj cpy = SASS_MEMORY_COPY(u);
934 cpy->operand(SASS_MEMORY_NEW(String_Constant, operand->pstate(), color->disp()));
935 return SASS_MEMORY_NEW(String_Quoted,
936 cpy->pstate(),
937 cpy->inspect());
938 }
939 }
940 else {
941 Unary_ExpressionObj cpy = SASS_MEMORY_COPY(u);
942 cpy->operand(operand__: operand);
943 return SASS_MEMORY_NEW(String_Quoted,
944 cpy->pstate(),
945 cpy->inspect());
946 }
947
948 return SASS_MEMORY_NEW(String_Quoted,
949 u->pstate(),
950 u->inspect());
951 }
952 // unreachable
953 return u;
954 }
955
956 Expression* Eval::operator()(Function_Call* c)
957 {
958 if (traces.size() > Constants::MaxCallStack) {
959 // XXX: this is never hit via spec tests
960 sass::ostream stm;
961 stm << "Stack depth exceeded max of " << Constants::MaxCallStack;
962 error(msg: stm.str(), pstate: c->pstate(), traces);
963 }
964
965 if (Cast<String_Schema>(ptr: c->sname())) {
966 ExpressionObj evaluated_name = c->sname()->perform(op: this);
967 ExpressionObj evaluated_args = c->arguments()->perform(op: this);
968 sass::string str(evaluated_name->to_string());
969 str += evaluated_args->to_string();
970 return SASS_MEMORY_NEW(String_Constant, c->pstate(), str);
971 }
972
973 sass::string name(Util::normalize_underscores(str: c->name()));
974 sass::string full_name(name + "[f]");
975
976 // we make a clone here, need to implement that further
977 Arguments_Obj args = c->arguments();
978
979 Env* env = environment();
980 if (!env->has(key: full_name) || (!c->via_call() && Prelexer::re_special_fun(src: name.c_str()))) {
981 if (!env->has(key: "*[f]")) {
982 for (Argument_Obj arg : args->elements()) {
983 if (List_Obj ls = Cast<List>(ptr: arg->value())) {
984 if (ls->size() == 0) error(msg: "() isn't a valid CSS value.", pstate: c->pstate(), traces);
985 }
986 }
987 args = Cast<Arguments>(ptr: args->perform(op: this));
988 Function_Call_Obj lit = SASS_MEMORY_NEW(Function_Call,
989 c->pstate(),
990 c->name(),
991 args);
992 if (args->has_named_arguments()) {
993 error(msg: "Plain CSS function " + c->name() + " doesn't support keyword arguments", pstate: c->pstate(), traces);
994 }
995 String_Quoted* str = SASS_MEMORY_NEW(String_Quoted,
996 c->pstate(),
997 lit->to_string(options()));
998 str->is_interpolant(is_interpolant__: c->is_interpolant());
999 return str;
1000 } else {
1001 // call generic function
1002 full_name = "*[f]";
1003 }
1004 }
1005
1006 // further delay for calls
1007 if (full_name != "call[f]") {
1008 args->set_delayed(false); // verified
1009 }
1010 if (full_name != "if[f]") {
1011 args = Cast<Arguments>(ptr: args->perform(op: this));
1012 }
1013 Definition* def = Cast<Definition>(ptr: (*env)[full_name]);
1014
1015 if (c->func()) def = c->func()->definition();
1016
1017 if (def->is_overload_stub()) {
1018 sass::ostream ss;
1019 size_t L = args->length();
1020 // account for rest arguments
1021 if (args->has_rest_argument() && args->length() > 0) {
1022 // get the rest arguments list
1023 List* rest = Cast<List>(ptr: args->last()->value());
1024 // arguments before rest argument plus rest
1025 if (rest) L += rest->length() - 1;
1026 }
1027 ss << full_name << L;
1028 full_name = ss.str();
1029 sass::string resolved_name(full_name);
1030 if (!env->has(key: resolved_name)) error(msg: "overloaded function `" + sass::string(c->name()) + "` given wrong number of arguments", pstate: c->pstate(), traces);
1031 def = Cast<Definition>(ptr: (*env)[resolved_name]);
1032 }
1033
1034 ExpressionObj result = c;
1035 Block_Obj body = def->block();
1036 Native_Function func = def->native_function();
1037 Sass_Function_Entry c_function = def->c_function();
1038
1039 if (c->is_css()) return result.detach();
1040
1041 Parameters_Obj params = def->parameters();
1042 Env fn_env(def->environment());
1043 env_stack().push_back(x: &fn_env);
1044
1045 if (func || body) {
1046 bind(type: sass::string("Function"), name: c->name(), params, args, &fn_env, this, traces);
1047 sass::string msg(", in function `" + c->name() + "`");
1048 traces.push_back(x: Backtrace(c->pstate(), msg));
1049 callee_stack().push_back(x: {
1050 .name: c->name().c_str(),
1051 .path: c->pstate().getPath(),
1052 .line: c->pstate().getLine(),
1053 .column: c->pstate().getColumn(),
1054 .type: SASS_CALLEE_FUNCTION,
1055 .env: { .frame: env }
1056 });
1057
1058 // eval the body if user-defined or special, invoke underlying CPP function if native
1059 if (body /* && !Prelexer::re_special_fun(name.c_str()) */) {
1060 result = body->perform(op: this);
1061 }
1062 else if (func) {
1063 result = func(fn_env, *env, ctx, def->signature(), c->pstate(), traces, exp.getSelectorStack(), exp.originalStack);
1064 }
1065 if (!result) {
1066 error(msg: sass::string("Function ") + c->name() + " finished without @return", pstate: c->pstate(), traces);
1067 }
1068 callee_stack().pop_back();
1069 traces.pop_back();
1070 }
1071
1072 // else if it's a user-defined c function
1073 // convert call into C-API compatible form
1074 else if (c_function) {
1075 Sass_Function_Fn c_func = sass_function_get_function(cb: c_function);
1076 if (full_name == "*[f]") {
1077 String_Quoted_Obj str = SASS_MEMORY_NEW(String_Quoted, c->pstate(), c->name());
1078 Arguments_Obj new_args = SASS_MEMORY_NEW(Arguments, c->pstate());
1079 new_args->append(SASS_MEMORY_NEW(Argument, c->pstate(), str));
1080 new_args->concat(v: args);
1081 args = new_args;
1082 }
1083
1084 // populates env with default values for params
1085 sass::string ff(c->name());
1086 bind(type: sass::string("Function"), name: c->name(), params, args, &fn_env, this, traces);
1087 sass::string msg(", in function `" + c->name() + "`");
1088 traces.push_back(x: Backtrace(c->pstate(), msg));
1089 callee_stack().push_back(x: {
1090 .name: c->name().c_str(),
1091 .path: c->pstate().getPath(),
1092 .line: c->pstate().getLine(),
1093 .column: c->pstate().getColumn(),
1094 .type: SASS_CALLEE_C_FUNCTION,
1095 .env: { .frame: env }
1096 });
1097
1098 AST2C ast2c;
1099 union Sass_Value* c_args = sass_make_list(len: params->length(), sep: SASS_COMMA, is_bracketed: false);
1100 for(size_t i = 0; i < params->length(); i++) {
1101 Parameter_Obj param = params->at(i);
1102 sass::string key = param->name();
1103 AST_Node_Obj node = fn_env.get_local(key);
1104 ExpressionObj arg = Cast<Expression>(ptr: node);
1105 sass_list_set_value(v: c_args, i, value: arg->perform(op: &ast2c));
1106 }
1107 union Sass_Value* c_val = c_func(c_args, c_function, compiler());
1108 if (sass_value_get_tag(v: c_val) == SASS_ERROR) {
1109 sass::string message("error in C function " + c->name() + ": " + sass_error_get_message(v: c_val));
1110 sass_delete_value(val: c_val);
1111 sass_delete_value(val: c_args);
1112 error(msg: message, pstate: c->pstate(), traces);
1113 } else if (sass_value_get_tag(v: c_val) == SASS_WARNING) {
1114 sass::string message("warning in C function " + c->name() + ": " + sass_warning_get_message(v: c_val));
1115 sass_delete_value(val: c_val);
1116 sass_delete_value(val: c_args);
1117 error(msg: message, pstate: c->pstate(), traces);
1118 }
1119 result = c2ast(v: c_val, traces, pstate: c->pstate());
1120
1121 callee_stack().pop_back();
1122 traces.pop_back();
1123 sass_delete_value(val: c_args);
1124 if (c_val != c_args)
1125 sass_delete_value(val: c_val);
1126 }
1127
1128 // link back to function definition
1129 // only do this for custom functions
1130 if (result->pstate().getSrcId() == sass::string::npos)
1131 result->pstate(pstate__: c->pstate());
1132
1133 result = result->perform(op: this);
1134 result->is_interpolant(is_interpolant__: c->is_interpolant());
1135 env_stack().pop_back();
1136 return result.detach();
1137 }
1138
1139 Expression* Eval::operator()(Variable* v)
1140 {
1141 ExpressionObj value;
1142 Env* env = environment();
1143 const sass::string& name(v->name());
1144 EnvResult rv(env->find(key: name));
1145 if (rv.found) value = static_cast<Expression*>(rv.it->second.ptr());
1146 else error(msg: "Undefined variable: \"" + v->name() + "\".", pstate: v->pstate(), traces);
1147 if (Argument* arg = Cast<Argument>(ptr: value)) value = arg->value();
1148 if (Number* nr = Cast<Number>(ptr: value)) nr->zero(zero__: true); // force flag
1149 value->is_interpolant(is_interpolant__: v->is_interpolant());
1150 if (force) value->is_expanded(is_expanded__: false);
1151 value->set_delayed(false); // verified
1152 value = value->perform(op: this);
1153 if(!force) rv.it->second = value;
1154 return value.detach();
1155 }
1156
1157 Expression* Eval::operator()(Color_RGBA* c)
1158 {
1159 return c;
1160 }
1161
1162 Expression* Eval::operator()(Color_HSLA* c)
1163 {
1164 return c;
1165 }
1166
1167 Expression* Eval::operator()(Number* n)
1168 {
1169 return n;
1170 }
1171
1172 Expression* Eval::operator()(Boolean* b)
1173 {
1174 return b;
1175 }
1176
1177 void Eval::interpolation(Context& ctx, sass::string& res, ExpressionObj ex, bool into_quotes, bool was_itpl) {
1178
1179 bool needs_closing_brace = false;
1180
1181 if (Arguments* args = Cast<Arguments>(ptr: ex)) {
1182 List* ll = SASS_MEMORY_NEW(List, args->pstate(), 0, SASS_COMMA);
1183 for(auto arg : args->elements()) {
1184 ll->append(element: arg->value());
1185 }
1186 ll->is_interpolant(is_interpolant__: args->is_interpolant());
1187 needs_closing_brace = true;
1188 res += "(";
1189 ex = ll;
1190 }
1191 if (Number* nr = Cast<Number>(ptr: ex)) {
1192 Number reduced(nr);
1193 reduced.reduce();
1194 if (!reduced.is_valid_css_unit()) {
1195 traces.push_back(x: Backtrace(nr->pstate()));
1196 throw Exception::InvalidValue(traces, *nr);
1197 }
1198 }
1199 if (Argument* arg = Cast<Argument>(ptr: ex)) {
1200 ex = arg->value();
1201 }
1202 if (String_Quoted* sq = Cast<String_Quoted>(ptr: ex)) {
1203 if (was_itpl) {
1204 bool was_interpolant = ex->is_interpolant();
1205 ex = SASS_MEMORY_NEW(String_Constant, sq->pstate(), sq->value());
1206 ex->is_interpolant(is_interpolant__: was_interpolant);
1207 }
1208 }
1209
1210 if (Cast<Null>(ptr: ex)) { return; }
1211
1212 // parent selector needs another go
1213 if (Cast<Parent_Reference>(ptr: ex)) {
1214 // XXX: this is never hit via spec tests
1215 ex = ex->perform(op: this);
1216 }
1217
1218 if (List* l = Cast<List>(ptr: ex)) {
1219 List_Obj ll = SASS_MEMORY_NEW(List, l->pstate(), 0, l->separator());
1220 // this fixes an issue with bourbon sample, not really sure why
1221 // if (l->size() && Cast<Null>((*l)[0])) { res += ""; }
1222 for(ExpressionObj item : *l) {
1223 item->is_interpolant(is_interpolant__: l->is_interpolant());
1224 sass::string rl(""); interpolation(ctx, res&: rl, ex: item, into_quotes, was_itpl: l->is_interpolant());
1225 bool is_null = Cast<Null>(ptr: item) != 0; // rl != ""
1226 if (!is_null) ll->append(SASS_MEMORY_NEW(String_Quoted, item->pstate(), rl));
1227 }
1228 // Check indicates that we probably should not get a list
1229 // here. Normally single list items are already unwrapped.
1230 if (l->size() > 1) {
1231 // string_to_output would fail "#{'_\a' '_\a'}";
1232 sass::string str(ll->to_string(opt: options()));
1233 str = read_hex_escapes(str); // read escapes
1234 newline_to_space(str); // replace directly
1235 res += str; // append to result string
1236 } else {
1237 res += (ll->to_string(opt: options()));
1238 }
1239 ll->is_interpolant(is_interpolant__: l->is_interpolant());
1240 }
1241
1242 // Value
1243 // Function_Call
1244 // Selector_List
1245 // String_Quoted
1246 // String_Constant
1247 // Binary_Expression
1248 else {
1249 // ex = ex->perform(this);
1250 if (into_quotes && ex->is_interpolant()) {
1251 res += evacuate_escapes(str: ex ? ex->to_string(opt: options()) : "");
1252 } else {
1253 sass::string str(ex ? ex->to_string(opt: options()) : "");
1254 if (into_quotes) str = read_hex_escapes(str);
1255 res += str; // append to result string
1256 }
1257 }
1258
1259 if (needs_closing_brace) res += ")";
1260
1261 }
1262
1263 Expression* Eval::operator()(String_Schema* s)
1264 {
1265 size_t L = s->length();
1266 bool into_quotes = false;
1267 if (L > 1) {
1268 if (!Cast<String_Quoted>(ptr: (*s)[0]) && !Cast<String_Quoted>(ptr: (*s)[L - 1])) {
1269 if (String_Constant* l = Cast<String_Constant>(ptr: (*s)[0])) {
1270 if (String_Constant* r = Cast<String_Constant>(ptr: (*s)[L - 1])) {
1271 if (r->value().size() > 0) {
1272 if (l->value()[0] == '"' && r->value()[r->value().size() - 1] == '"') into_quotes = true;
1273 if (l->value()[0] == '\'' && r->value()[r->value().size() - 1] == '\'') into_quotes = true;
1274 }
1275 }
1276 }
1277 }
1278 }
1279 bool was_quoted = false;
1280 bool was_interpolant = false;
1281 sass::string res("");
1282 for (size_t i = 0; i < L; ++i) {
1283 bool is_quoted = Cast<String_Quoted>(ptr: (*s)[i]) != NULL;
1284 if (was_quoted && !(*s)[i]->is_interpolant() && !was_interpolant) { res += " "; }
1285 else if (i > 0 && is_quoted && !(*s)[i]->is_interpolant() && !was_interpolant) { res += " "; }
1286 ExpressionObj ex = (*s)[i]->perform(op: this);
1287 interpolation(ctx, res, ex, into_quotes, was_itpl: ex->is_interpolant());
1288 was_quoted = Cast<String_Quoted>(ptr: (*s)[i]) != NULL;
1289 was_interpolant = (*s)[i]->is_interpolant();
1290
1291 }
1292 if (!s->is_interpolant()) {
1293 if (s->length() > 1 && res == "") return SASS_MEMORY_NEW(Null, s->pstate());
1294 String_Constant_Obj str = SASS_MEMORY_NEW(String_Constant, s->pstate(), res, s->css());
1295 return str.detach();
1296 }
1297 // string schema seems to have a special unquoting behavior (also handles "nested" quotes)
1298 String_Quoted_Obj str = SASS_MEMORY_NEW(String_Quoted, s->pstate(), res, 0, false, false, false, s->css());
1299 // if (s->is_interpolant()) str->quote_mark(0);
1300 // String_Constant* str = SASS_MEMORY_NEW(String_Constant, s->pstate(), res);
1301 if (str->quote_mark()) str->quote_mark(quote_mark__: '*');
1302 else if (!is_in_comment) str->value(value__: string_to_output(str: str->value()));
1303 str->is_interpolant(is_interpolant__: s->is_interpolant());
1304 return str.detach();
1305 }
1306
1307
1308 Expression* Eval::operator()(String_Constant* s)
1309 {
1310 return s;
1311 }
1312
1313 Expression* Eval::operator()(String_Quoted* s)
1314 {
1315 String_Quoted* str = SASS_MEMORY_NEW(String_Quoted, s->pstate(), "");
1316 str->value(value__: s->value());
1317 str->quote_mark(quote_mark__: s->quote_mark());
1318 str->is_interpolant(is_interpolant__: s->is_interpolant());
1319 return str;
1320 }
1321
1322 Expression* Eval::operator()(SupportsOperation* c)
1323 {
1324 Expression* left = c->left()->perform(op: this);
1325 Expression* right = c->right()->perform(op: this);
1326 SupportsOperation* cc = SASS_MEMORY_NEW(SupportsOperation,
1327 c->pstate(),
1328 Cast<SupportsCondition>(left),
1329 Cast<SupportsCondition>(right),
1330 c->operand());
1331 return cc;
1332 }
1333
1334 Expression* Eval::operator()(SupportsNegation* c)
1335 {
1336 Expression* condition = c->condition()->perform(op: this);
1337 SupportsNegation* cc = SASS_MEMORY_NEW(SupportsNegation,
1338 c->pstate(),
1339 Cast<SupportsCondition>(condition));
1340 return cc;
1341 }
1342
1343 Expression* Eval::operator()(SupportsDeclaration* c)
1344 {
1345 Expression* feature = c->feature()->perform(op: this);
1346 Expression* value = c->value()->perform(op: this);
1347 SupportsDeclaration* cc = SASS_MEMORY_NEW(SupportsDeclaration,
1348 c->pstate(),
1349 feature,
1350 value);
1351 return cc;
1352 }
1353
1354 Expression* Eval::operator()(Supports_Interpolation* c)
1355 {
1356 Expression* value = c->value()->perform(op: this);
1357 Supports_Interpolation* cc = SASS_MEMORY_NEW(Supports_Interpolation,
1358 c->pstate(),
1359 value);
1360 return cc;
1361 }
1362
1363 Expression* Eval::operator()(At_Root_Query* e)
1364 {
1365 ExpressionObj feature = e->feature();
1366 feature = (feature ? feature->perform(op: this) : 0);
1367 ExpressionObj value = e->value();
1368 value = (value ? value->perform(op: this) : 0);
1369 Expression* ee = SASS_MEMORY_NEW(At_Root_Query,
1370 e->pstate(),
1371 Cast<String>(feature),
1372 value);
1373 return ee;
1374 }
1375
1376 Media_Query* Eval::operator()(Media_Query* q)
1377 {
1378 String_Obj t = q->media_type();
1379 t = static_cast<String*>(t.isNull() ? 0 : t->perform(op: this));
1380 Media_Query_Obj qq = SASS_MEMORY_NEW(Media_Query,
1381 q->pstate(),
1382 t,
1383 q->length(),
1384 q->is_negated(),
1385 q->is_restricted());
1386 for (size_t i = 0, L = q->length(); i < L; ++i) {
1387 qq->append(element: static_cast<Media_Query_Expression*>((*q)[i]->perform(op: this)));
1388 }
1389 return qq.detach();
1390 }
1391
1392 Expression* Eval::operator()(Media_Query_Expression* e)
1393 {
1394 ExpressionObj feature = e->feature();
1395 feature = (feature ? feature->perform(op: this) : 0);
1396 if (feature && Cast<String_Quoted>(ptr: feature)) {
1397 feature = SASS_MEMORY_NEW(String_Quoted,
1398 feature->pstate(),
1399 Cast<String_Quoted>(feature)->value());
1400 }
1401 ExpressionObj value = e->value();
1402 value = (value ? value->perform(op: this) : 0);
1403 if (value && Cast<String_Quoted>(ptr: value)) {
1404 // XXX: this is never hit via spec tests
1405 value = SASS_MEMORY_NEW(String_Quoted,
1406 value->pstate(),
1407 Cast<String_Quoted>(value)->value());
1408 }
1409 return SASS_MEMORY_NEW(Media_Query_Expression,
1410 e->pstate(),
1411 feature,
1412 value,
1413 e->is_interpolated());
1414 }
1415
1416 Expression* Eval::operator()(Null* n)
1417 {
1418 return n;
1419 }
1420
1421 Expression* Eval::operator()(Argument* a)
1422 {
1423 ExpressionObj val = a->value()->perform(op: this);
1424 bool is_rest_argument = a->is_rest_argument();
1425 bool is_keyword_argument = a->is_keyword_argument();
1426
1427 if (a->is_rest_argument()) {
1428 if (val->concrete_type() == Expression::MAP) {
1429 is_rest_argument = false;
1430 is_keyword_argument = true;
1431 }
1432 else if(val->concrete_type() != Expression::LIST) {
1433 List_Obj wrapper = SASS_MEMORY_NEW(List,
1434 val->pstate(),
1435 0,
1436 SASS_COMMA,
1437 true);
1438 wrapper->append(element: val);
1439 val = wrapper;
1440 }
1441 }
1442 return SASS_MEMORY_NEW(Argument,
1443 a->pstate(),
1444 val,
1445 a->name(),
1446 is_rest_argument,
1447 is_keyword_argument);
1448 }
1449
1450 Expression* Eval::operator()(Arguments* a)
1451 {
1452 Arguments_Obj aa = SASS_MEMORY_NEW(Arguments, a->pstate());
1453 if (a->length() == 0) return aa.detach();
1454 for (size_t i = 0, L = a->length(); i < L; ++i) {
1455 ExpressionObj rv = (*a)[i]->perform(op: this);
1456 Argument* arg = Cast<Argument>(ptr: rv);
1457 if (!(arg->is_rest_argument() || arg->is_keyword_argument())) {
1458 aa->append(element: arg);
1459 }
1460 }
1461
1462 if (a->has_rest_argument()) {
1463 ExpressionObj rest = a->get_rest_argument()->perform(op: this);
1464 ExpressionObj splat = Cast<Argument>(ptr: rest)->value()->perform(op: this);
1465
1466 Sass_Separator separator = SASS_COMMA;
1467 List* ls = Cast<List>(ptr: splat);
1468 Map* ms = Cast<Map>(ptr: splat);
1469
1470 List_Obj arglist = SASS_MEMORY_NEW(List,
1471 splat->pstate(),
1472 0,
1473 ls ? ls->separator() : separator,
1474 true);
1475
1476 if (ls && ls->is_arglist()) {
1477 arglist->concat(v: ls);
1478 } else if (ms) {
1479 aa->append(SASS_MEMORY_NEW(Argument, splat->pstate(), ms, "", false, true));
1480 } else if (ls) {
1481 arglist->concat(v: ls);
1482 } else {
1483 arglist->append(element: splat);
1484 }
1485 if (arglist->length()) {
1486 aa->append(SASS_MEMORY_NEW(Argument, splat->pstate(), arglist, "", true));
1487 }
1488 }
1489
1490 if (a->has_keyword_argument()) {
1491 ExpressionObj rv = a->get_keyword_argument()->perform(op: this);
1492 Argument* rvarg = Cast<Argument>(ptr: rv);
1493 ExpressionObj kwarg = rvarg->value()->perform(op: this);
1494
1495 aa->append(SASS_MEMORY_NEW(Argument, kwarg->pstate(), kwarg, "", false, true));
1496 }
1497 return aa.detach();
1498 }
1499
1500 Expression* Eval::operator()(Comment* c)
1501 {
1502 return 0;
1503 }
1504
1505 SelectorList* Eval::operator()(Selector_Schema* s)
1506 {
1507 LOCAL_FLAG(is_in_selector_schema, true);
1508 // the parser will look for a brace to end the selector
1509 ExpressionObj sel = s->contents()->perform(op: this);
1510 sass::string result_str(sel->to_string(opt: options()));
1511 result_str = unquote(Util::rtrim(str: result_str));
1512 ItplFile* source = SASS_MEMORY_NEW(ItplFile,
1513 result_str.c_str(), s->pstate());
1514 Parser p(source, ctx, traces);
1515
1516 // If a schema contains a reference to parent it is already
1517 // connected to it, so don't connect implicitly anymore
1518 SelectorListObj parsed = p.parseSelectorList(chroot: true);
1519 flag_is_in_selector_schema.reset();
1520 return parsed.detach();
1521 }
1522
1523 Expression* Eval::operator()(Parent_Reference* p)
1524 {
1525 if (SelectorListObj pr = exp.original()) {
1526 return operator()(pr);
1527 } else {
1528 return SASS_MEMORY_NEW(Null, p->pstate());
1529 }
1530 }
1531
1532 SimpleSelector* Eval::operator()(SimpleSelector* s)
1533 {
1534 return s;
1535 }
1536
1537 PseudoSelector* Eval::operator()(PseudoSelector* pseudo)
1538 {
1539 // ToDo: should we eval selector?
1540 return pseudo;
1541 };
1542
1543}
1544

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