diff --git a/Makefile b/Makefile index 5187e5744d..10ef51194e 100644 --- a/Makefile +++ b/Makefile @@ -120,6 +120,7 @@ SOURCES = \ contextualize.cpp \ contextualize_eval.cpp \ cssize.cpp \ + debug.cpp \ listize.cpp \ error_handling.cpp \ eval.cpp \ diff --git a/Makefile.am b/Makefile.am index e59d2f8603..3bacdc633e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -48,6 +48,7 @@ libsass_la_SOURCES = \ context.cpp context.hpp \ contextualize.cpp contextualize.hpp \ contextualize_eval.cpp contextualize_eval.hpp \ + debug.cpp \ error_handling.cpp error_handling.hpp \ eval.cpp eval.hpp \ expand.cpp expand.hpp \ diff --git a/ast.hpp b/ast.hpp index bbf70f8f98..270805d103 100644 --- a/ast.hpp +++ b/ast.hpp @@ -30,6 +30,7 @@ #endif +#include "debug.hpp" #include "util.hpp" #include "units.hpp" #include "context.hpp" @@ -1367,16 +1368,16 @@ namespace Sass { public: String_Constant(ParserState pstate, string val) : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(val)), hash_(0) - { } + { TRACEINST(this) << "String_Constant created " << this; } String_Constant(ParserState pstate, const char* beg) : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(string(beg))), hash_(0) - { } + { TRACEINST(this) << "String_Constant created " << this; } String_Constant(ParserState pstate, const char* beg, const char* end) : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(string(beg, end-beg))), hash_(0) - { } + { TRACEINST(this) << "String_Constant created " << this; } String_Constant(ParserState pstate, const Token& tok) : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(string(tok.begin, tok.end))), hash_(0) - { } + { TRACEINST(this) << "String_Constant created " << this; } string type() { return "string"; } static string type_name() { return "string"; } @@ -1404,6 +1405,16 @@ namespace Sass { static char double_quote() { return '"'; } static char single_quote() { return '\''; } + friend std::ostream& operator << (std::ostream& os, String_Constant& sq) { + os << "(" << (sq.quote_mark_ ? sq.quote_mark_ : '0') << ",\"" << sq.value_ << "\")"; + return os; + } + + friend std::ostream& operator << (std::ostream& os, String_Constant* sq) { + os << "(" << (sq->quote_mark_ ? sq->quote_mark_ : '0') << ",\"" << sq->value_ << "\")"; + return os; + } + ATTACH_OPERATIONS(); }; @@ -1416,6 +1427,7 @@ namespace Sass { : String_Constant(pstate, val) { value_ = unquote(value_, "e_mark_); + TRACEINST(this) << "String_Quoted created " << this; } ATTACH_OPERATIONS(); }; diff --git a/debug.cpp b/debug.cpp new file mode 100644 index 0000000000..2bbaac9950 --- /dev/null +++ b/debug.cpp @@ -0,0 +1,28 @@ +#include +#include + +#include "debug.hpp" + +namespace Sass { + + Log::Log() {} + + std::ostringstream& Log::Get(TLogLevel level, void *p, const char *f, const char *filen, int lineno) + { + os << "[LIBSASS] " << p << ":" << f << " " << filen << ":" << lineno << " "; + messageLevel = level; + return os; + } + std::ostringstream& Log::Get(TLogLevel level, const char *f, const char *filen, int lineno) + { + os << "[LIBSASS] " << f << " " << filen << ":" << lineno << " "; + messageLevel = level; + return os; + } + Log::~Log() + { + os << std::endl; + fprintf(stderr, "%s", os.str().c_str()); + fflush(stderr); + } +} diff --git a/debug.hpp b/debug.hpp index ba7629621d..e6eda2697e 100644 --- a/debug.hpp +++ b/debug.hpp @@ -1,6 +1,7 @@ #ifndef SASS_DEBUG_H #define SASS_DEBUG_H +#define __STDC_LIMIT_MACROS #include enum dbg_lvl_t : uint32_t { @@ -12,10 +13,44 @@ enum dbg_lvl_t : uint32_t { EXTEND_COMPOUND = 16, EXTEND_COMPLEX = 32, LCS = 64, - EXTEND_OBJECT = 128, + EXTEND_OBJECT = 128, ALL = UINT32_MAX }; +namespace Sass { + enum TLogLevel {logINFO, logTRACE}; + static TLogLevel LibsassLogReportingLevel = getenv("LIBSASS_TRACE") ? logTRACE : logINFO; + class Log + { + public: + Log(); + virtual ~Log(); + std::ostringstream& Get(TLogLevel level, void *p, const char *f, const char *filen, int lineno); + std::ostringstream& Get(TLogLevel level, const char *f, const char *filen, int lineno); + public: + protected: + std::ostringstream os; + private: + Log(const Log&); + Log& operator =(const Log&); + private: + TLogLevel messageLevel; + }; +} + +// Visual Studio 2013 does not like __func__ +#if _MSC_VER < 1900 +#define __func__ __FUNCTION__ +#endif + +#define TRACE() \ + if (logTRACE > Sass::LibsassLogReportingLevel) ; \ + else Sass::Log().Get(Sass::logTRACE, __func__, __FILE__, __LINE__) + +#define TRACEINST(obj) \ + if (logTRACE > Sass::LibsassLogReportingLevel) ; \ + else Sass::Log().Get(Sass::logTRACE, (obj), __func__, __FILE__, __LINE__) + #ifdef DEBUG #ifndef DEBUG_LVL diff --git a/eval.cpp b/eval.cpp index e874beb045..17d7c58f36 100644 --- a/eval.cpp +++ b/eval.cpp @@ -734,11 +734,14 @@ namespace Sass { } else if (value->concrete_type() == Expression::STRING) { if (auto str = dynamic_cast(value)) { + TRACEINST(str) << "dynamic_cast to String_Quoted worked " << str; value = new (ctx.mem) String_Quoted(*str); } else if (auto str = dynamic_cast(value)) { if (str->quote_mark()) { + TRACEINST(str) << "dynamic_cast to String_Quoted did not work, but we have quote " << str; value = new (ctx.mem) String_Quoted(str->pstate(), str->perform(&to_string)); } else { + TRACEINST(str) << "dynamic_cast to String_Quoted did not work, we are String_Constant " << str; value = new (ctx.mem) String_Constant(str->pstate(), unquote(str->value())); } } @@ -856,18 +859,26 @@ namespace Sass { string Eval::interpolation(Expression* s) { if (String_Quoted* str_quoted = dynamic_cast(s)) { + TRACEINST(str_quoted) << "dynamic_cast to String_Quoted worked " << str_quoted; if (str_quoted->quote_mark()) { if (str_quoted->quote_mark() == '*' || str_quoted->is_delayed()) { + TRACEINST(str_quoted) << "... will do interpolation()"; return interpolation(new (ctx.mem) String_Constant(*str_quoted)); } else { + TRACEINST(str_quoted) << "... will string_escape()"; return string_escape(quote(str_quoted->value(), str_quoted->quote_mark())); } } else { + TRACEINST(str_quoted) << "dynamic_cast to String_Quoted failed, will evacuate_escapes()"; return evacuate_escapes(str_quoted->value()); } } else if (String_Constant* str_constant = dynamic_cast(s)) { + TRACEINST(str_constant) << "dynamic_cast to String_Constant worked"; string str = str_constant->value(); - if (!str_constant->quote_mark()) str = unquote(str); + if (!str_constant->quote_mark()) { + TRACEINST(str_constant) << "... but still need to unquote()"; + str = unquote(str); + } return evacuate_escapes(str); } else if (String_Schema* str_schema = dynamic_cast(s)) { string res = ""; @@ -1011,14 +1022,22 @@ namespace Sass { Expression* feature = e->feature(); feature = (feature ? feature->perform(this) : 0); if (feature && dynamic_cast(feature)) { + String_Quoted *qfeature = dynamic_cast(feature); + TRACEINST(qfeature) << "dynamic_cast to String_Quoted worked " << qfeature; feature = new (ctx.mem) String_Constant(feature->pstate(), dynamic_cast(feature)->value()); + } else { + TRACEINST(feature) << "dynamic_cast to String_Quoted did not work for " << feature; } Expression* value = e->value(); value = (value ? value->perform(this) : 0); if (value && dynamic_cast(value)) { + String_Quoted *qvalue = dynamic_cast(value); + TRACEINST(qvalue) << "dynamic_cast to String_Quoted worked " << qvalue; value = new (ctx.mem) String_Constant(value->pstate(), dynamic_cast(value)->value()); + } else { + TRACEINST(value) << "dynamic_cast to String_Quoted did not work for " << value; } return new (ctx.mem) Media_Query_Expression(e->pstate(), feature, @@ -1358,7 +1377,11 @@ namespace Sass { 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(pstate, sass_string_get_value(v)); + if (sass_string_is_quoted(v)) + e = new (ctx.mem) String_Quoted(pstate, sass_string_get_value(v)); + else { + e = new (ctx.mem) String_Constant(pstate, sass_string_get_value(v)); + } } break; case SASS_LIST: { List* l = new (ctx.mem) List(pstate, sass_list_get_length(v), sass_list_get_separator(v) == SASS_COMMA ? List::COMMA : List::SPACE); diff --git a/output.cpp b/output.cpp index 87157af6c5..3115008795 100644 --- a/output.cpp +++ b/output.cpp @@ -128,6 +128,7 @@ namespace Sass { string val(valConst->value()); if (dynamic_cast(valConst)) { if (!valConst->quote_mark() && val.empty()) { + bPrintExpression = false; } } @@ -372,18 +373,24 @@ namespace Sass { void Output::operator()(String_Quoted* s) { + TRACEINST(s) << "This should be a quoted string... " << s; if (s->quote_mark()) { + TRACEINST(s) << "... it even has a quote mark property, sending with quote marks"; append_token(quote(s->value(), s->quote_mark()), s); } else if (!in_comment) { + TRACEINST(s) << "... no quote mark(?), sending via string_to_output"; append_token(string_to_output(s->value()), s); } else { + TRACEINST(s) << "... no quote mark(?), sending directly (in comment)"; append_token(s->value(), s); } } void Output::operator()(String_Constant* s) { + TRACEINST(s) << "This should be a constant string... " << s; if (String_Quoted* quoted = dynamic_cast(s)) { + TRACEINST(s) << "... but dynamic_cast worked"; return Output::operator()(quoted); } else { string value(s->value()); @@ -391,8 +398,10 @@ namespace Sass { value.erase(std::remove_if(value.begin(), value.end(), ::isspace), value.end()); } if (!in_comment) { + TRACEINST(s) << "... sending via string_to_output"; append_token(string_to_output(value), s); } else { + TRACEINST(s) << "... sending directly (in comment)"; append_token(value, s); } } diff --git a/parser.cpp b/parser.cpp index a9d3f0e93d..049f422146 100644 --- a/parser.cpp +++ b/parser.cpp @@ -1381,6 +1381,7 @@ namespace Sass { if (lex< identifier >()) { String_Constant* str = new (ctx.mem) String_Quoted(pstate, lexed); + TRACEINST(str) << "We have just created a new instance " << str; // Dont' delay this string if it is a name color. Fixes #652. str->is_delayed(ctx.names_to_colors.count(unquote(lexed)) == 0); return str; diff --git a/sass_values.cpp b/sass_values.cpp index a00e15e12f..1b05e1a5e9 100644 --- a/sass_values.cpp +++ b/sass_values.cpp @@ -322,7 +322,7 @@ extern "C" { return sass_make_color(val->color.r, val->color.g, val->color.b, val->color.a); } break; case SASS_STRING: { - return sass_make_string(val->string.value); + return sass_string_is_quoted(val) ? sass_make_qstring(val->string.value) : sass_make_string(val->string.value); } break; case SASS_LIST: { union Sass_Value* list = sass_make_list(val->list.length, val->list.separator); diff --git a/to_c.cpp b/to_c.cpp index b03bb4a3fb..e3220e5d75 100644 --- a/to_c.cpp +++ b/to_c.cpp @@ -19,7 +19,19 @@ namespace Sass { { return sass_make_color(c->r(), c->g(), c->b(), c->a()); } Sass_Value* To_C::operator()(String_Constant* s) - { return sass_make_string(s->value().c_str()); } + { + if (s->quote_mark()) { + TRACEINST(s) << "We got String_Constant, but we convert quoted value to C" << s; + return sass_make_qstring(s->value().c_str()); + } else { + TRACEINST(s) << "Converting unquoted value to C" << s; + return sass_make_string(s->value().c_str()); + } + } + + Sass_Value* To_C::operator()(String_Quoted* s) + { TRACEINST(s) << "Converting quoted value to C" << s; + return sass_make_qstring(s->value().c_str()); } Sass_Value* To_C::operator()(List* l) { diff --git a/to_c.hpp b/to_c.hpp index 409c90c06c..7b734ad59f 100644 --- a/to_c.hpp +++ b/to_c.hpp @@ -29,6 +29,7 @@ namespace Sass { Sass_Value* operator()(Number*); Sass_Value* operator()(Color*); Sass_Value* operator()(String_Constant*); + Sass_Value* operator()(String_Quoted*); Sass_Value* operator()(List*); Sass_Value* operator()(Map*); Sass_Value* operator()(Null*); @@ -41,4 +42,4 @@ namespace Sass { } -#endif \ No newline at end of file +#endif diff --git a/util.cpp b/util.cpp index 831a4b7cd9..a39e385578 100644 --- a/util.cpp +++ b/util.cpp @@ -1,4 +1,5 @@ -#include +#define __STDC_LIMIT_MACROS +#include #include "ast.hpp" #include "util.hpp" #include "prelexer.hpp" diff --git a/win/libsass.vcxproj b/win/libsass.vcxproj index a6cb1cb4bc..d327e8492b 100644 --- a/win/libsass.vcxproj +++ b/win/libsass.vcxproj @@ -169,6 +169,7 @@ +