ext/libsass/eval.cpp in sassc-0.0.9 vs ext/libsass/eval.cpp in sassc-0.0.10
- old
+ new
@@ -7,10 +7,11 @@
#include "inspect.hpp"
#include "to_c.hpp"
#include "context.hpp"
#include "backtrace.hpp"
#include "prelexer.hpp"
+#include "parser.hpp"
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <iomanip>
@@ -79,37 +80,37 @@
Expression* Eval::operator()(For* f)
{
string variable(f->variable());
Expression* low = f->lower_bound()->perform(this);
if (low->concrete_type() != Expression::NUMBER) {
- error("lower bound of `@for` directive must be numeric", low->path(), low->position());
+ error("lower bound of `@for` directive must be numeric", low->pstate());
}
Expression* high = f->upper_bound()->perform(this);
if (high->concrete_type() != Expression::NUMBER) {
- error("upper bound of `@for` directive must be numeric", high->path(), high->position());
+ error("upper bound of `@for` directive must be numeric", high->pstate());
}
double start = static_cast<Number*>(low)->value();
double end = static_cast<Number*>(high)->value();
Env new_env;
- new_env[variable] = new (ctx.mem) Number(low->path(), low->position(), start);
+ new_env[variable] = new (ctx.mem) Number(low->pstate(), start);
new_env.link(env);
env = &new_env;
Block* body = f->block();
Expression* val = 0;
if (start < end) {
if (f->is_inclusive()) ++end;
for (double i = start;
i < end;
- (*env)[variable] = new (ctx.mem) Number(low->path(), low->position(), ++i)) {
+ (*env)[variable] = new (ctx.mem) Number(low->pstate(), ++i)) {
val = body->perform(this);
if (val) break;
}
} else {
if (f->is_inclusive()) --end;
for (double i = start;
i > end;
- (*env)[variable] = new (ctx.mem) Number(low->path(), low->position(), --i)) {
+ (*env)[variable] = new (ctx.mem) Number(low->pstate(), --i)) {
val = body->perform(this);
if (val) break;
}
}
env = new_env.parent();
@@ -124,11 +125,11 @@
Map* map = 0;
if (expr->concrete_type() == Expression::MAP) {
map = static_cast<Map*>(expr);
}
else if (expr->concrete_type() != Expression::LIST) {
- list = new (ctx.mem) List(expr->path(), expr->position(), 1, List::COMMA);
+ list = new (ctx.mem) List(expr->pstate(), 1, List::COMMA);
*list << expr;
}
else {
list = static_cast<List*>(expr);
}
@@ -142,11 +143,11 @@
if (map) {
for (auto key : map->keys()) {
Expression* value = map->at(key);
if (variables.size() == 1) {
- List* variable = new (ctx.mem) List(map->path(), map->position(), 2, List::SPACE);
+ List* variable = new (ctx.mem) List(map->pstate(), 2, List::SPACE);
*variable << key;
*variable << value;
(*env)[variables[0]] = variable;
} else {
(*env)[variables[0]] = key;
@@ -159,22 +160,22 @@
}
else {
for (size_t i = 0, L = list->length(); i < L; ++i) {
List* variable = 0;
if ((*list)[i]->concrete_type() != Expression::LIST || variables.size() == 1) {
- variable = new (ctx.mem) List((*list)[i]->path(), (*list)[i]->position(), 1, List::COMMA);
+ variable = new (ctx.mem) List((*list)[i]->pstate(), 1, List::COMMA);
*variable << (*list)[i];
}
else {
variable = static_cast<List*>((*list)[i]);
}
for (size_t j = 0, K = variables.size(); j < K; ++j) {
if (j < variable->length()) {
(*env)[variables[j]] = (*variable)[j];
}
else {
- (*env)[variables[j]] = new (ctx.mem) Null(expr->path(), expr->position());
+ (*env)[variables[j]] = new (ctx.mem) Null(expr->pstate());
}
val = body->perform(this);
if (val) break;
}
if (val) break;
@@ -201,11 +202,11 @@
}
Expression* Eval::operator()(Warning* w)
{
Expression* message = w->message()->perform(this);
- To_String to_string;
+ To_String to_string(&ctx);
// try to use generic function
if (env->has("@warn[f]")) {
Definition* def = static_cast<Definition*>((*env)["@warn[f]"]);
@@ -222,21 +223,21 @@
return 0;
}
string result(unquote(message->perform(&to_string)));
- Backtrace top(backtrace, w->path(), w->position(), "");
+ Backtrace top(backtrace, w->pstate(), "");
cerr << "WARNING: " << result;
cerr << top.to_string(true);
cerr << endl << endl;
return 0;
}
Expression* Eval::operator()(Error* e)
{
Expression* message = e->message()->perform(this);
- To_String to_string;
+ To_String to_string(&ctx);
// try to use generic function
if (env->has("@error[f]")) {
Definition* def = static_cast<Definition*>((*env)["@error[f]"]);
@@ -253,21 +254,21 @@
return 0;
}
string result(unquote(message->perform(&to_string)));
- Backtrace top(backtrace, e->path(), e->position(), "");
+ Backtrace top(backtrace, e->pstate(), "");
cerr << "Error: " << result;
cerr << top.to_string(true);
cerr << endl << endl;
return 0;
}
Expression* Eval::operator()(Debug* d)
{
Expression* message = d->value()->perform(this);
- To_String to_string;
+ To_String to_string(&ctx);
// try to use generic function
if (env->has("@debug[f]")) {
Definition* def = static_cast<Definition*>((*env)["@debug[f]"]);
@@ -285,21 +286,20 @@
}
string cwd(ctx.get_cwd());
string result(unquote(message->perform(&to_string)));
- string rel_path(Sass::File::resolve_relative_path(d->path(), cwd, cwd));
- cerr << rel_path << ":" << d->position().line << ":" << " DEBUG: " << result;
+ string rel_path(Sass::File::resolve_relative_path(d->pstate().path, cwd, cwd));
+ cerr << rel_path << ":" << d->pstate().line << ":" << " DEBUG: " << result;
cerr << endl;
return 0;
}
Expression* Eval::operator()(List* l)
{
if (l->is_expanded()) return l;
- List* ll = new (ctx.mem) List(l->path(),
- l->position(),
+ List* ll = new (ctx.mem) List(l->pstate(),
l->length(),
l->separator(),
l->is_arglist());
for (size_t i = 0, L = l->length(); i < L; ++i) {
*ll << (*l)[i]->perform(this);
@@ -309,12 +309,11 @@
}
Expression* Eval::operator()(Map* m)
{
if (m->is_expanded()) return m;
- Map* mm = new (ctx.mem) Map(m->path(),
- m->position(),
+ Map* mm = new (ctx.mem) Map(m->pstate(),
m->length());
for (auto key : m->keys()) {
*mm << std::make_pair(key->perform(this), m->at(key)->perform(this));
}
mm->is_expanded(true);
@@ -335,13 +334,14 @@
{
Binary_Expression::Type op_type = b->type();
// don't eval delayed expressions (the '/' when used as a separator)
if (op_type == Binary_Expression::DIV && b->is_delayed()) return b;
// if one of the operands is a '/' then make sure it's evaluated
- if (typeid(*b->left()) == typeid(Binary_Expression)) b->left()->is_delayed(false);
- // the logical connectives need to short-circuit
Expression* lhs = b->left()->perform(this);
+ lhs->is_delayed(false);
+ while (typeid(*lhs) == typeid(Binary_Expression)) lhs = lhs->perform(this);
+
switch (op_type) {
case Binary_Expression::AND:
return *lhs ? b->right()->perform(this) : lhs;
break;
@@ -352,19 +352,21 @@
default:
break;
}
// not a logical connective, so go ahead and eval the rhs
Expression* rhs = b->right()->perform(this);
+ rhs->is_delayed(false);
+ while (typeid(*rhs) == typeid(Binary_Expression)) rhs = rhs->perform(this);
// see if it's a relational expression
switch(op_type) {
- case Binary_Expression::EQ: return new (ctx.mem) Boolean(b->path(), b->position(), eq(lhs, rhs, ctx));
- case Binary_Expression::NEQ: return new (ctx.mem) Boolean(b->path(), b->position(), !eq(lhs, rhs, ctx));
- case Binary_Expression::GT: return new (ctx.mem) Boolean(b->path(), b->position(), !lt(lhs, rhs, ctx) && !eq(lhs, rhs, ctx));
- case Binary_Expression::GTE: return new (ctx.mem) Boolean(b->path(), b->position(), !lt(lhs, rhs, ctx));
- case Binary_Expression::LT: return new (ctx.mem) Boolean(b->path(), b->position(), lt(lhs, rhs, ctx));
- case Binary_Expression::LTE: return new (ctx.mem) Boolean(b->path(), b->position(), lt(lhs, rhs, ctx) || eq(lhs, rhs, ctx));
+ case Binary_Expression::EQ: return new (ctx.mem) Boolean(b->pstate(), eq(lhs, rhs, ctx));
+ case Binary_Expression::NEQ: return new (ctx.mem) Boolean(b->pstate(), !eq(lhs, rhs, ctx));
+ case Binary_Expression::GT: return new (ctx.mem) Boolean(b->pstate(), !lt(lhs, rhs, ctx) && !eq(lhs, rhs, ctx));
+ case Binary_Expression::GTE: return new (ctx.mem) Boolean(b->pstate(), !lt(lhs, rhs, ctx));
+ case Binary_Expression::LT: return new (ctx.mem) Boolean(b->pstate(), lt(lhs, rhs, ctx));
+ case Binary_Expression::LTE: return new (ctx.mem) Boolean(b->pstate(), lt(lhs, rhs, ctx) || eq(lhs, rhs, ctx));
default: break;
}
Expression::Concrete_Type l_type = lhs->concrete_type();
@@ -380,18 +382,29 @@
return op_color_number(ctx, op_type, lhs, rhs);
}
if (l_type == Expression::COLOR && r_type == Expression::COLOR) {
return op_colors(ctx, op_type, lhs, rhs);
}
- return op_strings(ctx, op_type, lhs, rhs);
+
+ Expression* ex = op_strings(ctx, op_type, lhs, rhs);
+ if (String_Constant* str = (String_Constant*) ex)
+ {
+ if (str->concrete_type() != Expression::STRING) return ex;
+ String_Constant* lstr = dynamic_cast<String_Constant*>(lhs);
+ String_Constant* rstr = dynamic_cast<String_Constant*>(rhs);
+ if (String_Constant* org = lstr ? lstr : rstr)
+ { str->quote_mark(org->quote_mark()); }
+ }
+ return ex;
+
}
Expression* Eval::operator()(Unary_Expression* u)
{
Expression* operand = u->operand()->perform(this);
if (u->type() == Unary_Expression::NOT) {
- Boolean* result = new (ctx.mem) Boolean(u->path(), u->position(), (bool)*operand);
+ Boolean* result = new (ctx.mem) Boolean(u->pstate(), (bool)*operand);
result->value(!result->value());
return result;
}
else if (operand->concrete_type() == Expression::NUMBER) {
Number* result = new (ctx.mem) Number(*static_cast<Number*>(operand));
@@ -399,19 +412,18 @@
? -result->value()
: result->value());
return result;
}
else {
- To_String to_string;
+ To_String to_string(&ctx);
// Special cases: +/- variables which evaluate to null ouput just +/-,
// but +/- null itself outputs the string
if (operand->concrete_type() == Expression::NULL_VAL && typeid(*(u->operand())) == typeid(Variable)) {
- u->operand(new (ctx.mem) String_Constant(u->path(), u->position(), ""));
+ u->operand(new (ctx.mem) String_Constant(u->pstate(), ""));
}
else u->operand(operand);
- String_Constant* result = new (ctx.mem) String_Constant(u->path(),
- u->position(),
+ String_Constant* result = new (ctx.mem) String_Constant(u->pstate(),
u->perform(&to_string));
return result;
}
// unreachable
return u;
@@ -432,17 +444,15 @@
}
}
// if it doesn't exist, just pass it through as a literal
if (!env->has(full_name)) {
- Function_Call* lit = new (ctx.mem) Function_Call(c->path(),
- c->position(),
+ Function_Call* lit = new (ctx.mem) Function_Call(c->pstate(),
c->name(),
args);
- To_String to_string;
- return new (ctx.mem) String_Constant(c->path(),
- c->position(),
+ To_String to_string(&ctx);
+ return new (ctx.mem) String_Constant(c->pstate(),
lit->perform(&to_string));
}
Expression* result = c;
Definition* def = static_cast<Definition*>((*env)[full_name]);
@@ -471,16 +481,16 @@
bind("function " + c->name(), params, args, ctx, &new_env, this);
Env* old_env = env;
env = &new_env;
- Backtrace here(backtrace, c->path(), c->position(), ", in function `" + c->name() + "`");
+ Backtrace here(backtrace, c->pstate(), ", in function `" + c->name() + "`");
backtrace = &here;
result = body->perform(this);
if (!result) {
- error(string("function ") + c->name() + " did not return a value", c->path(), c->position());
+ error(string("function ") + c->name() + " did not return a value", c->pstate());
}
backtrace = here.parent;
env = old_env;
}
// if it's native, invoke the underlying CPP function
@@ -488,35 +498,35 @@
bind("function " + c->name(), params, args, ctx, &new_env, this);
Env* old_env = env;
env = &new_env;
- Backtrace here(backtrace, c->path(), c->position(), ", in function `" + c->name() + "`");
+ Backtrace here(backtrace, c->pstate(), ", in function `" + c->name() + "`");
backtrace = &here;
- result = func(*env, *old_env, ctx, def->signature(), c->path(), c->position(), backtrace);
+ result = func(*env, *old_env, ctx, def->signature(), c->pstate(), backtrace);
backtrace = here.parent;
env = old_env;
}
// else if it's a user-defined c function
else if (c_func) {
if (full_name == "*[f]") {
- String_Constant *str = new (ctx.mem) String_Constant(c->path(), c->position(), c->name());
- Arguments* new_args = new (ctx.mem) Arguments(c->path(), c->position());
- *new_args << new (ctx.mem) Argument(c->path(), c->position(), str);
+ String_Constant *str = new (ctx.mem) String_Constant(c->pstate(), c->name());
+ Arguments* new_args = new (ctx.mem) Arguments(c->pstate());
+ *new_args << new (ctx.mem) Argument(c->pstate(), str);
*new_args += args;
args = new_args;
}
// populates env with default values for params
bind("function " + c->name(), params, args, ctx, &new_env, this);
Env* old_env = env;
env = &new_env;
- Backtrace here(backtrace, c->path(), c->position(), ", in function `" + c->name() + "`");
+ Backtrace here(backtrace, c->pstate(), ", in function `" + c->name() + "`");
backtrace = &here;
To_C to_c;
union Sass_Value* c_args = sass_make_list(env->current_frame().size(), SASS_COMMA);
for(size_t i = 0; i < params[0].length(); i++) {
@@ -525,15 +535,15 @@
Expression* arg = static_cast<Expression*>(node);
sass_list_set_value(c_args, i, arg->perform(&to_c));
}
Sass_Value* c_val = c_func(c_args, def->cookie());
if (sass_value_get_tag(c_val) == SASS_ERROR) {
- error("error in C function " + c->name() + ": " + sass_error_get_message(c_val), c->path(), c->position(), backtrace);
+ error("error in C function " + c->name() + ": " + sass_error_get_message(c_val), c->pstate(), backtrace);
} else if (sass_value_get_tag(c_val) == SASS_WARNING) {
- error("warning in C function " + c->name() + ": " + sass_warning_get_message(c_val), c->path(), c->position(), backtrace);
+ error("warning in C function " + c->name() + ": " + sass_warning_get_message(c_val), c->pstate(), backtrace);
}
- result = cval_to_astnode(c_val, ctx, backtrace, c->path(), c->position());
+ result = cval_to_astnode(c_val, ctx, backtrace, c->pstate());
backtrace = here.parent;
sass_delete_value(c_args);
if (c_val != c_args)
sass_delete_value(c_val);
@@ -543,68 +553,90 @@
else if (def->is_overload_stub()) {
size_t arity = args->length();
stringstream ss;
ss << full_name << arity;
string resolved_name(ss.str());
- if (!env->has(resolved_name)) error("overloaded function `" + string(c->name()) + "` given wrong number of arguments", c->path(), c->position());
+ if (!env->has(resolved_name)) error("overloaded function `" + string(c->name()) + "` given wrong number of arguments", c->pstate());
Definition* resolved_def = static_cast<Definition*>((*env)[resolved_name]);
params = resolved_def->parameters();
Env newer_env;
newer_env.link(resolved_def->environment());
bind("function " + c->name(), params, args, ctx, &newer_env, this);
Env* old_env = env;
env = &newer_env;
- Backtrace here(backtrace, c->path(), c->position(), ", in function `" + c->name() + "`");
+ Backtrace here(backtrace, c->pstate(), ", in function `" + c->name() + "`");
backtrace = &here;
- result = resolved_def->native_function()(*env, *old_env, ctx, resolved_def->signature(), c->path(), c->position(), backtrace);
+ result = resolved_def->native_function()(*env, *old_env, ctx, resolved_def->signature(), c->pstate(), backtrace);
backtrace = here.parent;
env = old_env;
}
// backtrace = here.parent;
// env = old_env;
- result->position(c->position());
+
+
+ // link back to function definition
+ // only do this for custom functions
+ if (result->pstate().file == string::npos)
+ result->pstate(c->pstate());
+
+ do {
+ result->is_delayed(result->concrete_type() == Expression::STRING);
+ result = result->perform(this);
+ } while (result->concrete_type() == Expression::NONE);
return result;
}
Expression* Eval::operator()(Function_Call_Schema* s)
{
Expression* evaluated_name = s->name()->perform(this);
Expression* evaluated_args = s->arguments()->perform(this);
- String_Schema* ss = new (ctx.mem) String_Schema(s->path(), s->position(), 2);
+ String_Schema* ss = new (ctx.mem) String_Schema(s->pstate(), 2);
(*ss) << evaluated_name << evaluated_args;
return ss->perform(this);
}
Expression* Eval::operator()(Variable* v)
{
- To_String to_string;
+ To_String to_string(&ctx);
string name(v->name());
Expression* value = 0;
if (env->has(name)) value = static_cast<Expression*>((*env)[name]);
- else error("unbound variable " + v->name(), v->path(), v->position());
+ else error("Undefined variable: \"" + v->name() + "\".", v->pstate());
// cerr << "name: " << v->name() << "; type: " << typeid(*value).name() << "; value: " << value->perform(&to_string) << endl;
if (typeid(*value) == typeid(Argument)) value = static_cast<Argument*>(value)->value();
// behave according to as ruby sass (add leading zero)
if (value->concrete_type() == Expression::NUMBER) {
- Number* n = static_cast<Number*>(value);
- value = new (ctx.mem) Number(n->path(),
- n->position(),
- n->value(),
- n->unit(),
- true);
+ value = new (ctx.mem) Number(*static_cast<Number*>(value));
+ static_cast<Number*>(value)->zero(true);
}
else if (value->concrete_type() == Expression::STRING) {
- String_Constant* s = static_cast<String_Constant*>(value);
- value = new (ctx.mem) String_Constant(s->path(),
- s->position(),
- s->value());
+ if (auto str = dynamic_cast<String_Quoted*>(value)) {
+ value = new (ctx.mem) String_Quoted(*str);
+ } else if (auto str = dynamic_cast<String_Constant*>(value)) {
+ value = new (ctx.mem) String_Constant(*str);
+ }
}
+ else if (value->concrete_type() == Expression::LIST) {
+ value = new (ctx.mem) List(*static_cast<List*>(value));
+ }
+ else if (value->concrete_type() == Expression::MAP) {
+ value = new (ctx.mem) Map(*static_cast<Map*>(value));
+ }
+ else if (value->concrete_type() == Expression::BOOLEAN) {
+ value = new (ctx.mem) Boolean(*static_cast<Boolean*>(value));
+ }
+ else if (value->concrete_type() == Expression::COLOR) {
+ value = new (ctx.mem) Color(*static_cast<Color*>(value));
+ }
+ else if (value->concrete_type() == Expression::NULL_VAL) {
+ value = new (ctx.mem) Null(value->pstate());
+ }
// cerr << "\ttype is now: " << typeid(*value).name() << endl << endl;
return value;
}
@@ -623,47 +655,42 @@
const string& num = text.substr(num_pos, unit_pos - num_pos);
switch (t->type())
{
case Textual::NUMBER:
- result = new (ctx.mem) Number(t->path(),
- t->position(),
- atof(num.c_str()),
+ result = new (ctx.mem) Number(t->pstate(),
+ sass_atof(num.c_str()),
"",
zero);
break;
case Textual::PERCENTAGE:
- result = new (ctx.mem) Number(t->path(),
- t->position(),
- atof(num.c_str()),
+ result = new (ctx.mem) Number(t->pstate(),
+ sass_atof(num.c_str()),
"%",
zero);
break;
case Textual::DIMENSION:
- result = new (ctx.mem) Number(t->path(),
- t->position(),
- atof(num.c_str()),
- Token(number(text.c_str())),
+ result = new (ctx.mem) Number(t->pstate(),
+ sass_atof(num.c_str()),
+ Token(number(text.c_str()), t->pstate()),
zero);
break;
case Textual::HEX: {
string hext(t->value().substr(1)); // chop off the '#'
if (hext.length() == 6) {
string r(hext.substr(0,2));
string g(hext.substr(2,2));
string b(hext.substr(4,2));
- result = new (ctx.mem) Color(t->path(),
- t->position(),
+ result = new (ctx.mem) Color(t->pstate(),
static_cast<double>(strtol(r.c_str(), NULL, 16)),
static_cast<double>(strtol(g.c_str(), NULL, 16)),
static_cast<double>(strtol(b.c_str(), NULL, 16)),
1, true,
t->value());
}
else {
- result = new (ctx.mem) Color(t->path(),
- t->position(),
+ result = new (ctx.mem) Color(t->pstate(),
static_cast<double>(strtol(string(2,hext[0]).c_str(), NULL, 16)),
static_cast<double>(strtol(string(2,hext[1]).c_str(), NULL, 16)),
static_cast<double>(strtol(string(2,hext[2]).c_str(), NULL, 16)),
1, false,
t->value());
@@ -674,12 +701,11 @@
}
Expression* Eval::operator()(Number* n)
{
// behave according to as ruby sass (add leading zero)
- return new (ctx.mem) Number(n->path(),
- n->position(),
+ return new (ctx.mem) Number(n->pstate(),
n->value(),
n->unit(),
true);
}
@@ -698,46 +724,106 @@
else {
return 0;
}
}
+ string Eval::interpolation(Expression* s) {
+
+ if (String_Quoted* str_quoted = dynamic_cast<String_Quoted*>(s)) {
+
+ if (str_quoted->quote_mark()) {
+ return string_escape(str_quoted->value());
+ } else {
+ return evacuate_escapes(str_quoted->value());
+ }
+
+ } else if (String_Constant* str_constant = dynamic_cast<String_Constant*>(s)) {
+
+ return evacuate_escapes(str_constant->value());
+
+ } else if (String_Schema* str_schema = dynamic_cast<String_Schema*>(s)) {
+
+ string res = "";
+ for(auto i : str_schema->elements())
+ res += (interpolation(i));
+ //ToDo: do this in one step
+ auto esc = evacuate_escapes(res);
+ auto unq = unquote(esc);
+ if (unq == esc) {
+ return string_to_output(res);
+ } else {
+ return evacuate_quotes(unq);
+ }
+
+ } else if (List* list = dynamic_cast<List*>(s)) {
+
+ string acc = ""; // ToDo: different output styles
+ string sep = list->separator() == List::Separator::COMMA ? "," : " ";
+ if (ctx.output_style != COMPRESSED && sep == ",") sep += " ";
+ bool initial = false;
+ for(auto item : list->elements()) {
+ if (initial) acc += sep;
+ acc += interpolation(item);
+ initial = true;
+ }
+ return evacuate_quotes(acc);
+
+ } else if (Variable* var = dynamic_cast<Variable*>(s)) {
+
+ string name(var->name());
+ if (!env->has(name)) error("Undefined variable: \"" + var->name() + "\".", var->pstate());
+ Expression* value = static_cast<Expression*>((*env)[name]);
+ return evacuate_quotes(interpolation(value));
+
+ } else if (Binary_Expression* var = dynamic_cast<Binary_Expression*>(s)) {
+
+ Expression* ex = operator()(var);
+ return evacuate_quotes(interpolation(ex));
+
+ } else if (Function_Call* var = dynamic_cast<Function_Call*>(s)) {
+
+ Expression* ex = operator()(var);
+ return evacuate_quotes(interpolation(ex));
+
+ } else {
+
+ To_String to_string(&ctx);
+ // to_string.in_decl_list = true;
+ return evacuate_quotes(s->perform(&to_string));
+
+ }
+ }
+
Expression* Eval::operator()(String_Schema* s)
{
string acc;
- ctx._skip_source_map_update = true;
- To_String to_string(&ctx);
- ctx._skip_source_map_update = false;
for (size_t i = 0, L = s->length(); i < L; ++i) {
- string chunk((*s)[i]->perform(this)->perform(&to_string));
- if (((s->quote_mark() && is_quoted(chunk)) || !s->quote_mark()) && (*s)[i]->is_interpolant()) { // some redundancy in that test
- acc += unquote(chunk);
- }
- else {
- acc += chunk;
- }
+ acc += interpolation((*s)[i]);
}
- return new (ctx.mem) String_Constant(s->path(),
- s->position(),
- acc);
+ String_Quoted* str = new (ctx.mem) String_Quoted(s->pstate(), acc);
+ if (!str->quote_mark()) {
+ str->value(string_unescape(str->value()));
+ } else if (str->quote_mark()) {
+ str->quote_mark('*');
+ }
+ return str;
}
Expression* Eval::operator()(String_Constant* s)
{
- if (!s->is_delayed() && ctx.names_to_colors.count(s->value())) {
+ if (!s->quote_mark() && !s->is_delayed() && ctx.names_to_colors.count(s->value())) {
Color* c = new (ctx.mem) Color(*ctx.names_to_colors[s->value()]);
- c->path(s->path());
- c->position(s->position());
+ c->pstate(s->pstate());
c->disp(s->value());
return c;
}
return s;
}
Expression* Eval::operator()(Feature_Query* q)
{
- Feature_Query* qq = new (ctx.mem) Feature_Query(q->path(),
- q->position(),
+ Feature_Query* qq = new (ctx.mem) Feature_Query(q->pstate(),
q->length());
for (size_t i = 0, L = q->length(); i < L; ++i) {
*qq << static_cast<Feature_Query_Condition*>((*q)[i]->perform(this));
}
return qq;
@@ -746,12 +832,11 @@
Expression* Eval::operator()(Feature_Query_Condition* c)
{
String* feature = c->feature();
Expression* value = c->value();
value = (value ? value->perform(this) : 0);
- Feature_Query_Condition* cc = new (ctx.mem) Feature_Query_Condition(c->path(),
- c->position(),
+ Feature_Query_Condition* cc = new (ctx.mem) Feature_Query_Condition(c->pstate(),
c->length(),
feature,
value,
c->operand(),
c->is_root());
@@ -759,16 +844,29 @@
*cc << static_cast<Feature_Query_Condition*>((*c)[i]->perform(this));
}
return cc;
}
+ Expression* Eval::operator()(At_Root_Expression* e)
+ {
+ Expression* feature = e->feature();
+ feature = (feature ? feature->perform(this) : 0);
+ Expression* value = e->value();
+ value = (value ? value->perform(this) : 0);
+ Expression* ee = new (ctx.mem) At_Root_Expression(e->pstate(),
+ static_cast<String*>(feature),
+ value,
+ e->is_interpolated());
+ return ee;
+ }
+
Expression* Eval::operator()(Media_Query* q)
{
+ To_String to_string(&ctx);
String* t = q->media_type();
t = static_cast<String*>(t ? t->perform(this) : 0);
- Media_Query* qq = new (ctx.mem) Media_Query(q->path(),
- q->position(),
+ Media_Query* qq = new (ctx.mem) Media_Query(q->pstate(),
t,
q->length(),
q->is_negated(),
q->is_restricted());
for (size_t i = 0, L = q->length(); i < L; ++i) {
@@ -781,12 +879,11 @@
{
Expression* feature = e->feature();
feature = (feature ? feature->perform(this) : 0);
Expression* value = e->value();
value = (value ? value->perform(this) : 0);
- return new (ctx.mem) Media_Query_Expression(e->path(),
- e->position(),
+ return new (ctx.mem) Media_Query_Expression(e->pstate(),
feature,
value,
e->is_interpolated());
}
@@ -810,36 +907,39 @@
is_rest_argument = false;
is_keyword_argument = true;
}
else
if(val->concrete_type() != Expression::LIST) {
- List* wrapper = new (ctx.mem) List(val->path(),
- val->position(),
+ List* wrapper = new (ctx.mem) List(val->pstate(),
0,
List::COMMA,
true);
*wrapper << val;
val = wrapper;
}
}
- return new (ctx.mem) Argument(a->path(),
- a->position(),
+ return new (ctx.mem) Argument(a->pstate(),
val,
a->name(),
is_rest_argument,
is_keyword_argument);
}
Expression* Eval::operator()(Arguments* a)
{
- Arguments* aa = new (ctx.mem) Arguments(a->path(), a->position());
+ Arguments* aa = new (ctx.mem) Arguments(a->pstate());
for (size_t i = 0, L = a->length(); i < L; ++i) {
*aa << static_cast<Argument*>((*a)[i]->perform(this));
}
return aa;
}
+ Expression* Eval::operator()(Comment* c)
+ {
+ return 0;
+ }
+
inline Expression* Eval::fallback_impl(AST_Node* n)
{
return static_cast<Expression*>(n);
}
@@ -911,19 +1011,19 @@
bool lt(Expression* lhs, Expression* rhs, Context& ctx)
{
if (lhs->concrete_type() != Expression::NUMBER ||
rhs->concrete_type() != Expression::NUMBER)
- error("may only compare numbers", lhs->path(), lhs->position());
+ error("may only compare numbers", lhs->pstate());
Number* l = static_cast<Number*>(lhs);
Number* r = static_cast<Number*>(rhs);
Number tmp_r(*r);
tmp_r.normalize(l->find_convertible_unit());
string l_unit(l->unit());
string r_unit(tmp_r.unit());
if (!l_unit.empty() && !r_unit.empty() && l->unit() != tmp_r.unit()) {
- error("cannot compare numbers with incompatible units", l->path(), l->position());
+ error("cannot compare numbers with incompatible units", l->pstate());
}
return l->value() < tmp_r.value();
}
Expression* op_numbers(Context& ctx, Binary_Expression* b, Expression* lhs, Expression* rhs)
@@ -932,26 +1032,26 @@
Number* r = static_cast<Number*>(rhs);
double lv = l->value();
double rv = r->value();
Binary_Expression::Type op = b->type();
if (op == Binary_Expression::DIV && !rv) {
- return new (ctx.mem) String_Constant(l->path(), b->position(), "Infinity");
+ return new (ctx.mem) String_Constant(l->pstate(), "Infinity");
}
if (op == Binary_Expression::MOD && !rv) {
- error("division by zero", r->path(), r->position());
+ error("division by zero", r->pstate());
}
Number tmp(*r);
tmp.normalize(l->find_convertible_unit());
string l_unit(l->unit());
string r_unit(tmp.unit());
if (l_unit != r_unit && !l_unit.empty() && !r_unit.empty() &&
(op == Binary_Expression::ADD || op == Binary_Expression::SUB)) {
- error("cannot add or subtract numbers with incompatible units", l->path(), l->position());
+ error("Incompatible units: '"+r_unit+"' and '"+l_unit+"'.", l->pstate());
}
Number* v = new (ctx.mem) Number(*l);
- v->position(b->position());
+ v->pstate(b->pstate());
if (l_unit.empty() && (op == Binary_Expression::ADD || op == Binary_Expression::SUB || op == Binary_Expression::MOD)) {
v->numerator_units() = r->numerator_units();
v->denominator_units() = r->denominator_units();
}
@@ -986,31 +1086,30 @@
r->disp("");
double lv = l->value();
switch (op) {
case Binary_Expression::ADD:
case Binary_Expression::MUL: {
- return new (ctx.mem) Color(l->path(),
- l->position(),
+ return new (ctx.mem) Color(l->pstate(),
ops[op](lv, r->r()),
ops[op](lv, r->g()),
ops[op](lv, r->b()),
r->a());
} break;
case Binary_Expression::SUB:
case Binary_Expression::DIV: {
string sep(op == Binary_Expression::SUB ? "-" : "/");
- To_String to_string;
- string color(r->sixtuplet() ? r->perform(&to_string) :
+ To_String to_string(&ctx);
+ string color(r->sixtuplet() && (ctx.output_style != COMPRESSED) ?
+ r->perform(&to_string) :
Util::normalize_sixtuplet(r->perform(&to_string)));
- return new (ctx.mem) String_Constant(l->path(),
- l->position(),
+ return new (ctx.mem) String_Constant(l->pstate(),
l->perform(&to_string)
+ sep
+ color);
} break;
case Binary_Expression::MOD: {
- error("cannot divide a number by a color", r->path(), r->position());
+ error("cannot divide a number by a color", r->pstate());
} break;
default: break; // caller should ensure that we don't get here
}
// unreachable
return l;
@@ -1019,13 +1118,12 @@
Expression* op_color_number(Context& ctx, Binary_Expression::Type op, Expression* lhs, Expression* rhs)
{
Color* l = static_cast<Color*>(lhs);
Number* r = static_cast<Number*>(rhs);
double rv = r->value();
- if (op == Binary_Expression::DIV && !rv) error("division by zero", r->path(), r->position());
- return new (ctx.mem) Color(l->path(),
- l->position(),
+ if (op == Binary_Expression::DIV && !rv) error("division by zero", r->pstate());
+ return new (ctx.mem) Color(l->pstate(),
ops[op](l->r(), rv),
ops[op](l->g(), rv),
ops[op](l->b(), rv),
l->a());
}
@@ -1033,40 +1131,37 @@
Expression* op_colors(Context& ctx, Binary_Expression::Type op, Expression* lhs, Expression* rhs)
{
Color* l = static_cast<Color*>(lhs);
Color* r = static_cast<Color*>(rhs);
if (l->a() != r->a()) {
- error("alpha channels must be equal when combining colors", r->path(), r->position());
+ error("alpha channels must be equal when combining colors", r->pstate());
}
if ((op == Binary_Expression::DIV || op == Binary_Expression::MOD) &&
(!r->r() || !r->g() ||!r->b())) {
- error("division by zero", r->path(), r->position());
+ error("division by zero", r->pstate());
}
- return new (ctx.mem) Color(l->path(),
- l->position(),
+ return new (ctx.mem) Color(l->pstate(),
ops[op](l->r(), r->r()),
ops[op](l->g(), r->g()),
ops[op](l->b(), r->b()),
l->a());
}
Expression* op_strings(Context& ctx, Binary_Expression::Type op, Expression* lhs, Expression*rhs)
{
- To_String to_string;
+ To_String to_string(&ctx);
Expression::Concrete_Type ltype = lhs->concrete_type();
Expression::Concrete_Type rtype = rhs->concrete_type();
string lstr(lhs->perform(&to_string));
string rstr(rhs->perform(&to_string));
- bool l_str_quoted = ((Sass::String*)lhs) && ((Sass::String*)lhs)->needs_unquoting();
- bool r_str_quoted = ((Sass::String*)rhs) && ((Sass::String*)rhs)->needs_unquoting();
+ bool l_str_quoted = ((Sass::String*)lhs) && ((Sass::String*)lhs)->sass_fix_1291();
+ bool r_str_quoted = ((Sass::String*)rhs) && ((Sass::String*)rhs)->sass_fix_1291();
bool l_str_color = ltype == Expression::STRING && ctx.names_to_colors.count(lstr) && !l_str_quoted;
bool r_str_color = rtype == Expression::STRING && ctx.names_to_colors.count(rstr) && !r_str_quoted;
- bool unquoted = false;
- if (ltype == Expression::STRING && lstr[0] != '"' && lstr[0] != '\'') unquoted = true;
if (l_str_color && r_str_color) {
return op_colors(ctx, op, ctx.names_to_colors[lstr], ctx.names_to_colors[rstr]);
}
else if (l_str_color && rtype == Expression::COLOR) {
return op_colors(ctx, op, ctx.names_to_colors[lstr], rhs);
@@ -1078,70 +1173,67 @@
return op_number_color(ctx, op, lhs, ctx.names_to_colors[rstr]);
}
else if (ltype == Expression::NUMBER && r_str_color) {
return op_number_color(ctx, op, lhs, ctx.names_to_colors[rstr]);
}
- if (op == Binary_Expression::MUL) error("invalid operands for multiplication", lhs->path(), lhs->position());
- if (op == Binary_Expression::MOD) error("invalid operands for modulo", lhs->path(), lhs->position());
+ if (op == Binary_Expression::MUL) error("invalid operands for multiplication", lhs->pstate());
+ if (op == Binary_Expression::MOD) error("invalid operands for modulo", lhs->pstate());
string sep;
switch (op) {
case Binary_Expression::SUB: sep = "-"; break;
case Binary_Expression::DIV: sep = "/"; break;
default: break;
}
- if (ltype == Expression::NULL_VAL) error("invalid null operation: \"null plus "+quote(unquote(rstr), '"')+"\".", lhs->path(), lhs->position());
- if (rtype == Expression::NULL_VAL) error("invalid null operation: \""+quote(unquote(lstr), '"')+" plus null\".", lhs->path(), lhs->position());
- char q = '\0';
- if (lstr[0] == '"' || lstr[0] == '\'') q = lstr[0];
- else if (rstr[0] == '"' || rstr[0] == '\'') q = rstr[0];
- string result(unquote(lstr) + sep + unquote(rstr));
- return new (ctx.mem) String_Constant(lhs->path(),
- lhs->position(),
- unquoted ? result : quote(result, q));
+ if (ltype == Expression::NULL_VAL) error("invalid null operation: \"null plus "+quote(unquote(rstr), '"')+"\".", lhs->pstate());
+ if (rtype == Expression::NULL_VAL) error("invalid null operation: \""+quote(unquote(lstr), '"')+" plus null\".", lhs->pstate());
+ string result((lstr) + sep + (rstr));
+ String_Quoted* str = new (ctx.mem) String_Quoted(lhs->pstate(), result);
+ str->quote_mark(0);
+ return str;
}
- Expression* cval_to_astnode(Sass_Value* v, Context& ctx, Backtrace* backtrace, string path, Position position)
+ Expression* cval_to_astnode(Sass_Value* v, Context& ctx, Backtrace* backtrace, ParserState pstate)
{
using std::strlen;
using std::strcpy;
Expression* e = 0;
switch (sass_value_get_tag(v)) {
case SASS_BOOLEAN: {
- e = new (ctx.mem) Boolean(path, position, !!sass_boolean_get_value(v));
+ e = new (ctx.mem) Boolean(pstate, !!sass_boolean_get_value(v));
} break;
case SASS_NUMBER: {
- e = new (ctx.mem) Number(path, position, sass_number_get_value(v), sass_number_get_unit(v));
+ e = new (ctx.mem) Number(pstate, sass_number_get_value(v), sass_number_get_unit(v));
} break;
case SASS_COLOR: {
- e = new (ctx.mem) Color(path, position, sass_color_get_r(v), sass_color_get_g(v), sass_color_get_b(v), sass_color_get_a(v));
+ e = new (ctx.mem) Color(pstate, sass_color_get_r(v), sass_color_get_g(v), sass_color_get_b(v), sass_color_get_a(v));
} break;
case SASS_STRING: {
- e = new (ctx.mem) String_Constant(path, position, sass_string_get_value(v));
+ e = new (ctx.mem) String_Constant(pstate, sass_string_get_value(v));
} break;
case SASS_LIST: {
- List* l = new (ctx.mem) List(path, position, sass_list_get_length(v), sass_list_get_separator(v) == SASS_COMMA ? List::COMMA : List::SPACE);
+ List* l = new (ctx.mem) List(pstate, sass_list_get_length(v), sass_list_get_separator(v) == SASS_COMMA ? List::COMMA : List::SPACE);
for (size_t i = 0, L = sass_list_get_length(v); i < L; ++i) {
- *l << cval_to_astnode(sass_list_get_value(v, i), ctx, backtrace, path, position);
+ *l << cval_to_astnode(sass_list_get_value(v, i), ctx, backtrace, pstate);
}
e = l;
} break;
case SASS_MAP: {
- Map* m = new (ctx.mem) Map(path, position);
+ Map* m = new (ctx.mem) Map(pstate);
for (size_t i = 0, L = sass_map_get_length(v); i < L; ++i) {
*m << std::make_pair(
- cval_to_astnode(sass_map_get_key(v, i), ctx, backtrace, path, position),
- cval_to_astnode(sass_map_get_value(v, i), ctx, backtrace, path, position));
+ cval_to_astnode(sass_map_get_key(v, i), ctx, backtrace, pstate),
+ cval_to_astnode(sass_map_get_value(v, i), ctx, backtrace, pstate));
}
e = m;
} break;
case SASS_NULL: {
- e = new (ctx.mem) Null(path, position);
+ e = new (ctx.mem) Null(pstate);
} break;
case SASS_ERROR: {
- error("Error in C function: " + string(sass_error_get_message(v)), path, position, backtrace);
+ error("Error in C function: " + string(sass_error_get_message(v)), pstate, backtrace);
} break;
case SASS_WARNING: {
- error("Warning in C function: " + string(sass_warning_get_message(v)), path, position, backtrace);
+ error("Warning in C function: " + string(sass_warning_get_message(v)), pstate, backtrace);
} break;
}
return e;
}