Commit 7ec14dff by xzyfer Committed by Michael Mifsud

Bump LibSass@3.5.3

parent eb5ad0a7
{
"name": "node-sass",
"version": "4.9.0",
"libsass": "3.5.2",
"libsass": "3.5.3",
"description": "Wrapper around libsass",
"license": "MIT",
"bugs": "https://github.com/sass/node-sass/issues",
......@@ -83,7 +83,7 @@
"object-merge": "^2.5.1",
"read-yaml": "^1.0.0",
"rimraf": "^2.5.2",
"sass-spec": "^3.5.1",
"sass-spec": "3.5.3",
"unique-temp-dir": "^1.0.0"
}
}
......@@ -25,63 +25,49 @@ else
AM_CXXFLAGS += -std=c++0x
endif
TEST_EXTENSIONS = .rb
if ENABLE_TESTS
noinst_PROGRAMS = tester
SASS_SASSC_PATH ?= $(top_srcdir)/sassc
SASS_SPEC_PATH ?= $(top_srcdir)/sass-spec
noinst_PROGRAMS = tester
tester_LDADD = src/libsass.la
tester_SOURCES = $(SASS_SASSC_PATH)/sassc.c
tester_VERSION ?= `cd "$(SASS_SASSC_PATH)" && ./version.sh`
tester_CFLAGS = $(AM_CFLAGS) -DSASSC_VERSION="\"$(tester_VERSION)\""
tester_CXXFLAGS = $(AM_CXXFLAGS) -DSASSC_VERSION="\"$(tester_VERSION)\""
tester_LDFLAGS = $(AM_LDFLAGS)
nodist_tester_SOURCES = $(SASS_SASSC_PATH)/sassc.c
SASS_SASSC_VERSION ?= `cd "$(SASS_SASSC_PATH)" && ./version.sh`
tester_CFLAGS = $(AM_CFLAGS) -DSASSC_VERSION="\"$(SASS_SASSC_VERSION)\""
tester_CXXFLAGS = $(AM_CXXFLAGS) -DSASSC_VERSION="\"$(SASS_SASSC_VERSION)\""
if ENABLE_COVERAGE
nodist_EXTRA_tester_SOURCES = non-existent-file-to-force-CXX-linking.cxx
endif
SASS_SASSC_PATH ?= $(top_srcdir)/sassc
SASS_SPEC_PATH ?= $(top_srcdir)/sass-spec
TESTS = \
$(SASS_SPEC_PATH)/spec/basic \
$(SASS_SPEC_PATH)/spec/css \
$(SASS_SPEC_PATH)/spec/extend-tests \
$(SASS_SPEC_PATH)/spec/extends \
$(SASS_SPEC_PATH)/spec/libsass \
$(SASS_SPEC_PATH)/spec/libsass-closed-issues \
$(SASS_SPEC_PATH)/spec/maps \
$(SASS_SPEC_PATH)/spec/misc \
$(SASS_SPEC_PATH)/spec/regressions \
$(SASS_SPEC_PATH)/spec/scss \
$(SASS_SPEC_PATH)/spec/scss-tests \
$(SASS_SPEC_PATH)/spec/types
TESTS = $(SASS_SPEC_PATH)/sass-spec.rb
RB_LOG_COMPILER = ./script/tap-runner
AM_RB_LOG_FLAGS = $(RUBY)
SASS_TEST_FLAGS = -V 3.5 --impl libsass
LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) ./script/tap-driver
AM_LOG_FLAGS = -c ./tester $(LOG_FLAGS)
if USE_TAP
AM_LOG_FLAGS += -t
SASS_TEST_FLAGS += -t | tapout
LOG_COMPILER = ./script/tap-runner $(RUBY) $(SASS_SPEC_PATH)/sass-spec.rb
else
LOG_COMPILER = $(RUBY) $(SASS_SPEC_PATH)/sass-spec.rb
endif
SASS_TEST_FLAGS += -r $(SASS_SPEC_PATH)
SASS_TEST_FLAGS += -c $(top_srcdir)/tester$(EXEEXT)
AM_TESTS_ENVIRONMENT = TEST_FLAGS='$(SASS_TEST_FLAGS)'
SASS_TESTER = $(RUBY) $(SASS_SPEC_PATH)/sass-spec.rb
SASS_TESTER += -c $(top_srcdir)/tester$(EXEEXT)
test:
$(SASS_TESTER) $(LOG_FLAGS) $(SASS_SPEC_PATH) $(SASS_TEST_FLAGS)
$(SASS_TESTER) $(SASS_TEST_FLAGS)
test_build:
$(SASS_TESTER) $(LOG_FLAGS) $(SASS_SPEC_PATH) $(SASS_TEST_FLAGS)
$(SASS_TESTER) $(SASS_TEST_FLAGS)
test_full:
$(SASS_TESTER) --run-todo $(LOG_FLAGS) $(SASS_SPEC_PATH) $(SASS_TEST_FLAGS)
$(SASS_TESTER) --run-todo $(SASS_TEST_FLAGS)
test_probe:
$(SASS_TESTER) --probe-todo $(LOG_FLAGS) $(SASS_SPEC_PATH) $(SASS_TEST_FLAGS)
$(SASS_TESTER) --probe-todo $(SASS_TEST_FLAGS)
.PHONY: test test_build test_full test_probe
endif
......
......@@ -9,6 +9,7 @@ AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([src/config.h])
AC_CONFIG_FILES([include/sass/version.h])
AC_CONFIG_AUX_DIR([script])
# These are flags passed to automake
# Though they look like gcc flags!
AM_INIT_AUTOMAKE([foreign parallel-tests -Wall])
......@@ -93,21 +94,16 @@ the --with-sass-spec-dir=<dir> argument.
;;
esac
AC_SUBST(SASS_SPEC_PATH)
# TODO: Remove this when automake requirements are 1.12+
AC_MSG_CHECKING([whether we can use TAP mode])
tmp=`$AWK '/TEST_LOG_DRIVER/' $srcdir/GNUmakefile.in`
if test "x$tmp" != "x"; then
use_tap=yes
else
use_tap=no
fi
AC_MSG_RESULT([$use_tap])
else
# we do not really need these paths for non test build
# but automake may error if we do not define them here
SASS_SPEC_PATH=sass-spec
SASS_SASSC_PATH=sassc
AC_SUBST(SASS_SPEC_PATH)
AC_SUBST(SASS_SASSC_PATH)
fi
AM_CONDITIONAL(ENABLE_TESTS, test "x$enable_tests" = "xyes")
AM_CONDITIONAL(USE_TAP, test "x$use_tap" = "xyes")
AC_ARG_ENABLE([coverage],
[AS_HELP_STRING([--enable-coverage],
......
......@@ -14,6 +14,17 @@ There are several implementations of `libsass` for a variety of languages. Here
* [go_sass](https://github.com/suapapa/go_sass)
* [go-sass](https://github.com/SamWhited/go-sass)
### Haskell
* [hLibsass](https://github.com/jakubfijalkowski/hlibsass)
* [hSass](https://github.com/jakubfijalkowski/hsass)
### Java
* [libsass-maven-plugin](https://github.com/warmuuh/libsass-maven-plugin)
* [jsass](https://github.com/bit3/jsass)
### JavaScript
* [sass.js](https://github.com/medialize/sass.js)
### Lua
* [lua-sass](https://github.com/craigbarnes/lua-sass)
......@@ -21,16 +32,14 @@ There are several implementations of `libsass` for a variety of languages. Here
* [libsass-net](https://github.com/darrenkopp/libsass-net)
* [NSass](https://github.com/TBAPI-0KA/NSass)
* [Sass.Net](https://github.com/andyalm/Sass.Net)
* [SharpScss](https://github.com/xoofx/SharpScss)
* [LibSassHost](https://github.com/Taritsyn/LibSassHost)
### node.js
* [node-sass](https://github.com/andrew/node-sass)
### Java
* [libsass-maven-plugin](https://github.com/warmuuh/libsass-maven-plugin)
* [jsass](https://github.com/bit3/jsass)
### Nim
* [nim-sass](https://github.com/zacharycarter/nim-sass)
### JavaScript
* [sass.js](https://github.com/medialize/sass.js)
### node.js
* [node-sass](https://github.com/sass/node-sass)
### Perl
* [CSS::Sass](https://github.com/caldwell/CSS-Sass)
......
LibSass currently expects all input to be utf8 encoded (and outputs only utf8), if you actually have any unicode characters at all. We do not support conversion between encodings, even if you declare it with a `@charset` rule. The text below was originally posted as an [issue](https://github.com/sass/libsass/issues/381) on the LibSass tracker.
LibSass currently expects all input to be utf8 encoded (and outputs only utf8), if you actually have any unicode characters at all. We do not support conversion between encodings, even if you declare it with a `@charset` rule. The text below was originally posted as an [issue](https://github.com/sass/libsass/issues/381) on the LibSass tracker. Since then the status is outdated as LibSass now expects your
input to be utf8/ascii compatible, as it has been proven that reading ANSI (e.g. single byte encodings) as utf8 can lead to unexpected
behavior, which can in the worst case lead to buffer overruns/segfaults. Therefore LibSass now checks your input to be valid utf8 encoded!
### [Declaring character encodings in CSS](http://www.w3.org/International/questions/qa-css-charset.en)
This [explains](http://www.w3.org/International/questions/qa-css-charset.en) how the character encoding of a css file is determined. Since we are only dealing with local files, we never have a HTTP header. So the precedence should be 'charset' rule, byte-order mark (BOM) or auto-detection (finally falling back to system default/UTF-8). This may not sound too hard to implement, but what about import rules? The CSS specs do not forbid the mixing of different encodings! I solved that by converting all files to UTF-8 internally. On writing there is an option to tell the tool what encoding it should be (UTF-8 by default). One can also define if it should write a BOM or not and if it should add the charset declaration.
This [explains](http://www.w3.org/International/questions/qa-css-charset.en) how the character encoding of a css file is determined. Since we are only dealing with local files, we never have a HTTP header. So the precedence should be 'charset' rule, byte-order mark (BOM) or auto-detection (finally falling back to system default/UTF-8). This may not sound too hard to implement, but what about import rules? The CSS specs do not forbid the mixing of different encodings! I [solved that](https://github.com/mgreter/webmerge/) by converting all files to UTF-8 internally. On writing there is an option to tell the tool what encoding it should be (UTF-8 by default). One can also define if it should write a BOM or not and if it should add the charset declaration.
Since my tool is written in perl, I have a lot of utilities at hand to deal with different unicode charsets. I'm pretty sure that most OSS uses [libiconv](https://www.gnu.org/software/libiconv/) to convert between different encodings. But I have now idea how easy/hard this would be to integrate platform independent (it seems doable).
Since my [tool]((https://github.com/mgreter/webmerge/)) is written in perl, I have a lot of utilities at hand to deal with different unicode charsets. I'm pretty sure that most OSS uses [ICU](http://site.icu-project.org/) or [libiconv](https://www.gnu.org/software/libiconv/) to convert between different encodings. But I have now idea how easy/hard this would be to integrate platform independent (it seems doable). ANSII (single byte encoding) to utf8 is basically just a conversion table (for every supported code-page).
### Current status on LibSass unicode support
Currently LibSass seems to handle the common UTF-8 case pretty well. I believe it should correctly support all ASCII compatible encodings (like UTF-8 or Latin-1). If all includes use the same encoding, the output should be correct (in the same encoding). It should also handle unicode chars in [selectors, variable names and other identifiers](https://github.com/hcatlin/libsass/issues/244#issuecomment-34681227). This is true for all ASCII compatible encodings. So the main incompatible encodings (I'm aware of) are UTF-16/UTF-32 (which could be converted to UTF-8 with libiconv).
LibSass should/is fully UTF (and therefore plain ASCII) compatible.
~~Currently LibSass seems to handle the common UTF-8 case pretty well. I believe it should correctly support all ASCII compatible encodings (like UTF-8 or Latin-1). If all includes use the same encoding, the output should be correct (in the same encoding). It should also handle unicode chars in [selectors, variable names and other identifiers](https://github.com/hcatlin/libsass/issues/244#issuecomment-34681227). This is true for all ASCII compatible encodings. So the main incompatible encodings (I'm aware of) are UTF-16/UTF-32 (which could be converted to UTF-8 with libiconv).~~
LibSass 3.5 will enforce that your input is either plain ASCII (chars below 127) or utf8. It does not handle anything else, but therefore ensures that the output is in a valid form. Before version 3.5 you were able to mix different code-pages, which yielded unexpected behavior.
### Current encoding auto detection
LibSass currently reads all kind of BOMs and will error out if it finds something it doesn't know how to handle! It seems that it throws away the optional UTF-8 BOM (if any is found). IMO it would be nice if users could configure that (also if a charset rule should be added to the output).
LibSass currently reads all kind of BOMs and will error out if it finds something it doesn't know how to handle! It seems that it throws away the optional UTF-8 BOM (if any is found). IMO it would be nice if users could configure that (also if a charset rule should be added to the output). But it does not really take any `@charset` into account, it always assumes your input is utf8 and ignores any given `@charset`!
### What is currently not supported
- Using non ASCII compatible encodings (like UTF-16)
- Using non ASCII compatible encodings (like UTF-16, Latin-1 etc.)
- Using non ASCII characters in different encodings in different includes
### What is missing to support the above cases
- A way to convert between encodings (like libiconv)
- A way to convert between encodings (like libiconv/ICU)
- Sniffing the charset inside the file (source is available)
- Handling the conversion on import (and export)
- Optional: Make output encoding configurable
......@@ -31,9 +37,9 @@ LibSass currently reads all kind of BOMs and will error out if it finds somethin
I guess the current implementation should handle more than 99% of all real world use cases.
A) Unicode characters are still seldomly seen (as they can be written escaped)
B) It will still work if it's UTF-8 or in any of the most common known western ISO codepages.
Although I'm not sure how this applies to asian and other "exotic" codepages!
~~B) It will still work if it's UTF-8 or in any of the most common known western ISO codepages.
Although I'm not sure how this applies to asian and other "exotic" codepages!~~
I guess the biggest Problem is to have libiconv (or some other) library as a dependency. Since it contains a lot of rules for the conversions, I see it as the only way to handle this correctly. Once that is sorted out it should be pretty much straight forward to implement the missing pieces (in parser.cpp - Parser::parse should return encoding and add Parser::sniff_charset, then convert the source byte stream to UTF-8).
I guess the biggest Problem is to have libiconv/ICU (or some other) library as a dependency. Since it contains a lot of rules for the conversions, I see it as the only way to handle this correctly. Once that is sorted out it should be pretty much straight forward to implement the missing pieces (in parser.cpp - Parser::parse should return encoding and add Parser::sniff_charset, then convert the source byte stream to UTF-8).
I hope the statements above all hold true. Unicode is really not the easiest topic to wrap your head around. But since I did all the above recently in Perl, I wanted to document it here. Feel free to extend or criticize.
......@@ -149,6 +149,9 @@ ADDAPI size_t ADDCALL sass_compiler_get_callee_stack_size(struct Sass_Compiler*
ADDAPI Sass_Callee_Entry ADDCALL sass_compiler_get_last_callee(struct Sass_Compiler* compiler);
ADDAPI Sass_Callee_Entry ADDCALL sass_compiler_get_callee_entry(struct Sass_Compiler* compiler, size_t idx);
// Push function for import extenions
ADDAPI void ADDCALL sass_option_push_import_extension (struct Sass_Options* options, const char* ext);
// Push function for paths (no manipulation support for now)
ADDAPI void ADDCALL sass_option_push_plugin_path (struct Sass_Options* options, const char* path);
ADDAPI void ADDCALL sass_option_push_include_path (struct Sass_Options* options, const char* path);
......
$@ | tapout tap
\ No newline at end of file
$@ $TEST_FLAGS --tap --silent | tapout tap
......@@ -96,6 +96,8 @@ namespace Sass {
// include_paths.push_back(CWD);
// collect more paths from different options
collect_extensions(c_options.extension);
collect_extensions(c_options.extensions);
collect_include_paths(c_options.include_path);
collect_include_paths(c_options.include_paths);
collect_plugin_paths(c_options.plugin_path);
......@@ -166,6 +168,37 @@ namespace Sass {
{
}
void Context::collect_extensions(const char* exts_str)
{
if (exts_str) {
const char* beg = exts_str;
const char* end = Prelexer::find_first<PATH_SEP>(beg);
while (end) {
std::string ext(beg, end - beg);
if (!ext.empty()) {
extensions.push_back(ext);
}
beg = end + 1;
end = Prelexer::find_first<PATH_SEP>(beg);
}
std::string ext(beg);
if (!ext.empty()) {
extensions.push_back(ext);
}
}
}
void Context::collect_extensions(string_list* paths_array)
{
while (paths_array)
{
collect_extensions(paths_array->string);
paths_array = paths_array->next;
}
}
void Context::collect_include_paths(const char* paths_str)
{
if (paths_str) {
......@@ -236,15 +269,20 @@ namespace Sass {
// looks for alternatives and returns a list from one directory
std::vector<Include> Context::find_includes(const Importer& import)
{
// include configured extensions
std::vector<std::string> exts(File::defaultExtensions);
if (extensions.size() > 0) {
exts.insert(exts.end(), extensions.begin(), extensions.end());
}
// make sure we resolve against an absolute path
std::string base_path(rel2abs(import.base_path));
// first try to resolve the load path relative to the base path
std::vector<Include> vec(resolve_includes(base_path, import.imp_path));
std::vector<Include> vec(resolve_includes(base_path, import.imp_path, exts));
// then search in every include path (but only if nothing found yet)
for (size_t i = 0, S = include_paths.size(); vec.size() == 0 && i < S; ++i)
{
// call resolve_includes and individual base path and append all results
std::vector<Include> resolved(resolve_includes(include_paths[i], import.imp_path));
std::vector<Include> resolved(resolve_includes(include_paths[i], import.imp_path, exts));
if (resolved.size()) vec.insert(vec.end(), resolved.begin(), resolved.end());
}
// return vector
......@@ -365,6 +403,14 @@ namespace Sass {
// process the resolved entry
else if (resolved.size() == 1) {
bool use_cache = c_importers.size() == 0;
if (resolved[0].deprecated) {
// emit deprecation warning when import resolves to a .css file
deprecated(
"Including .css files with @import is non-standard behaviour which will be removed in future versions of LibSass.",
"Use a custom importer to maintain this behaviour. Check your implementations documentation on how to create a custom importer.",
true, pstate
);
}
// use cache for the resource loading
if (use_cache && sheets.count(resolved[0].abs_path)) return resolved[0];
// try to read the content of the resolved file entry
......
......@@ -67,6 +67,7 @@ namespace Sass {
std::vector<std::string> plugin_paths; // relative paths to load plugins
std::vector<std::string> include_paths; // lookup paths for includes
std::vector<std::string> extensions; // lookup extensions for imports`
......@@ -109,6 +110,8 @@ namespace Sass {
void collect_plugin_paths(string_list* paths_array);
void collect_include_paths(const char* paths_str);
void collect_include_paths(string_list* paths_array);
void collect_extensions(const char* extensions_str);
void collect_extensions(string_list* extensions_array);
std::string format_embedded_source_map();
std::string format_source_mapping_url(const std::string& out_path);
......
......@@ -559,7 +559,7 @@ namespace Sass {
std::string m1 = std::string(mq1->is_restricted() ? "only" : mq1->is_negated() ? "not" : "");
std::string t1 = mq1->media_type() ? mq1->media_type()->to_string(ctx.c_options) : "";
std::string m2 = std::string(mq2->is_restricted() ? "only" : mq1->is_negated() ? "not" : "");
std::string m2 = std::string(mq2->is_restricted() ? "only" : mq2->is_negated() ? "not" : "");
std::string t2 = mq2->media_type() ? mq2->media_type()->to_string(ctx.c_options) : "";
......
......@@ -627,6 +627,7 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env)
Number_Ptr expression = Cast<Number>(node);
std::cerr << ind << "Number " << expression;
std::cerr << " (" << pstate_source_position(node) << ")";
std::cerr << " [delayed: " << expression->is_delayed() << "] ";
std::cerr << " [interpolant: " << expression->is_interpolant() << "] ";
std::cerr << " [" << expression->value() << expression->unit() << "]" <<
" [hash: " << expression->hash() << "] " <<
......
......@@ -599,10 +599,6 @@ namespace Sass {
switch (op_type) {
case Sass_OP::EQ: return *l_n == *r_c ? bool_true : bool_false;
case Sass_OP::NEQ: return *l_n == *r_c ? bool_false : bool_true;
case Sass_OP::LT: return *l_n < *r_c ? bool_true : bool_false;
case Sass_OP::GTE: return *l_n < *r_c ? bool_false : bool_true;
case Sass_OP::LTE: return *l_n < *r_c || *l_n == *r_c ? bool_true : bool_false;
case Sass_OP::GT: return *l_n < *r_c || *l_n == *r_c ? bool_false : bool_true;
case Sass_OP::ADD: case Sass_OP::SUB: case Sass_OP::MUL: case Sass_OP::DIV: case Sass_OP::MOD:
return Operators::op_number_color(op_type, *l_n, *r_c, ctx.c_options, b_in->pstate());
default: break;
......@@ -643,10 +639,6 @@ namespace Sass {
switch (op_type) {
case Sass_OP::EQ: return *l_c == *r_n ? bool_true : bool_false;
case Sass_OP::NEQ: return *l_c == *r_n ? bool_false : bool_true;
case Sass_OP::LT: return *l_c < *r_n ? bool_true : bool_false;
case Sass_OP::GTE: return *l_c < *r_n ? bool_false : bool_true;
case Sass_OP::LTE: return *l_c < *r_n || *l_c == *r_n ? bool_true : bool_false;
case Sass_OP::GT: return *l_c < *r_n || *l_c == *r_n ? bool_false : bool_true;
case Sass_OP::ADD: case Sass_OP::SUB: case Sass_OP::MUL: case Sass_OP::DIV: case Sass_OP::MOD:
return Operators::op_color_number(op_type, *l_c, *r_n, ctx.c_options, b_in->pstate());
default: break;
......@@ -1265,13 +1257,6 @@ namespace Sass {
Expression_Ptr Eval::operator()(String_Constant_Ptr s)
{
if (!s->is_delayed() && name_to_color(s->value())) {
Color_Ptr c = SASS_MEMORY_COPY(name_to_color(s->value())); // copy
c->pstate(s->pstate());
c->disp(s->value());
c->is_delayed(true);
return c;
}
return s;
}
......
......@@ -246,7 +246,8 @@ namespace Sass {
std::string str(prop->to_string(ctx.c_options));
new_p = SASS_MEMORY_NEW(String_Constant, old_p->pstate(), str);
}
Expression_Obj value = d->value()->perform(&eval);
Expression_Obj value = d->value();
if (value) value = value->perform(&eval);
Block_Obj bb = ab ? operator()(ab) : NULL;
if (!bb) {
if (!value || (value->is_invisible() && !d->is_important())) return 0;
......
......@@ -342,13 +342,13 @@ namespace Sass {
for(auto ext : exts) {
rel_path = join_paths(base, "_" + name + ext);
abs_path = join_paths(root, rel_path);
if (file_exists(abs_path)) includes.push_back({{ rel_path, root }, abs_path });
if (file_exists(abs_path)) includes.push_back({{ rel_path, root }, abs_path, ext == ".css" });
}
// next test plain name with exts
for(auto ext : exts) {
rel_path = join_paths(base, name + ext);
abs_path = join_paths(root, rel_path);
if (file_exists(abs_path)) includes.push_back({{ rel_path, root }, abs_path });
if (file_exists(abs_path)) includes.push_back({{ rel_path, root }, abs_path, ext == ".css" });
}
// nothing found
return includes;
......
......@@ -89,9 +89,14 @@ namespace Sass {
public:
// resolved absolute path
std::string abs_path;
// is a deprecated file type
bool deprecated;
public:
Include(const Importer& imp, std::string abs_path, bool deprecated)
: Importer(imp), abs_path(abs_path), deprecated(deprecated)
{ }
Include(const Importer& imp, std::string abs_path)
: Importer(imp), abs_path(abs_path)
: Importer(imp), abs_path(abs_path), deprecated(false)
{ }
};
......@@ -121,11 +126,12 @@ namespace Sass {
namespace File {
static std::vector<std::string> defaultExtensions = { ".scss", ".sass", ".css" };
static std::vector<std::string> defaultExtensions = { ".scss", ".sass" };
std::vector<Include> resolve_includes(const std::string& root, const std::string& file,
const std::vector<std::string>& exts = defaultExtensions);
}
}
......
......@@ -467,7 +467,7 @@ namespace Sass {
double s;
double l = (max + min) / 2.0;
if (max == min) {
if (NEAR_EQUAL(max, min)) {
h = s = 0; // achromatic
}
else {
......
......@@ -658,6 +658,9 @@ namespace Sass {
}
std::stringstream hexlet;
// dart sass compressed all colors in regular css always
// ruby sass and libsass does it only when not delayed
// since color math is going to be removed, this can go too
bool compressed = opt.output_style == COMPRESSED;
hexlet << '#' << std::setw(1) << std::setfill('0');
// create a short color hexlet if there is any need for it
......@@ -681,9 +684,6 @@ namespace Sass {
if (name != "") {
ss << name;
}
else if (r == 0 && g == 0 && b == 0 && a == 0) {
ss << "transparent";
}
else if (a >= 1) {
if (res_name != "") {
if (compressed && hexlet.str().size() < res_name.size()) {
......
......@@ -127,15 +127,15 @@ namespace Sass {
double lval = lhs.value();
double rval = rhs.value();
if (op == Sass_OP::MOD && rval == 0) {
return SASS_MEMORY_NEW(String_Quoted, pstate, "NaN");
}
if (op == Sass_OP::DIV && rval == 0) {
std::string result(lval ? "Infinity" : "NaN");
return SASS_MEMORY_NEW(String_Quoted, pstate, result);
}
if (op == Sass_OP::MOD && rval == 0) {
throw Exception::ZeroDivisionError(lhs, rhs);
}
size_t l_n_units = lhs.numerators.size();
size_t l_d_units = lhs.numerators.size();
size_t r_n_units = rhs.denominators.size();
......
......@@ -1578,7 +1578,7 @@ namespace Sass {
return nr;
}
Expression_Ptr Parser::lexed_hex_color(const ParserState& pstate, const std::string& parsed)
Value_Ptr Parser::lexed_hex_color(const ParserState& pstate, const std::string& parsed)
{
Color_Ptr color = NULL;
if (parsed[0] != '#') {
......@@ -1628,6 +1628,19 @@ namespace Sass {
return color;
}
Value_Ptr Parser::color_or_string(const std::string& lexed) const
{
if (auto color = name_to_color(lexed)) {
auto c = SASS_MEMORY_NEW(Color, color);
c->is_delayed(true);
c->pstate(pstate);
c->disp(lexed);
return c;
} else {
return SASS_MEMORY_NEW(String_Constant, pstate, lexed);
}
}
// parse one value for a list
Expression_Obj Parser::parse_value()
{
......@@ -1670,7 +1683,7 @@ namespace Sass {
{ return SASS_MEMORY_NEW(Null, pstate); }
if (lex< identifier >()) {
return SASS_MEMORY_NEW(String_Constant, pstate, lexed);
return color_or_string(lexed);
}
if (lex< percentage >())
......@@ -1841,7 +1854,7 @@ namespace Sass {
return schema->length() > 0 ? schema.detach() : NULL;
}
String_Constant_Obj Parser::parse_static_value()
Value_Obj Parser::parse_static_value()
{
lex< static_value >();
Token str(lexed);
......@@ -1852,8 +1865,7 @@ namespace Sass {
--str.end;
--position;
String_Constant_Ptr str_node = SASS_MEMORY_NEW(String_Constant, pstate, str.time_wspace());
return str_node;
return color_or_string(str.time_wspace());;
}
String_Obj Parser::parse_string()
......@@ -1962,7 +1974,7 @@ namespace Sass {
if (lex< re_static_expression >()) {
ex = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
} else {
ex = parse_list();
ex = parse_list(true);
}
ex->is_interpolant(true);
schema->append(ex);
......@@ -1986,7 +1998,7 @@ namespace Sass {
}
if (peek < exactly < '-' > >()) break;
}
else if (lex< sequence < identifier > >()) {
else if (lex< identifier >()) {
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed));
if ((*position == '"' || *position == '\'') || peek < alternatives < alpha > >()) {
// need_space = true;
......@@ -2691,7 +2703,9 @@ namespace Sass {
if ((rv = lex_interp_string())) return rv;
if ((rv = lex_interp_uri())) return rv;
if ((rv = lex_interpolation())) return rv;
return rv;
if (lex< alternatives< hex, hex0 > >())
{ return lexed_hex_color(lexed); }
return rv;
}
String_Schema_Obj Parser::parse_almost_any_value()
......@@ -2777,6 +2791,7 @@ namespace Sass {
>(p)
) {
bool could_be_property = peek< sequence< exactly<'-'>, exactly<'-'> > >(p) != 0;
bool could_be_escaped = false;
while (p < q) {
// did we have interpolations?
if (*p == '#' && *(p+1) == '{') {
......@@ -2785,9 +2800,10 @@ namespace Sass {
}
// A property that's ambiguous with a nested selector is interpreted as a
// custom property.
if (*p == ':') {
if (*p == ':' && !could_be_escaped) {
rv.is_custom_property = could_be_property || p+1 == q || peek< space >(p+1);
}
could_be_escaped = *p == '\\';
++ p;
}
// store anyway }
......
......@@ -290,7 +290,7 @@ namespace Sass {
String_Obj parse_url_function_argument();
String_Obj parse_interpolated_chunk(Token, bool constant = false, bool css = true);
String_Obj parse_string();
String_Constant_Obj parse_static_value();
Value_Obj parse_static_value();
String_Schema_Obj parse_css_variable_value(bool top_level = true);
String_Schema_Obj parse_css_variable_value_token(bool top_level = true);
String_Obj parse_ie_property();
......@@ -325,6 +325,8 @@ namespace Sass {
Error_Obj parse_error();
Debug_Obj parse_debug();
Value_Ptr color_or_string(const std::string& lexed) const;
// be more like ruby sass
Expression_Obj lex_almost_any_value_token();
Expression_Obj lex_almost_any_value_chars();
......@@ -380,12 +382,12 @@ namespace Sass {
static Number_Ptr lexed_number(const ParserState& pstate, const std::string& parsed);
static Number_Ptr lexed_dimension(const ParserState& pstate, const std::string& parsed);
static Number_Ptr lexed_percentage(const ParserState& pstate, const std::string& parsed);
static Expression_Ptr lexed_hex_color(const ParserState& pstate, const std::string& parsed);
static Value_Ptr lexed_hex_color(const ParserState& pstate, const std::string& parsed);
private:
Number_Ptr lexed_number(const std::string& parsed) { return lexed_number(pstate, parsed); };
Number_Ptr lexed_dimension(const std::string& parsed) { return lexed_dimension(pstate, parsed); };
Number_Ptr lexed_percentage(const std::string& parsed) { return lexed_percentage(pstate, parsed); };
Expression_Ptr lexed_hex_color(const std::string& parsed) { return lexed_hex_color(pstate, parsed); };
Value_Ptr lexed_hex_color(const std::string& parsed) { return lexed_hex_color(pstate, parsed); };
static const char* re_attr_sensitive_close(const char* src);
static const char* re_attr_insensitive_close(const char* src);
......
......@@ -1606,7 +1606,7 @@ namespace Sass {
>(src);
}
extern const char css_variable_url_top_level_negates[] = "()[]{}\"'#/;!";
extern const char css_variable_url_top_level_negates[] = "()[]{}\"'#/;";
const char* css_variable_top_level_value(const char* src) {
return sequence<
alternatives<
......
......@@ -33,8 +33,10 @@ extern "C" {
void* ADDCALL sass_alloc_memory(size_t size)
{
void* ptr = malloc(size);
if (ptr == NULL)
out_of_memory();
if (ptr == NULL) {
std::cerr << "Out of memory.\n";
exit(EXIT_FAILURE);
}
return ptr;
}
......
......@@ -154,6 +154,21 @@ namespace Sass
}
static size_t findFirstCharacter (std::string& sass, size_t pos)
{
return sass.find_first_not_of(SASS2SCSS_FIND_WHITESPACE, pos);
}
static size_t findLastCharacter (std::string& sass, size_t pos)
{
return sass.find_last_not_of(SASS2SCSS_FIND_WHITESPACE, pos);
}
static bool isUrl (std::string& sass, size_t pos)
{
return sass[pos] == 'u' && sass[pos+1] == 'r' && sass[pos+2] == 'l' && sass[pos+3] == '(';
}
// check if there is some char data
// will ignore everything in comments
static bool hasCharData (std::string& sass)
......@@ -587,6 +602,7 @@ namespace Sass
sass.substr(pos_left, 5) == "@warn" ||
sass.substr(pos_left, 6) == "@debug" ||
sass.substr(pos_left, 6) == "@error" ||
sass.substr(pos_left, 6) == "@value" ||
sass.substr(pos_left, 8) == "@charset" ||
sass.substr(pos_left, 10) == "@namespace"
) { sass = indent + sass.substr(pos_left); }
......@@ -606,23 +622,38 @@ namespace Sass
{
// get positions for the actual import url
size_t pos_import = sass.find_first_of(SASS2SCSS_FIND_WHITESPACE, pos_left + 7);
size_t pos_quote = sass.find_first_not_of(SASS2SCSS_FIND_WHITESPACE, pos_import);
// leave proper urls untouched
if (sass.substr(pos_quote, 4) != "url(")
{
// check if the url appears to be already quoted
if (sass.substr(pos_quote, 1) != "\"" && sass.substr(pos_quote, 1) != "\'")
{
// get position of the last char on the line
size_t pos_end = sass.find_last_not_of(SASS2SCSS_FIND_WHITESPACE);
// assertion check for valid result
if (pos_end != std::string::npos)
{
// add quotes around the full line after the import statement
sass = sass.substr(0, pos_quote) + "\"" + sass.substr(pos_quote, pos_end - pos_quote + 1) + "\"";
size_t pos = sass.find_first_not_of(SASS2SCSS_FIND_WHITESPACE, pos_import);
size_t start = pos;
bool in_dqstr = false;
bool in_sqstr = false;
bool is_escaped = false;
do {
if (is_escaped) {
is_escaped = false;
}
else if (sass[pos] == '\\') {
is_escaped = true;
}
else if (sass[pos] == '"') {
if (!in_sqstr) in_dqstr = ! in_dqstr;
}
else if (sass[pos] == '\'') {
if (!in_dqstr) in_sqstr = ! in_sqstr;
}
else if (in_dqstr || in_sqstr) {
// skip over quoted stuff
}
else if (sass[pos] == ',' || sass[pos] == 0) {
if (sass[start] != '"' && sass[start] != '\'' && !isUrl(sass, start)) {
size_t end = findLastCharacter(sass, pos - 1) + 1;
sass = sass.replace(end, 0, "\"");
sass = sass.replace(start, 0, "\"");
pos += 2;
}
start = findFirstCharacter(sass, pos + 1);
}
}
while (sass[pos++] != 0);
}
else if (
......
......@@ -74,14 +74,14 @@ namespace Sass {
// move line_beg pointer to line start
while (line_beg && *line_beg && lines != 0) {
if (*line_beg == '\n') --lines;
utf8::unchecked::next(line_beg);
utf8::unchecked::next(line_beg);
}
const char* line_end = line_beg;
// move line_end before next newline character
while (line_end && *line_end && *line_end != '\n') {
if (*line_end == '\n') break;
if (*line_end == '\r') break;
utf8::unchecked::next(line_end);
utf8::unchecked::next(line_end);
}
if (line_end && *line_end != 0) ++ line_end;
size_t line_len = line_end - line_beg;
......@@ -524,6 +524,7 @@ extern "C" {
options->c_headers = 0;
options->plugin_paths = 0;
options->include_paths = 0;
options->extensions = 0;
}
// helper function, not exported, only accessible locally
......@@ -558,6 +559,18 @@ extern "C" {
cur = next;
}
}
// Deallocate extension
if (options->extensions) {
struct string_list* cur;
struct string_list* next;
cur = options->extensions;
while (cur) {
next = cur->next;
free(cur->string);
free(cur);
cur = next;
}
}
// Free options strings
free(options->input_path);
free(options->output_path);
......@@ -577,6 +590,7 @@ extern "C" {
options->c_headers = 0;
options->plugin_paths = 0;
options->include_paths = 0;
options->extensions = 0;
}
// helper function, not exported, only accessible locally
......@@ -713,6 +727,22 @@ extern "C" {
IMPLEMENT_SASS_CONTEXT_TAKER(char*, source_map_string);
IMPLEMENT_SASS_CONTEXT_TAKER(char**, included_files);
// Push function for import extenions
void ADDCALL sass_option_push_import_extension(struct Sass_Options* options, const char* ext)
{
struct string_list* extension = (struct string_list*) calloc(1, sizeof(struct string_list));
if (extension == 0) return;
extension->string = ext ? sass_copy_c_string(ext) : 0;
struct string_list* last = options->extensions;
if (!options->extensions) {
options->extensions = extension;
} else {
while (last->next)
last = last->next;
last->next = extension;
}
}
// Push function for include paths (no manipulation support for now)
void ADDCALL sass_option_push_include_path(struct Sass_Options* options, const char* path)
{
......
......@@ -40,9 +40,12 @@ struct Sass_Options : Sass_Output_Options {
// Colon-separated list of paths
// Semicolon-separated on Windows
// Maybe use array interface instead?
char* extension;
char* include_path;
char* plugin_path;
// Extensions (linked string list)
struct string_list* extensions;
// Include paths (linked string list)
struct string_list* include_paths;
// Plugin paths (linked string list)
......@@ -126,4 +129,4 @@ struct Sass_Compiler {
Sass::Block_Obj root;
};
#endif
\ No newline at end of file
#endif
......@@ -12,11 +12,6 @@
namespace Sass {
#define out_of_memory() do { \
std::cerr << "Out of memory.\n"; \
exit(EXIT_FAILURE); \
} while (0)
double round(double val, size_t precision = 0);
double sass_strtod(const char* str);
const char* safe_str(const char *, const char* = "");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment