diff --git a/package.json b/package.json index afdba96e7..f64a62fa9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "node-sass", "version": "4.3.0", - "libsass": "3.4.3", + "libsass": "3.5.0.beta.2", "description": "Wrapper around libsass", "license": "MIT", "bugs": "https://github.com/sass/node-sass/issues", diff --git a/src/libsass.gyp b/src/libsass.gyp index b0764ab97..0fd857d81 100644 --- a/src/libsass.gyp +++ b/src/libsass.gyp @@ -12,6 +12,7 @@ ], 'sources': [ 'libsass/src/ast.cpp', + 'libsass/src/ast_fwd_decl.cpp', 'libsass/src/base64vlq.cpp', 'libsass/src/bind.cpp', 'libsass/src/cencode.c', diff --git a/src/libsass/.travis.yml b/src/libsass/.travis.yml index c36f15572..09ca55066 100755 --- a/src/libsass/.travis.yml +++ b/src/libsass/.travis.yml @@ -1,13 +1,6 @@ language: cpp sudo: false -os: - - linux - - osx - -compiler: - - gcc - - clang # don't create redundant code coverage reports # - AUTOTOOLS=yes COVERAGE=yes BUILD=static @@ -19,27 +12,53 @@ compiler: # this will still catch all coding errors! # - AUTOTOOLS=yes COVERAGE=no BUILD=static -env: - - AUTOTOOLS=no COVERAGE=no BUILD=shared - - AUTOTOOLS=no COVERAGE=yes BUILD=static - - AUTOTOOLS=yes COVERAGE=no BUILD=shared - # currenty there are various issues when # built with coverage, clang and autotools # - AUTOTOOLS=yes COVERAGE=yes BUILD=shared matrix: - exclude: - - compiler: clang - env: AUTOTOOLS=yes COVERAGE=yes BUILD=static + include : + - os: linux + compiler: gcc + env: AUTOTOOLS=no COVERAGE=yes BUILD=static - os: linux + compiler: g++-5 + env: AUTOTOOLS=yes COVERAGE=no BUILD=shared + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-5 + - os: linux + compiler: clang++-3.7 + env: AUTOTOOLS=no COVERAGE=yes BUILD=static + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.7 + packages: + - clang-3.7 + - os: linux + compiler: clang + env: AUTOTOOLS=yes COVERAGE=no BUILD=shared + - os: osx + compiler: clang env: AUTOTOOLS=no COVERAGE=no BUILD=shared - os: osx - compiler: gcc + compiler: clang + env: AUTOTOOLS=no COVERAGE=yes BUILD=static - os: osx - env: AUTOTOOLS=no BUILD=static + compiler: clang + env: AUTOTOOLS=yes COVERAGE=no BUILD=shared -script: ./script/ci-build-libsass +script: + - ./script/ci-build-libsass + - ./script/ci-build-plugin math + - ./script/ci-build-plugin glob + - ./script/ci-build-plugin digest + - ./script/ci-build-plugin tests before_install: ./script/ci-install-deps install: ./script/ci-install-compiler after_success: ./script/ci-report-coverage diff --git a/src/libsass/GNUmakefile.am b/src/libsass/GNUmakefile.am index d2bfdbfec..3dfc2b532 100755 --- a/src/libsass/GNUmakefile.am +++ b/src/libsass/GNUmakefile.am @@ -4,7 +4,7 @@ AM_COPT = -Wall -O2 AM_COVLDFLAGS = if ENABLE_COVERAGE - AM_COPT = -O0 --coverage + AM_COPT = -Wall -O1 -fno-omit-frame-pointer --coverage AM_COVLDFLAGS += -lgcov endif @@ -57,7 +57,7 @@ TESTS = \ $(SASS_SPEC_PATH)/spec/scss-tests \ $(SASS_SPEC_PATH)/spec/types -SASS_TEST_FLAGS = -V 3.4 --impl libsass +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 diff --git a/src/libsass/Makefile b/src/libsass/Makefile index abfe7efaf..7215a1dc4 100755 --- a/src/libsass/Makefile +++ b/src/libsass/Makefile @@ -15,10 +15,14 @@ INSTALL ?= install CFLAGS ?= -Wall CXXFLAGS ?= -Wall LDFLAGS ?= -Wall -ifneq "$(COVERAGE)" "yes" +ifeq "x$(COVERAGE)" "x" CFLAGS += -O2 CXXFLAGS += -O2 LDFLAGS += -O2 +else + CFLAGS += -O1 -fno-omit-frame-pointer + CXXFLAGS += -O1 -fno-omit-frame-pointer + LDFLAGS += -O1 -fno-omit-frame-pointer endif LDFLAGS += -Wl,-undefined,error CAT ?= $(if $(filter $(OS),Windows_NT),type,cat) @@ -305,16 +309,16 @@ version: $(SASSC_BIN) $(SASSC_BIN) -v test: $(SASSC_BIN) - $(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.4 -c $(SASSC_BIN) --impl libsass $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR) + $(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.5 -c $(SASSC_BIN) --impl libsass $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR) test_build: $(SASSC_BIN) - $(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.4 -c $(SASSC_BIN) --impl libsass $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR) + $(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.5 -c $(SASSC_BIN) --impl libsass $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR) test_full: $(SASSC_BIN) - $(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.4 -c $(SASSC_BIN) --impl libsass --run-todo $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR) + $(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.5 -c $(SASSC_BIN) --impl libsass --run-todo $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR) test_probe: $(SASSC_BIN) - $(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.4 -c $(SASSC_BIN) --impl libsass --probe-todo $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR) + $(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.5 -c $(SASSC_BIN) --impl libsass --probe-todo $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR) clean-objects: lib -$(RM) lib/*.a lib/*.so lib/*.dll lib/*.la diff --git a/src/libsass/Makefile.conf b/src/libsass/Makefile.conf index 6c15907b1..a8954edea 100755 --- a/src/libsass/Makefile.conf +++ b/src/libsass/Makefile.conf @@ -13,6 +13,7 @@ SOURCES = \ functions.cpp \ color_maps.cpp \ environment.cpp \ + ast_fwd_decl.cpp \ bind.cpp \ file.cpp \ util.cpp \ diff --git a/src/libsass/appveyor.yml b/src/libsass/appveyor.yml index e88cfcb81..767e6738a 100755 --- a/src/libsass/appveyor.yml +++ b/src/libsass/appveyor.yml @@ -65,7 +65,7 @@ test_script: } $env:TargetPath = Join-Path $pwd.Path $env:TargetPath If (Test-Path "$env:TargetPath") { - ruby sass-spec/sass-spec.rb -V 3.4 --probe-todo --impl libsass -c $env:TargetPath -s sass-spec/spec + ruby sass-spec/sass-spec.rb -V 3.5 --probe-todo --impl libsass -c $env:TargetPath -s sass-spec/spec if(-not($?)) { echo "sass-spec tests failed" exit 1 diff --git a/src/libsass/configure.ac b/src/libsass/configure.ac index 3a6ccc940..bf05dbfaa 100755 --- a/src/libsass/configure.ac +++ b/src/libsass/configure.ac @@ -121,8 +121,8 @@ if test "x$enable_cov" = "xyes"; then # Remove all optimization flags from C[XX]FLAGS changequote({,}) - CFLAGS=`echo "$CFLAGS" | $SED -e 's/-O[0-9]*//g'` - CXXFLAGS=`echo "$CXXFLAGS" | $SED -e 's/-O[0-9]*//g'` + CFLAGS=`echo "$CFLAGS -O1 -fno-omit-frame-pointer" | $SED -e 's/-O[0-9]*//g'` + CXXFLAGS=`echo "$CXXFLAGS -O1 -fno-omit-frame-pointer" | $SED -e 's/-O[0-9]*//g'` changequote([,]) AC_SUBST(GCOV) diff --git a/src/libsass/docs/api-context-internal.md b/src/libsass/docs/api-context-internal.md index 94fd62804..1a2818b34 100755 --- a/src/libsass/docs/api-context-internal.md +++ b/src/libsass/docs/api-context-internal.md @@ -7,26 +7,35 @@ enum Sass_Input_Style { SASS_CONTEXT_FOLDER }; -// simple linked list -struct string_list { - string_list* next; - char* string; -}; - // sass config options structure -struct Sass_Options { - - // Precision for fractional numbers - int precision; +struct Sass_Inspect_Options { // Output style for the generated css code // A value from above SASS_STYLE_* constants enum Sass_Output_Style output_style; + // Precision for fractional numbers + int precision; + +}; + +// sass config options structure +struct Sass_Output_Options : Sass_Inspect_Options { + + // String to be used for indentation + const char* indent; + // String to be used to for line feeds + const char* linefeed; + // Emit comments in the generated CSS indicating // the corresponding source line. bool source_comments; +}; + +// sass config options structure +struct Sass_Options : Sass_Output_Options { + // embed sourceMappingUrl as data uri bool source_map_embed; @@ -56,15 +65,9 @@ struct Sass_Options { // information in source-maps etc. char* output_path; - // String to be used for indentation - const char* indent; - // String to be used to for line feeds - const char* linefeed; - // Colon-separated list of paths // Semicolon-separated on Windows - // Note: It may be better to use - // array interface instead + // Maybe use array interface instead? char* include_path; char* plugin_path; @@ -82,10 +85,13 @@ struct Sass_Options { char* source_map_root; // Custom functions that can be called from sccs code - Sass_C_Function_List c_functions; + Sass_Function_List c_functions; // Callback to overload imports - Sass_C_Import_Callback importer; + Sass_Importer_List c_importers; + + // List of custom headers + Sass_Importer_List c_headers; }; @@ -111,6 +117,7 @@ struct Sass_Context : Sass_Options char* error_file; size_t error_line; size_t error_column; + const char* error_src; // report imported files char** included_files; @@ -130,6 +137,7 @@ struct Sass_Data_Context : Sass_Context { // provided source string char* source_string; + char* srcmap_string; }; @@ -147,9 +155,9 @@ struct Sass_Compiler { // original c context Sass_Context* c_ctx; // Sass::Context - void* cpp_ctx; + Sass::Context* cpp_ctx; // Sass::Block - void* root; + Sass::Block_Obj root; }; ``` diff --git a/src/libsass/docs/api-context.md b/src/libsass/docs/api-context.md index b023d4e00..dfd10c181 100755 --- a/src/libsass/docs/api-context.md +++ b/src/libsass/docs/api-context.md @@ -207,6 +207,15 @@ size_t sass_context_get_error_column (struct Sass_Context* ctx); const char* sass_context_get_source_map_string (struct Sass_Context* ctx); char** sass_context_get_included_files (struct Sass_Context* ctx); +// Getters for Sass_Compiler options (query import stack) +size_t sass_compiler_get_import_stack_size(struct Sass_Compiler* compiler); +Sass_Import_Entry sass_compiler_get_last_import(struct Sass_Compiler* compiler); +Sass_Import_Entry sass_compiler_get_import_entry(struct Sass_Compiler* compiler, size_t idx); +// Getters for Sass_Compiler options (query function stack) +size_t sass_compiler_get_callee_stack_size(struct Sass_Compiler* compiler); +Sass_Callee_Entry sass_compiler_get_last_callee(struct Sass_Compiler* compiler); +Sass_Callee_Entry sass_compiler_get_callee_entry(struct Sass_Compiler* compiler, size_t idx); + // Take ownership of memory (value on context is set to 0) char* sass_context_take_error_json (struct Sass_Context* ctx); char* sass_context_take_error_text (struct Sass_Context* ctx); @@ -214,10 +223,6 @@ char* sass_context_take_error_message (struct Sass_Context* ctx); char* sass_context_take_error_file (struct Sass_Context* ctx); char* sass_context_take_output_string (struct Sass_Context* ctx); char* sass_context_take_source_map_string (struct Sass_Context* ctx); - -// Push function for plugin/include paths (no manipulation support for now) -void sass_option_push_plugin_path (struct Sass_Options* options, const char* path); -void sass_option_push_include_path (struct Sass_Options* options, const char* path); ``` ### Sass Options API @@ -236,13 +241,18 @@ const char* sass_option_get_indent (struct Sass_Options* options); const char* sass_option_get_linefeed (struct Sass_Options* options); const char* sass_option_get_input_path (struct Sass_Options* options); const char* sass_option_get_output_path (struct Sass_Options* options); -const char* sass_option_get_plugin_path (struct Sass_Options* options); -const char* sass_option_get_include_path (struct Sass_Options* options); const char* sass_option_get_source_map_file (struct Sass_Options* options); const char* sass_option_get_source_map_root (struct Sass_Options* options); Sass_C_Function_List sass_option_get_c_functions (struct Sass_Options* options); Sass_C_Import_Callback sass_option_get_importer (struct Sass_Options* options); +// Getters for Context_Option include path array +size_t sass_option_get_include_path_size(struct Sass_Options* options); +const char* sass_option_get_include_path(struct Sass_Options* options, size_t i); +// Plugin paths to load dynamic libraries work the same +size_t sass_option_get_plugin_path_size(struct Sass_Options* options); +const char* sass_option_get_plugin_path(struct Sass_Options* options, size_t i); + // Setters for Context_Option values void sass_option_set_precision (struct Sass_Options* options, int precision); void sass_option_set_output_style (struct Sass_Options* options, enum Sass_Output_Style output_style); @@ -266,6 +276,16 @@ void sass_option_set_importer (struct Sass_Options* options, Sass_C_Import_Callb // Push function for paths (no manipulation support for now) void sass_option_push_plugin_path (struct Sass_Options* options, const char* path); void sass_option_push_include_path (struct Sass_Options* options, const char* path); + +// Resolve a file via the given include paths in the sass option struct +// find_file looks for the exact file name while find_include does a regular sass include +char* sass_find_file (const char* path, struct Sass_Options* opt); +char* sass_find_include (const char* path, struct Sass_Options* opt); + +// Resolve a file relative to last import or include paths in the sass option struct +// find_file looks for the exact file name while find_include does a regular sass include +char* sass_compiler_find_file (const char* path, struct Sass_Compiler* compiler); +char* sass_compiler_find_include (const char* path, struct Sass_Compiler* compiler); ``` ### More links diff --git a/src/libsass/docs/api-doc.md b/src/libsass/docs/api-doc.md index b1393e07f..58e427eeb 100755 --- a/src/libsass/docs/api-doc.md +++ b/src/libsass/docs/api-doc.md @@ -1,6 +1,9 @@ ## Introduction -LibSass wouldn't be much good without a way to interface with it. These interface documentations describe the various functions and data structures available to implementers. They are split up over three major components, which have all their own source files (plus some common functionality). +LibSass wouldn't be much good without a way to interface with it. These +interface documentations describe the various functions and data structures +available to implementers. They are split up over three major components, which +have all their own source files (plus some common functionality). - [Sass Context](api-context.md) - Trigger and handle the main Sass compilation - [Sass Value](api-value.md) - Exchange values and its format with LibSass @@ -41,7 +44,12 @@ gcc -Wall version.c -lsass -o version && ./version ## Compiling your code -The most important is your sass file (or string of sass code). With this, you will want to start a LibSass compiler. Here is some pseudocode describing the process. The compiler has two different modes: direct input as a string with `Sass_Data_Context` or LibSass will do file reading for you by using `Sass_File_Context`. See the code for a list of options available [Sass_Options](https://github.com/sass/libsass/blob/36feef0/include/sass/interface.h#L18) +The most important is your sass file (or string of sass code). With this, you +will want to start a LibSass compiler. Here is some pseudocode describing the +process. The compiler has two different modes: direct input as a string with +`Sass_Data_Context` or LibSass will do file reading for you by using +`Sass_File_Context`. See the code for a list of options available +[Sass_Options](https://github.com/sass/libsass/blob/36feef0/include/sass/interface.h#L18) **Building a file compiler** @@ -97,7 +105,9 @@ struct Sass_Data_context : Sass_Context; This mirrors very well how `libsass` uses these structures. -- `Sass_Options` holds everything you feed in before the compilation. It also hosts `input_path` and `output_path` options, because they are used to generate/calculate relative links in source-maps. The `input_path` is shared with `Sass_File_Context`. +- `Sass_Options` holds everything you feed in before the compilation. It also hosts +`input_path` and `output_path` options, because they are used to generate/calculate +relative links in source-maps. The `input_path` is shared with `Sass_File_Context`. - `Sass_Context` holds all the data returned by the compilation step. - `Sass_File_Context` is a specific implementation that requires no additional fields - `Sass_Data_Context` is a specific implementation that adds the `input_source` field @@ -106,8 +116,11 @@ Structs can be down-casted to access `context` or `options`! ## Memory handling and life-cycles -We keep memory around for as long as the main [context](api-context.md) object is not destroyed (`sass_delete_context`). LibSass will create copies of most inputs/options beside the main sass code. -You need to allocate and fill that buffer before passing it to LibSass. You may also overtake memory management from libsass for certain return values (i.e. `sass_context_take_output_string`). +We keep memory around for as long as the main [context](api-context.md) object +is not destroyed (`sass_delete_context`). LibSass will create copies of most +inputs/options beside the main sass code. You need to allocate and fill that +buffer before passing it to LibSass. You may also overtake memory management +from libsass for certain return values (i.e. `sass_context_take_output_string`). ```C // to allocate buffer to be filled @@ -125,9 +138,6 @@ void sass_free_memory(void* ptr); char* sass_string_unquote (const char* str); char* sass_string_quote (const char* str, const char quote_mark); -// Resolve a file via the given include paths in the include char* array -char* sass_resolve_file (const char* path, const char* incs[]); - // Get compiled libsass version const char* libsass_version(void); @@ -140,15 +150,25 @@ const char* libsass_language_version(void); **input_path** -The `input_path` is part of `Sass_Options`, but it also is the main option for `Sass_File_Context`. It is also used to generate relative file links in source-maps. Therefore it is pretty usefull to pass this information if you have a `Sass_Data_Context` and know the original path. +The `input_path` is part of `Sass_Options`, but it also is the main option for +`Sass_File_Context`. It is also used to generate relative file links in source- +maps. Therefore it is pretty usefull to pass this information if you have a +`Sass_Data_Context` and know the original path. **output_path** -Be aware that `libsass` does not write the output file itself. This option merely exists to give `libsass` the proper information to generate links in source-maps. The file has to be written to the disk by the binding/implementation. If the `output_path` is omitted, `libsass` tries to extrapolate one from the `input_path` by replacing (or adding) the file ending with `.css`. +Be aware that `libsass` does not write the output file itself. This option +merely exists to give `libsass` the proper information to generate links in +source-maps. The file has to be written to the disk by the +binding/implementation. If the `output_path` is omitted, `libsass` tries to +extrapolate one from the `input_path` by replacing (or adding) the file ending +with `.css`. ## Error Codes -The `error_code` is integer value which indicates the type of error that occurred inside the LibSass process. Following is the list of error codes along with the short description: +The `error_code` is integer value which indicates the type of error that +occurred inside the LibSass process. Following is the list of error codes along +with the short description: * 1: normal errors like parsing or `eval` errors * 2: bad allocation error (memory error) @@ -156,11 +176,15 @@ The `error_code` is integer value which indicates the type of error that occurre * 4: legacy string exceptions ( `throw const char*` or `std::string` ) * 5: Some other unknown exception -Although for the API consumer, error codes do not offer much value except indicating whether *any* error occurred during the compilation, it helps debugging the LibSass internal code paths. +Although for the API consumer, error codes do not offer much value except +indicating whether *any* error occurred during the compilation, it helps +debugging the LibSass internal code paths. ## Real-World Implementations -The proof is in the pudding, so we have highlighted a few implementations that should be on par with the latest LibSass interface version. Some of them may not have all features implemented! +The proof is in the pudding, so we have highlighted a few implementations that +should be on par with the latest LibSass interface version. Some of them may not +have all features implemented! 1. [Perl Example](https://github.com/sass/perl-libsass/blob/master/lib/CSS/Sass.xs) 2. [Go Example](http://godoc.org/github.com/wellington/go-libsass#example-Context-Compile) @@ -168,11 +192,20 @@ The proof is in the pudding, so we have highlighted a few implementations that s ## ABI forward compatibility -We use a functional API to make dynamic linking more robust and future compatible. The API is not yet 100% stable, so we do not yet guarantee [ABI](https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html) forward compatibility. We will do so, once we increase the shared library version above 1.0. +We use a functional API to make dynamic linking more robust and future +compatible. The API is not yet 100% stable, so we do not yet guarantee +[ABI](https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html) forward +compatibility. ## Plugins (experimental) -LibSass can load plugins from directories. Just define `plugin_path` on context options to load all plugins from the given directories. To implement plugins, please consult the [[Wiki-Page for plugins|API-Plugins]]. +LibSass can load plugins from directories. Just define `plugin_path` on context +options to load all plugins from the directories. To implement plugins, please +consult the following example implementations. + +- https://github.com/mgreter/libsass-glob +- https://github.com/mgreter/libsass-math +- https://github.com/mgreter/libsass-digest ## Internal Structs diff --git a/src/libsass/docs/api-function-example.md b/src/libsass/docs/api-function-example.md index 0e41940ce..38608e1a2 100755 --- a/src/libsass/docs/api-function-example.md +++ b/src/libsass/docs/api-function-example.md @@ -11,7 +11,7 @@ union Sass_Value* call_fn_foo(const union Sass_Value* s_args, Sass_Function_Entr struct Sass_Context* ctx = sass_compiler_get_context(comp); struct Sass_Options* opts = sass_compiler_get_options(comp); // get information about previous importer entry from the stack - struct Sass_Import* import = sass_compiler_get_last_import(comp); + Sass_Import_Entry import = sass_compiler_get_last_import(comp); const char* prev_abs_path = sass_import_get_abs_path(import); const char* prev_imp_path = sass_import_get_imp_path(import); // get the cookie from function descriptor diff --git a/src/libsass/docs/api-function.md b/src/libsass/docs/api-function.md index eeaa61a1d..8d9d97ca4 100755 --- a/src/libsass/docs/api-function.md +++ b/src/libsass/docs/api-function.md @@ -30,17 +30,41 @@ typedef union Sass_Value* (*Sass_Function_Fn) (const union Sass_Value*, Sass_Function_Entry cb, struct Sass_Compiler* compiler); // Creators for sass function list and function descriptors -ADDAPI Sass_Function_List ADDCALL sass_make_function_list (size_t length); -ADDAPI Sass_Function_Entry ADDCALL sass_make_function (const char* signature, Sass_Function_Fn cb, void* cookie); +Sass_Function_List sass_make_function_list (size_t length); +Sass_Function_Entry sass_make_function (const char* signature, Sass_Function_Fn cb, void* cookie); +// In case you need to free them yourself +void sass_delete_function (Sass_Function_Entry entry); +void sass_delete_function_list (Sass_Function_List list); // Setters and getters for callbacks on function lists -ADDAPI Sass_Function_Entry ADDCALL sass_function_get_list_entry(Sass_Function_List list, size_t pos); -ADDAPI void ADDCALL sass_function_set_list_entry(Sass_Function_List list, size_t pos, Sass_Function_Entry cb); +Sass_Function_Entry sass_function_get_list_entry(Sass_Function_List list, size_t pos); +void sass_function_set_list_entry(Sass_Function_List list, size_t pos, Sass_Function_Entry cb); + +// Setters to insert an entry into the import list (you may also use [] access directly) +// Since we are dealing with pointers they should have a guaranteed and fixed size +void sass_import_set_list_entry (Sass_Import_List list, size_t idx, Sass_Import_Entry entry); +Sass_Import_Entry sass_import_get_list_entry (Sass_Import_List list, size_t idx); // Getters for custom function descriptors -ADDAPI const char* ADDCALL sass_function_get_signature (Sass_Function_Entry cb); -ADDAPI Sass_Function_Fn ADDCALL sass_function_get_function (Sass_Function_Entry cb); -ADDAPI void* ADDCALL sass_function_get_cookie (Sass_Function_Entry cb); +const char* sass_function_get_signature (Sass_Function_Entry cb); +Sass_Function_Fn sass_function_get_function (Sass_Function_Entry cb); +void* sass_function_get_cookie (Sass_Function_Entry cb); + +// Getters for callee entry +const char* sass_callee_get_name (Sass_Callee_Entry); +const char* sass_callee_get_path (Sass_Callee_Entry); +size_t sass_callee_get_line (Sass_Callee_Entry); +size_t sass_callee_get_column (Sass_Callee_Entry); +enum Sass_Callee_Type sass_callee_get_type (Sass_Callee_Entry); +Sass_Env_Frame sass_callee_get_env (Sass_Callee_Entry); + +// Getters and Setters for environments (lexical, local and global) +union Sass_Value* sass_env_get_lexical (Sass_Env_Frame, const char*); +void sass_env_set_lexical (Sass_Env_Frame, const char*, union Sass_Value*); +union Sass_Value* sass_env_get_local (Sass_Env_Frame, const char*); +void sass_env_set_local (Sass_Env_Frame, const char*, union Sass_Value*); +union Sass_Value* sass_env_get_global (Sass_Env_Frame, const char*); +void sass_env_set_global (Sass_Env_Frame, const char*, union Sass_Value*); ``` ### More links diff --git a/src/libsass/docs/api-importer.md b/src/libsass/docs/api-importer.md index 08ef6cd2e..b6265002e 100755 --- a/src/libsass/docs/api-importer.md +++ b/src/libsass/docs/api-importer.md @@ -5,7 +5,7 @@ By using custom importers, Sass stylesheets can be implemented in any possible w You actually have to return a list of imports, since some importers may want to import multiple files from one import statement (ie. a glob/star importer). The memory you pass with source and srcmap is taken over by LibSass and freed automatically when the import is done. You are also allowed to return `0` instead of a list, which will tell LibSass to handle the import by itself (as if no custom importer was in use). ```C -struct Sass_Import** rv = sass_make_import_list(1); +Sass_Import_Entry* rv = sass_make_import_list(1); rv[0] = sass_make_import(rel, abs, source, srcmap); ``` @@ -31,7 +31,7 @@ struct Sass_C_Import_Descriptor; // Typedef defining the custom importer callback typedef struct Sass_C_Import_Descriptor (*Sass_C_Import_Callback); // Typedef defining the importer c function prototype -typedef struct Sass_Import** (*Sass_C_Import_Fn) (const char* url, const char* prev, void* cookie); +typedef Sass_Import_Entry* (*Sass_C_Import_Fn) (const char* url, const char* prev, void* cookie); // Creators for custom importer callback (with some additional pointer) // The pointer is mostly used to store the callback into the actual function @@ -45,38 +45,38 @@ void* sass_import_get_cookie (Sass_C_Import_Callback fn); void sass_delete_importer (Sass_C_Import_Callback fn); // Creator for sass custom importer return argument list -struct Sass_Import** sass_make_import_list (size_t length); +Sass_Import_Entry* sass_make_import_list (size_t length); // Creator for a single import entry returned by the custom importer inside the list -struct Sass_Import* sass_make_import_entry (const char* path, char* source, char* srcmap); -struct Sass_Import* sass_make_import (const char* rel, const char* abs, char* source, char* srcmap); +Sass_Import_Entry sass_make_import_entry (const char* path, char* source, char* srcmap); +Sass_Import_Entry sass_make_import (const char* rel, const char* abs, char* source, char* srcmap); // set error message to abort import and to print out a message (path from existing object is used in output) -struct Sass_Import* sass_import_set_error(struct Sass_Import* import, const char* message, size_t line, size_t col); +Sass_Import_Entry sass_import_set_error(Sass_Import_Entry import, const char* message, size_t line, size_t col); // Setters to insert an entry into the import list (you may also use [] access directly) // Since we are dealing with pointers they should have a guaranteed and fixed size -void sass_import_set_list_entry (struct Sass_Import** list, size_t idx, struct Sass_Import* entry); -struct Sass_Import* sass_import_get_list_entry (struct Sass_Import** list, size_t idx); +void sass_import_set_list_entry (Sass_Import_Entry* list, size_t idx, Sass_Import_Entry entry); +Sass_Import_Entry sass_import_get_list_entry (Sass_Import_Entry* list, size_t idx); // Getters for import entry -const char* sass_import_get_rel_path (struct Sass_Import*); -const char* sass_import_get_abs_path (struct Sass_Import*); -const char* sass_import_get_source (struct Sass_Import*); -const char* sass_import_get_srcmap (struct Sass_Import*); +const char* sass_import_get_imp_path (Sass_Import_Entry); +const char* sass_import_get_abs_path (Sass_Import_Entry); +const char* sass_import_get_source (Sass_Import_Entry); +const char* sass_import_get_srcmap (Sass_Import_Entry); // Explicit functions to take ownership of these items // The property on our struct will be reset to NULL -char* sass_import_take_source (struct Sass_Import*); -char* sass_import_take_srcmap (struct Sass_Import*); +char* sass_import_take_source (Sass_Import_Entry); +char* sass_import_take_srcmap (Sass_Import_Entry); // Getters for import error entries -size_t sass_import_get_error_line (struct Sass_Import*); -size_t sass_import_get_error_column (struct Sass_Import*); -const char* sass_import_get_error_message (struct Sass_Import*); +size_t sass_import_get_error_line (Sass_Import_Entry); +size_t sass_import_get_error_column (Sass_Import_Entry); +const char* sass_import_get_error_message (Sass_Import_Entry); // Deallocator for associated memory (incl. entries) -void sass_delete_import_list (struct Sass_Import**); +void sass_delete_import_list (Sass_Import_Entry*); // Just in case we have some stray import structs -void sass_delete_import (struct Sass_Import*); +void sass_delete_import (Sass_Import_Entry); ``` ### More links diff --git a/src/libsass/docs/api-value.md b/src/libsass/docs/api-value.md index ddf016c17..9ac60f2d1 100755 --- a/src/libsass/docs/api-value.md +++ b/src/libsass/docs/api-value.md @@ -58,7 +58,7 @@ union Sass_Value* sass_make_string (const char* val); union Sass_Value* sass_make_qstring (const char* val); union Sass_Value* sass_make_number (double val, const char* unit); union Sass_Value* sass_make_color (double r, double g, double b, double a); -union Sass_Value* sass_make_list (size_t len, enum Sass_Separator sep); +union Sass_Value* sass_make_list (size_t len, enum Sass_Separator sep, bool is_bracketed); union Sass_Value* sass_make_map (size_t len); union Sass_Value* sass_make_error (const char* msg); union Sass_Value* sass_make_warning (const char* msg); @@ -124,6 +124,8 @@ size_t sass_list_get_length (const union Sass_Value* v); // Getters and setters for Sass_List enum Sass_Separator sass_list_get_separator (const union Sass_Value* v); void sass_list_set_separator (union Sass_Value* v, enum Sass_Separator value); +bool sass_list_get_is_bracketed (const union Sass_Value* v); +void sass_list_set_is_bracketed (union Sass_Value* v, bool value); // Getters and setters for Sass_List values union Sass_Value* sass_list_get_value (const union Sass_Value* v, size_t i); void sass_list_set_value (union Sass_Value* v, size_t i, union Sass_Value* value); diff --git a/src/libsass/docs/build-on-windows.md b/src/libsass/docs/build-on-windows.md index 7c095fad0..4639d4928 100755 --- a/src/libsass/docs/build-on-windows.md +++ b/src/libsass/docs/build-on-windows.md @@ -130,7 +130,7 @@ cd libsass REM set PATH=%PATH%;%PROGRAMFILES%\MSBuild\12.0\Bin msbuild /m:4 /p:Configuration=Release win\libsass.sln REM running the spec test-suite manually (needs ruby and minitest gem) -ruby sass-spec\sass-spec.rb -V 3.4 -c win\bin\sassc.exe -s --impl libsass sass-spec/spec +ruby sass-spec\sass-spec.rb -V 3.5 -c win\bin\sassc.exe -s --impl libsass sass-spec/spec cd .. ``` diff --git a/src/libsass/docs/custom-functions-internal.md b/src/libsass/docs/custom-functions-internal.md index 1c19965c6..57fec82b8 100755 --- a/src/libsass/docs/custom-functions-internal.md +++ b/src/libsass/docs/custom-functions-internal.md @@ -45,14 +45,16 @@ The cookie can hold any pointer you want. In the `perl-libsass` implementation i ```C // allocate memory (copies passed strings) -union Sass_Value* make_sass_boolean (int val); -union Sass_Value* make_sass_number (double val, const char* unit); -union Sass_Value* make_sass_color (double r, double g, double b, double a); -union Sass_Value* make_sass_string (const char* val); -union Sass_Value* make_sass_list (size_t len, enum Sass_Separator sep); -union Sass_Value* make_sass_map (size_t len); -union Sass_Value* make_sass_null (); -union Sass_Value* make_sass_error (const char* msg); +union Sass_Value* sass_make_null (void); +union Sass_Value* sass_make_boolean (bool val); +union Sass_Value* sass_make_string (const char* val); +union Sass_Value* sass_make_qstring (const char* val); +union Sass_Value* sass_make_number (double val, const char* unit); +union Sass_Value* sass_make_color (double r, double g, double b, double a); +union Sass_Value* sass_make_list (size_t len, enum Sass_Separator sep, bool is_bracketed); +union Sass_Value* sass_make_map (size_t len); +union Sass_Value* sass_make_error (const char* msg); +union Sass_Value* sass_make_warning (const char* msg); // Make a deep cloned copy of the given sass value union Sass_Value* sass_clone_value (const union Sass_Value* val); diff --git a/src/libsass/include/sass/base.h b/src/libsass/include/sass/base.h index d88af927f..88dd8d303 100755 --- a/src/libsass/include/sass/base.h +++ b/src/libsass/include/sass/base.h @@ -75,9 +75,6 @@ ADDAPI void ADDCALL sass_free_memory(void* ptr); ADDAPI char* ADDCALL sass_string_quote (const char* str, const char quote_mark); ADDAPI char* ADDCALL sass_string_unquote (const char* str); -// Resolve a file via the given include paths in the include char* array -ADDAPI char* ADDCALL sass_resolve_file (const char* path, const char* incs[]); - // Implemented sass language version // Hardcoded version 3.4 for time being ADDAPI const char* ADDCALL libsass_version(void); diff --git a/src/libsass/include/sass/context.h b/src/libsass/include/sass/context.h index 0a913c02d..2f88d6888 100755 --- a/src/libsass/include/sass/context.h +++ b/src/libsass/include/sass/context.h @@ -81,8 +81,6 @@ ADDAPI const char* ADDCALL sass_option_get_indent (struct Sass_Options* options) ADDAPI const char* ADDCALL sass_option_get_linefeed (struct Sass_Options* options); ADDAPI const char* ADDCALL sass_option_get_input_path (struct Sass_Options* options); ADDAPI const char* ADDCALL sass_option_get_output_path (struct Sass_Options* options); -ADDAPI const char* ADDCALL sass_option_get_plugin_path (struct Sass_Options* options); -ADDAPI const char* ADDCALL sass_option_get_include_path (struct Sass_Options* options); ADDAPI const char* ADDCALL sass_option_get_source_map_file (struct Sass_Options* options); ADDAPI const char* ADDCALL sass_option_get_source_map_root (struct Sass_Options* options); ADDAPI Sass_Importer_List ADDCALL sass_option_get_c_headers (struct Sass_Options* options); @@ -124,6 +122,10 @@ ADDAPI size_t ADDCALL sass_context_get_error_column (struct Sass_Context* ctx); ADDAPI const char* ADDCALL sass_context_get_source_map_string (struct Sass_Context* ctx); ADDAPI char** ADDCALL sass_context_get_included_files (struct Sass_Context* ctx); +// Getters for options include path array +ADDAPI size_t ADDCALL sass_option_get_include_path_size(struct Sass_Options* options); +ADDAPI const char* ADDCALL sass_option_get_include_path(struct Sass_Options* options, size_t i); + // Calculate the size of the stored null terminated array ADDAPI size_t ADDCALL sass_context_get_included_files_size (struct Sass_Context* ctx); @@ -143,11 +145,24 @@ ADDAPI struct Sass_Options* ADDCALL sass_compiler_get_options(struct Sass_Compil ADDAPI size_t ADDCALL sass_compiler_get_import_stack_size(struct Sass_Compiler* compiler); ADDAPI Sass_Import_Entry ADDCALL sass_compiler_get_last_import(struct Sass_Compiler* compiler); ADDAPI Sass_Import_Entry ADDCALL sass_compiler_get_import_entry(struct Sass_Compiler* compiler, size_t idx); +ADDAPI size_t ADDCALL sass_compiler_get_callee_stack_size(struct Sass_Compiler* 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 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); +// Resolve a file via the given include paths in the sass option struct +// find_file looks for the exact file name while find_include does a regular sass include +ADDAPI char* ADDCALL sass_find_file (const char* path, struct Sass_Options* opt); +ADDAPI char* ADDCALL sass_find_include (const char* path, struct Sass_Options* opt); + +// Resolve a file relative to last import or include paths in the sass option struct +// find_file looks for the exact file name while find_include does a regular sass include +ADDAPI char* ADDCALL sass_compiler_find_file (const char* path, struct Sass_Compiler* compiler); +ADDAPI char* ADDCALL sass_compiler_find_include (const char* path, struct Sass_Compiler* compiler); + #ifdef __cplusplus } // __cplusplus defined. #endif diff --git a/src/libsass/include/sass/functions.h b/src/libsass/include/sass/functions.h index 2eeb39c4c..ac47e8ede 100755 --- a/src/libsass/include/sass/functions.h +++ b/src/libsass/include/sass/functions.h @@ -11,12 +11,18 @@ extern "C" { // Forward declaration +struct Sass_Env; +struct Sass_Callee; struct Sass_Import; struct Sass_Options; struct Sass_Compiler; struct Sass_Importer; struct Sass_Function; +// Typedef helpers for callee lists +typedef struct Sass_Env (*Sass_Env_Frame); +// Typedef helpers for callee lists +typedef struct Sass_Callee (*Sass_Callee_Entry); // Typedef helpers for import lists typedef struct Sass_Import (*Sass_Import_Entry); typedef struct Sass_Import* (*Sass_Import_List); @@ -34,11 +40,18 @@ typedef struct Sass_Function* (*Sass_Function_List); typedef union Sass_Value* (*Sass_Function_Fn) (const union Sass_Value*, Sass_Function_Entry cb, struct Sass_Compiler* compiler); +// Type of function calls +enum Sass_Callee_Type { + SASS_CALLEE_MIXIN, + SASS_CALLEE_FUNCTION, + SASS_CALLEE_C_FUNCTION, +}; // Creator for sass custom importer return argument list ADDAPI Sass_Importer_List ADDCALL sass_make_importer_list (size_t length); ADDAPI Sass_Importer_Entry ADDCALL sass_importer_get_list_entry (Sass_Importer_List list, size_t idx); ADDAPI void ADDCALL sass_importer_set_list_entry (Sass_Importer_List list, size_t idx, Sass_Importer_Entry entry); +ADDAPI void ADDCALL sass_delete_importer_list (Sass_Importer_List list); // Creators for custom importer callback (with some additional pointer) @@ -66,6 +79,22 @@ ADDAPI Sass_Import_Entry ADDCALL sass_import_set_error(Sass_Import_Entry import, ADDAPI void ADDCALL sass_import_set_list_entry (Sass_Import_List list, size_t idx, Sass_Import_Entry entry); ADDAPI Sass_Import_Entry ADDCALL sass_import_get_list_entry (Sass_Import_List list, size_t idx); +// Getters for callee entry +ADDAPI const char* ADDCALL sass_callee_get_name (Sass_Callee_Entry); +ADDAPI const char* ADDCALL sass_callee_get_path (Sass_Callee_Entry); +ADDAPI size_t ADDCALL sass_callee_get_line (Sass_Callee_Entry); +ADDAPI size_t ADDCALL sass_callee_get_column (Sass_Callee_Entry); +ADDAPI enum Sass_Callee_Type ADDCALL sass_callee_get_type (Sass_Callee_Entry); +ADDAPI Sass_Env_Frame ADDCALL sass_callee_get_env (Sass_Callee_Entry); + +// Getters and Setters for environments (lexical, local and global) +ADDAPI union Sass_Value* ADDCALL sass_env_get_lexical (Sass_Env_Frame, const char*); +ADDAPI void ADDCALL sass_env_set_lexical (Sass_Env_Frame, const char*, union Sass_Value*); +ADDAPI union Sass_Value* ADDCALL sass_env_get_local (Sass_Env_Frame, const char*); +ADDAPI void ADDCALL sass_env_set_local (Sass_Env_Frame, const char*, union Sass_Value*); +ADDAPI union Sass_Value* ADDCALL sass_env_get_global (Sass_Env_Frame, const char*); +ADDAPI void ADDCALL sass_env_set_global (Sass_Env_Frame, const char*, union Sass_Value*); + // Getters for import entry ADDAPI const char* ADDCALL sass_import_get_imp_path (Sass_Import_Entry); ADDAPI const char* ADDCALL sass_import_get_abs_path (Sass_Import_Entry); @@ -90,6 +119,8 @@ ADDAPI void ADDCALL sass_delete_import (Sass_Import_Entry); // Creators for sass function list and function descriptors ADDAPI Sass_Function_List ADDCALL sass_make_function_list (size_t length); ADDAPI Sass_Function_Entry ADDCALL sass_make_function (const char* signature, Sass_Function_Fn cb, void* cookie); +ADDAPI void ADDCALL sass_delete_function (Sass_Function_Entry entry); +ADDAPI void ADDCALL sass_delete_function_list (Sass_Function_List list); // Setters and getters for callbacks on function lists ADDAPI Sass_Function_Entry ADDCALL sass_function_get_list_entry(Sass_Function_List list, size_t pos); diff --git a/src/libsass/include/sass/values.h b/src/libsass/include/sass/values.h index c00d091ec..9832038b7 100755 --- a/src/libsass/include/sass/values.h +++ b/src/libsass/include/sass/values.h @@ -50,7 +50,7 @@ ADDAPI union Sass_Value* ADDCALL sass_make_string (const char* val); ADDAPI union Sass_Value* ADDCALL sass_make_qstring (const char* val); ADDAPI union Sass_Value* ADDCALL sass_make_number (double val, const char* unit); ADDAPI union Sass_Value* ADDCALL sass_make_color (double r, double g, double b, double a); -ADDAPI union Sass_Value* ADDCALL sass_make_list (size_t len, enum Sass_Separator sep); +ADDAPI union Sass_Value* ADDCALL sass_make_list (size_t len, enum Sass_Separator sep, bool is_bracketed); ADDAPI union Sass_Value* ADDCALL sass_make_map (size_t len); ADDAPI union Sass_Value* ADDCALL sass_make_error (const char* msg); ADDAPI union Sass_Value* ADDCALL sass_make_warning (const char* msg); @@ -116,6 +116,8 @@ ADDAPI size_t ADDCALL sass_list_get_length (const union Sass_Value* v); // Getters and setters for Sass_List ADDAPI enum Sass_Separator ADDCALL sass_list_get_separator (const union Sass_Value* v); ADDAPI void ADDCALL sass_list_set_separator (union Sass_Value* v, enum Sass_Separator value); +ADDAPI bool ADDCALL sass_list_get_is_bracketed (const union Sass_Value* v); +ADDAPI void ADDCALL sass_list_set_is_bracketed (union Sass_Value* v, bool value); // Getters and setters for Sass_List values ADDAPI union Sass_Value* ADDCALL sass_list_get_value (const union Sass_Value* v, size_t i); ADDAPI void ADDCALL sass_list_set_value (union Sass_Value* v, size_t i, union Sass_Value* value); diff --git a/src/libsass/include/sass/version.h b/src/libsass/include/sass/version.h index 3047c3953..56ea016a2 100755 --- a/src/libsass/include/sass/version.h +++ b/src/libsass/include/sass/version.h @@ -6,7 +6,7 @@ #endif #ifndef LIBSASS_LANGUAGE_VERSION -#define LIBSASS_LANGUAGE_VERSION "3.4" +#define LIBSASS_LANGUAGE_VERSION "3.5" #endif #endif diff --git a/src/libsass/include/sass/version.h.in b/src/libsass/include/sass/version.h.in index 197468b6f..b8d4072d4 100755 --- a/src/libsass/include/sass/version.h.in +++ b/src/libsass/include/sass/version.h.in @@ -6,7 +6,7 @@ #endif #ifndef LIBSASS_LANGUAGE_VERSION -#define LIBSASS_LANGUAGE_VERSION "3.4" +#define LIBSASS_LANGUAGE_VERSION "3.5" #endif #endif diff --git a/src/libsass/script/ci-build-libsass b/src/libsass/script/ci-build-libsass index e2e5b2d2c..a5085fec6 100755 --- a/src/libsass/script/ci-build-libsass +++ b/src/libsass/script/ci-build-libsass @@ -18,9 +18,14 @@ if [ "x$TRAVIS_OS_NAME" == "x" ]; then export TRAVIS_OS_NAME=`uname -s | perl -n if [ "x$COVERAGE" == "xyes" ]; then COVERAGE_OPT="--enable-coverage" - export EXTRA_CFLAGS="--coverage" - export EXTRA_CXXFLAGS="--coverage" - export EXTRA_LDFLAGS="--coverage" + export EXTRA_CFLAGS="-fprofile-arcs -ftest-coverage" + export EXTRA_CXXFLAGS="-fprofile-arcs -ftest-coverage" + if [ "$TRAVIS_OS_NAME" == "osx" ]; then + # osx doesn't seem to know gcov lib? + export EXTRA_LDFLAGS="--coverage" + else + export EXTRA_LDFLAGS="-lgcov --coverage" + fi else COVERAGE_OPT="--disable-coverage" fi @@ -37,7 +42,7 @@ fi if [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then MAKE_OPTS="$MAKE_OPTS -j1 V=1" else - MAKE_OPTS="$MAKE_OPTS -j3 V=1" + MAKE_OPTS="$MAKE_OPTS -j5 V=1" fi if [ "x$PREFIX" == "x" ]; then diff --git a/src/libsass/script/ci-build-plugin b/src/libsass/script/ci-build-plugin new file mode 100755 index 000000000..3660c6224 --- /dev/null +++ b/src/libsass/script/ci-build-plugin @@ -0,0 +1,62 @@ +#!/bin/bash + +PLUGIN=$1 +RUBY_BIN=ruby +SASS_SPEC_PATH=sass-spec +SASSC_BIN=sassc/bin/sassc +SASS_SPEC_SPEC_DIR=plugins/libsass-${PLUGIN}/test + +if [ -e ./tester ] ; then + SASSC_BIN=./tester +fi + +if [ -d ./build/lib ] ; then + cp -a build/lib lib +fi + +if [ "x$1" == "x" ] ; then + echo "No plugin name given" + exit 1 +fi + +if [ "x$COVERAGE" == "0" ] ; then + unset COVERAGE +fi + +export EXTRA_CFLAGS="" +export EXTRA_CXXFLAGS="" +if [ "$TRAVIS_OS_NAME" == "osx" ]; then + # osx doesn't seem to know gcov lib? + export EXTRA_LDFLAGS="--coverage" +else + export EXTRA_LDFLAGS="-lgcov --coverage" +fi + +mkdir -p plugins +if [ ! -d plugins/libsass-${PLUGIN} ] ; then + git clone https://github.com/mgreter/libsass-${PLUGIN} plugins/libsass-${PLUGIN} +fi +if [ ! -d plugins/libsass-${PLUGIN}/build ] ; then + mkdir plugins/libsass-${PLUGIN}/build +fi +RETVAL=$?; if [ "$RETVAL" != "0" ]; then exit $RETVAL; fi + +cd plugins/libsass-${PLUGIN}/build +cmake -G "Unix Makefiles" -D LIBSASS_DIR="../../.." .. +RETVAL=$?; if [ "$RETVAL" != "0" ]; then exit $RETVAL; fi +make VERBOSE=1 -j2 +RETVAL=$?; if [ "$RETVAL" != "0" ]; then exit $RETVAL; fi +cd ../../.. + +# glob only works on paths relative to imports +if [ "x$PLUGIN" == "xglob" ]; then + ${SASSC_BIN} --plugin-path plugins/libsass-${PLUGIN}/build ${SASS_SPEC_SPEC_DIR}/basic/input.scss > ${SASS_SPEC_SPEC_DIR}/basic/result.css + ${SASSC_BIN} --plugin-path plugins/libsass-${PLUGIN}/build ${SASS_SPEC_SPEC_DIR}/basic/input.scss --sourcemap > /dev/null +else + cat ${SASS_SPEC_SPEC_DIR}/basic/input.scss | ${SASSC_BIN} --plugin-path plugins/libsass-${PLUGIN}/build -I ${SASS_SPEC_SPEC_DIR}/basic > ${SASS_SPEC_SPEC_DIR}/basic/result.css + cat ${SASS_SPEC_SPEC_DIR}/basic/input.scss | ${SASSC_BIN} --plugin-path plugins/libsass-${PLUGIN}/build -I ${SASS_SPEC_SPEC_DIR}/basic --sourcemap > /dev/null +fi +RETVAL=$?; if [ "$RETVAL" != "0" ]; then exit $RETVAL; fi + +diff ${SASS_SPEC_SPEC_DIR}/basic/expected_output.css ${SASS_SPEC_SPEC_DIR}/basic/result.css +RETVAL=$?; if [ "$RETVAL" != "0" ]; then exit $RETVAL; fi diff --git a/src/libsass/script/ci-report-coverage b/src/libsass/script/ci-report-coverage index 4e4c99f03..495cb05cb 100755 --- a/src/libsass/script/ci-report-coverage +++ b/src/libsass/script/ci-report-coverage @@ -2,6 +2,12 @@ if [ "x$COVERAGE" = "xyes" ]; then + # find / -name "gcovr" + # find / -name "coveralls" + # this is only needed for mac os x builds! + PATH=$PATH:/Users/travis/Library/Python/2.7/bin/ + + # exclude some directories from profiling (.libs is from autotools) export EXCLUDE_COVERAGE="--exclude plugins --exclude sassc/sassc.c @@ -21,10 +27,14 @@ if [ "x$COVERAGE" = "xyes" ]; then --exclude src/test --exclude src/posix --exclude src/debugger.hpp" - # debug via gcovr - gcov -v + # debug used gcov version + # option not available on mac + if [ "$TRAVIS_OS_NAME" != "osx" ]; then + gcov -v + fi + # create summarized report gcovr -r . - # generate and submit report to coveralls.io + # submit report to coveralls.io coveralls $EXCLUDE_COVERAGE --gcov-options '\-lp' else diff --git a/src/libsass/src/GNUmakefile.am b/src/libsass/src/GNUmakefile.am index c4c5e08cb..fee9312f9 100755 --- a/src/libsass/src/GNUmakefile.am +++ b/src/libsass/src/GNUmakefile.am @@ -34,7 +34,7 @@ include $(top_srcdir)/Makefile.conf libsass_la_SOURCES = ${CSOURCES} ${SOURCES} -libsass_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 0:9:0 +libsass_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 1:0:0 if ENABLE_TESTS if ENABLE_COVERAGE diff --git a/src/libsass/src/ast.cpp b/src/libsass/src/ast.cpp index 726f0103c..d8c67e339 100755 --- a/src/libsass/src/ast.cpp +++ b/src/libsass/src/ast.cpp @@ -2,6 +2,7 @@ #include "ast.hpp" #include "context.hpp" #include "node.hpp" +#include "eval.hpp" #include "extend.hpp" #include "emitter.hpp" #include "color_maps.hpp" @@ -19,79 +20,33 @@ namespace Sass { static Null sass_null(ParserState("null")); bool Supports_Operator::needs_parens(Supports_Condition_Obj cond) const { - if (Supports_Operator_Obj op = SASS_MEMORY_CAST(Supports_Operator, cond)) { + if (Supports_Operator_Obj op = Cast(cond)) { return op->operand() != operand(); } - return SASS_MEMORY_CAST(Supports_Negation, cond) != NULL; + return Cast(cond) != NULL; } bool Supports_Negation::needs_parens(Supports_Condition_Obj cond) const { - return SASS_MEMORY_CAST(Supports_Negation, cond) || - SASS_MEMORY_CAST(Supports_Operator, cond); + return Cast(cond) || + Cast(cond); } - size_t HashExpression::operator() (Expression_Obj ex) const { - return ex ? ex->hash() : 0; - } - - size_t HashSimpleSelector::operator() (Simple_Selector_Obj ex) const { - return ex ? ex->hash() : 0; - } - - - bool CompareExpression::operator()(const Expression_Obj& lhs, const Expression_Obj& rhs) const { - return lhs && rhs && lhs->eq(*rhs); - } - - bool CompareSimpleSelector::operator()(Simple_Selector_Obj lhs, Simple_Selector_Obj rhs) const { - return &lhs && &rhs && *lhs == *rhs; - } - - std::string & str_ltrim(std::string & str) - { - auto it2 = std::find_if( str.begin() , str.end() , [](char ch){ return !std::isspace(ch , std::locale::classic() ) ; } ); - str.erase( str.begin() , it2); - return str; - } - - std::string & str_rtrim(std::string & str) + void str_rtrim(std::string& str, const std::string& delimiters = " \f\n\r\t\v") { - auto it1 = std::find_if( str.rbegin() , str.rend() , [](char ch){ return !std::isspace(ch , std::locale::classic() ) ; } ); - str.erase( it1.base() , str.end() ); - return str; + str.erase( str.find_last_not_of( delimiters ) + 1 ); } void String_Constant::rtrim() { - value_ = str_rtrim(value_); - } - void String_Constant::ltrim() - { - value_ = str_ltrim(value_); - } - void String_Constant::trim() - { - rtrim(); - ltrim(); + str_rtrim(value_); } void String_Schema::rtrim() { if (!empty()) { - if (String_Ptr str = SASS_MEMORY_CAST(String, last())) str->rtrim(); - } - } - void String_Schema::ltrim() - { - if (!empty()) { - if (String_Ptr str = SASS_MEMORY_CAST(String, first())) str->ltrim(); + if (String_Ptr str = Cast(last())) str->rtrim(); } } - void String_Schema::trim() - { - rtrim(); - ltrim(); - } void Argument::set_delayed(bool delayed) { @@ -111,7 +66,7 @@ namespace Sass { bool At_Root_Query::exclude(std::string str) { bool with = feature() && unquote(feature()->to_string()).compare("with") == 0; - List_Ptr l = static_cast(&value()); + List_Ptr l = static_cast(value().ptr()); std::string v; if (with) @@ -141,21 +96,20 @@ namespace Sass { pstate_.offset += pstate - pstate_ + pstate.offset; } - void AST_Node::set_pstate_offset(const Offset& offset) - { - pstate_.offset = offset; - } - - inline bool is_ns_eq(const std::string& l, const std::string& r) + bool Simple_Selector::is_ns_eq(const Simple_Selector& r) const { - if (l.empty() && r.empty()) return true; - else if (l.empty() && r == "*") return true; - else if (r.empty() && l == "*") return true; - else return l == r; + // https://github.com/sass/sass/issues/2229 + if ((has_ns_ == r.has_ns_) || + (has_ns_ && ns_.empty()) || + (r.has_ns_ && r.ns_.empty()) + ) { + if (ns_.empty() && r.ns() == "*") return false; + else if (r.ns().empty() && ns() == "*") return false; + else return ns() == r.ns(); + } + return false; } - - bool Compound_Selector::operator< (const Compound_Selector& rhs) const { size_t L = std::min(length(), rhs.length()); @@ -173,7 +127,7 @@ namespace Sass { return length() < rhs.length(); } - bool Compound_Selector::has_parent_ref() + bool Compound_Selector::has_parent_ref() const { for (Simple_Selector_Obj s : *this) { if (s && s->has_parent_ref()) return true; @@ -181,7 +135,7 @@ namespace Sass { return false; } - bool Compound_Selector::has_real_parent_ref() + bool Compound_Selector::has_real_parent_ref() const { for (Simple_Selector_Obj s : *this) { if (s && s->has_real_parent_ref()) return true; @@ -189,13 +143,13 @@ namespace Sass { return false; } - bool Complex_Selector::has_parent_ref() + bool Complex_Selector::has_parent_ref() const { return (head() && head()->has_parent_ref()) || (tail() && tail()->has_parent_ref()); } - bool Complex_Selector::has_real_parent_ref() + bool Complex_Selector::has_real_parent_ref() const { return (head() && head()->has_real_parent_ref()) || (tail() && tail()->has_real_parent_ref()); @@ -206,25 +160,31 @@ namespace Sass { // const iterators for tails Complex_Selector_Ptr_Const l = this; Complex_Selector_Ptr_Const r = &rhs; - Compound_Selector_Ptr l_h = l ? &l->head() : 0; - Compound_Selector_Ptr r_h = r ? &r->head() : 0; + Compound_Selector_Ptr l_h = NULL; + Compound_Selector_Ptr r_h = NULL; + if (l) l_h = l->head(); + if (r) r_h = r->head(); // process all tails while (true) { + #ifdef DEBUG // skip empty ancestor first if (l && l->is_empty_ancestor()) { - l = &l->tail(); - l_h = l ? &l->head() : 0; + l_h = NULL; + l = l->tail(); + if(l) l_h = l->head(); continue; } // skip empty ancestor first if (r && r->is_empty_ancestor()) { - r = &r->tail(); - r_h = r ? &r->head() : 0; + r_h = NULL; + r = r->tail(); + if (r) r_h = r->head(); continue; } + #endif // check for valid selectors if (!l) return !!r; if (!r) return false; @@ -235,11 +195,12 @@ namespace Sass { if (l->combinator() != r->combinator()) { return l->combinator() < r->combinator(); } // advance to next tails - l = &l->tail(); - r = &r->tail(); + l = l->tail(); + r = r->tail(); // fetch the next headers - l_h = l ? &l->head() : 0; - r_h = r ? &r->head() : 0; + l_h = NULL; r_h = NULL; + if (l) l_h = l->head(); + if (r) r_h = r->head(); } // one side is null else if (!r_h) return true; @@ -251,11 +212,12 @@ namespace Sass { if (l->combinator() != r->combinator()) { return l->combinator() < r->combinator(); } // advance to next tails - l = &l->tail(); - r = &r->tail(); + l = l->tail(); + r = r->tail(); // fetch the next headers - l_h = l ? &l->head() : 0; - r_h = r ? &r->head() : 0; + l_h = NULL; r_h = NULL; + if (l) l_h = l->head(); + if (r) r_h = r->head(); } // heads are not equal else return *l_h < *r_h; @@ -268,25 +230,31 @@ namespace Sass { // const iterators for tails Complex_Selector_Ptr_Const l = this; Complex_Selector_Ptr_Const r = &rhs; - Compound_Selector_Ptr l_h = l ? &l->head() : 0; - Compound_Selector_Ptr r_h = r ? &r->head() : 0; + Compound_Selector_Ptr l_h = NULL; + Compound_Selector_Ptr r_h = NULL; + if (l) l_h = l->head(); + if (r) r_h = r->head(); // process all tails while (true) { + #ifdef DEBUG // skip empty ancestor first if (l && l->is_empty_ancestor()) { - l = &l->tail(); - l_h = l ? &l->head() : 0; + l_h = NULL; + l = l->tail(); + if (l) l_h = l->head(); continue; } // skip empty ancestor first if (r && r->is_empty_ancestor()) { - r = &r->tail(); - r_h = r ? &r->head() : 0; + r_h = NULL; + r = r->tail(); + if (r) r_h = r->head(); continue; } + #endif // check the pointers if (!r) return !l; if (!l) return !r; @@ -297,11 +265,12 @@ namespace Sass { if (l->combinator() != r->combinator()) { return l->combinator() < r->combinator(); } // advance to next tails - l = &l->tail(); - r = &r->tail(); + l = l->tail(); + r = r->tail(); // fetch the next heads - l_h = l ? &l->head() : 0; - r_h = r ? &r->head() : 0; + l_h = NULL; r_h = NULL; + if (l) l_h = l->head(); + if (r) r_h = r->head(); } // equals if other head is empty else if ((!l_h && !r_h) || @@ -313,11 +282,12 @@ namespace Sass { if (l->combinator() != r->combinator()) { return l->combinator() == r->combinator(); } // advance to next tails - l = &l->tail(); - r = &r->tail(); + l = l->tail(); + r = r->tail(); // fetch the next heads - l_h = l ? &l->head() : 0; - r_h = r ? &r->head() : 0; + l_h = NULL; r_h = NULL; + if (l) l_h = l->head(); + if (r) r_h = r->head(); } // abort else break; @@ -333,71 +303,102 @@ namespace Sass { for (size_t i = 0, L = length(); i < L; ++i) { if (unified.isNull()) break; - unified = at(i)->unify_with(&unified, ctx); + unified = at(i)->unify_with(unified, ctx); } return unified.detach(); } - bool Selector::operator== (const Selector& rhs) const + bool Complex_Selector::operator== (const Selector& rhs) const + { + if (const Selector_List* sl = Cast(&rhs)) return *this == *sl; + if (const Simple_Selector* sp = Cast(&rhs)) return *this == *sp; + if (const Complex_Selector* cs = Cast(&rhs)) return *this == *cs; + if (const Compound_Selector* ch = Cast(&rhs)) return *this == *ch; + throw std::runtime_error("invalid selector base classes to compare"); + return false; + } + + + bool Complex_Selector::operator< (const Selector& rhs) const + { + if (const Selector_List* sl = Cast(&rhs)) return *this < *sl; + if (const Simple_Selector* sp = Cast(&rhs)) return *this < *sp; + if (const Complex_Selector* cs = Cast(&rhs)) return *this < *cs; + if (const Compound_Selector* ch = Cast(&rhs)) return *this < *ch; + throw std::runtime_error("invalid selector base classes to compare"); + return false; + } + + bool Compound_Selector::operator== (const Selector& rhs) const { - if (Selector_List_Ptr_Const sl = dynamic_cast(this)) return *sl == rhs; - if (Simple_Selector_Ptr_Const sp = dynamic_cast(this)) return *sp == rhs; + if (const Selector_List* sl = Cast(&rhs)) return *this == *sl; + if (const Simple_Selector* sp = Cast(&rhs)) return *this == *sp; + if (const Complex_Selector* cs = Cast(&rhs)) return *this == *cs; + if (const Compound_Selector* ch = Cast(&rhs)) return *this == *ch; throw std::runtime_error("invalid selector base classes to compare"); return false; } - bool Selector::operator< (const Selector& rhs) const + bool Compound_Selector::operator< (const Selector& rhs) const { - if (Selector_List_Ptr_Const sl = dynamic_cast(this)) return *sl < rhs; - if (Simple_Selector_Ptr_Const sp = dynamic_cast(this)) return *sp < rhs; + if (const Selector_List* sl = Cast(&rhs)) return *this < *sl; + if (const Simple_Selector* sp = Cast(&rhs)) return *this < *sp; + if (const Complex_Selector* cs = Cast(&rhs)) return *this < *cs; + if (const Compound_Selector* ch = Cast(&rhs)) return *this < *ch; + throw std::runtime_error("invalid selector base classes to compare"); + return false; + } + + bool Selector_Schema::operator== (const Selector& rhs) const + { + if (const Selector_List* sl = Cast(&rhs)) return *this == *sl; + if (const Simple_Selector* sp = Cast(&rhs)) return *this == *sp; + if (const Complex_Selector* cs = Cast(&rhs)) return *this == *cs; + if (const Compound_Selector* ch = Cast(&rhs)) return *this == *ch; + throw std::runtime_error("invalid selector base classes to compare"); + return false; + } + + bool Selector_Schema::operator< (const Selector& rhs) const + { + if (const Selector_List* sl = Cast(&rhs)) return *this < *sl; + if (const Simple_Selector* sp = Cast(&rhs)) return *this < *sp; + if (const Complex_Selector* cs = Cast(&rhs)) return *this < *cs; + if (const Compound_Selector* ch = Cast(&rhs)) return *this < *ch; throw std::runtime_error("invalid selector base classes to compare"); return false; } bool Simple_Selector::operator== (const Selector& rhs) const { - if (Simple_Selector_Ptr_Const sp = dynamic_cast(&rhs)) return *this == *sp; + if (Simple_Selector_Ptr_Const sp = Cast(&rhs)) return *this == *sp; return false; } bool Simple_Selector::operator< (const Selector& rhs) const { - if (Simple_Selector_Ptr_Const sp = dynamic_cast(&rhs)) return *this < *sp; + if (Simple_Selector_Ptr_Const sp = Cast(&rhs)) return *this < *sp; return false; } bool Simple_Selector::operator== (const Simple_Selector& rhs) const { - Simple_Type type = simple_type(); - // dynamic cast is a bottleneck - use concrete type as types are final - if (type == PSEUDO_SEL /* Pseudo_Selector_Ptr_Const lp = dynamic_cast(this) */) { - return *static_cast(this) == rhs; - } - else if (type == WRAPPED_SEL /* Wrapped_Selector_Ptr_Const lw = dynamic_cast(this) */) { - return *static_cast(this) == rhs; - } - else if (type == ATTR_SEL /* Attribute_Selector_Ptr_Const la = dynamic_cast(this) */) { - return *static_cast(this) == rhs; - } + // solve the double dispatch problem by using RTTI information via dynamic cast + if (const Pseudo_Selector* lhs = Cast(this)) {return *lhs == rhs; } + else if (const Wrapped_Selector* lhs = Cast(this)) {return *lhs == rhs; } + else if (const Attribute_Selector* lhs = Cast(this)) {return *lhs == rhs; } else if (name_ == rhs.name_) - { return is_ns_eq(ns_, rhs.ns_); } + { return is_ns_eq(rhs); } else return false; } bool Simple_Selector::operator< (const Simple_Selector& rhs) const { - Simple_Type type = simple_type(); - // dynamic cast is a bottleneck - use concrete type as types are final - if (type == PSEUDO_SEL /* Pseudo_Selector_Ptr_Const lp = dynamic_cast(this) */) { - return *static_cast(this) < rhs; - } - else if (type == WRAPPED_SEL /* Wrapped_Selector_Ptr_Const lw = dynamic_cast(this) */) { - return *static_cast(this) < rhs; - } - else if (type == ATTR_SEL /* Attribute_Selector_Ptr_Const la = dynamic_cast(this) */) { - return *static_cast(this) < rhs; - } - if (is_ns_eq(ns_, rhs.ns_)) + // solve the double dispatch problem by using RTTI information via dynamic cast + if (const Pseudo_Selector* lhs = Cast(this)) {return *lhs < rhs; } + else if (const Wrapped_Selector* lhs = Cast(this)) {return *lhs < rhs; } + else if (const Attribute_Selector* lhs = Cast(this)) {return *lhs < rhs; } + if (is_ns_eq(rhs)) { return name_ < rhs.name_; } return ns_ < rhs.ns_; } @@ -405,9 +406,9 @@ namespace Sass { bool Selector_List::operator== (const Selector& rhs) const { // solve the double dispatch problem by using RTTI information via dynamic cast - if (Selector_List_Ptr_Const ls = dynamic_cast(&rhs)) { return *this == *ls; } - else if (Complex_Selector_Ptr_Const ls = dynamic_cast(&rhs)) { return *this == *ls; } - else if (Compound_Selector_Ptr_Const ls = dynamic_cast(&rhs)) { return *this == *ls; } + if (Selector_List_Ptr_Const ls = Cast(&rhs)) { return *this == *ls; } + else if (Complex_Selector_Ptr_Const ls = Cast(&rhs)) { return *this == *ls; } + else if (Compound_Selector_Ptr_Const ls = Cast(&rhs)) { return *this == *ls; } // no compare method return this == &rhs; } @@ -416,8 +417,8 @@ namespace Sass { bool Selector_List::operator==(const Expression& rhs) const { // solve the double dispatch problem by using RTTI information via dynamic cast - if (List_Ptr_Const ls = dynamic_cast(&rhs)) { return *this == *ls; } - if (Selector_Ptr_Const ls = dynamic_cast(&rhs)) { return *this == *ls; } + if (List_Ptr_Const ls = Cast(&rhs)) { return *this == *ls; } + if (Selector_Ptr_Const ls = Cast(&rhs)) { return *this == *ls; } // compare invalid (maybe we should error?) return false; } @@ -431,8 +432,8 @@ namespace Sass { // create temporary vectors and sort them std::vector l_lst = this->elements(); std::vector r_lst = rhs.elements(); - std::sort(l_lst.begin(), l_lst.end(), cmp_complex_selector()); - std::sort(r_lst.begin(), r_lst.end(), cmp_complex_selector()); + std::sort(l_lst.begin(), l_lst.end(), OrderNodes()); + std::sort(r_lst.begin(), r_lst.end(), OrderNodes()); // process loop while (true) { @@ -457,17 +458,18 @@ namespace Sass { bool Selector_List::operator< (const Selector& rhs) const { - if (Selector_List_Ptr_Const sp = dynamic_cast(&rhs)) return *this < *sp; + if (Selector_List_Ptr_Const sp = Cast(&rhs)) return *this < *sp; return false; } bool Selector_List::operator< (const Selector_List& rhs) const { - if (this->length() != rhs.length()) return false; - for (size_t i = 0; i < rhs.length(); i ++) { - if (!(*at(i) < *rhs.at(i))) return false; + size_t l = rhs.length(); + if (length() < l) l = length(); + for (size_t i = 0; i < l; i ++) { + if (*at(i) < *rhs.at(i)) return true; } - return true; + return false; } Compound_Selector_Ptr Simple_Selector::unify_with(Compound_Selector_Ptr rhs, Context& ctx) @@ -482,7 +484,7 @@ namespace Sass { { for (i = 0, L = rhs->length(); i < L; ++i) { - if ((SASS_MEMORY_CAST(Pseudo_Selector, (*rhs)[i]) || SASS_MEMORY_CAST(Wrapped_Selector, (*rhs)[i])) && (*rhs)[L-1]->is_pseudo_element()) + if ((Cast((*rhs)[i]) || Cast((*rhs)[i])) && (*rhs)[L-1]->is_pseudo_element()) { found = true; break; } } } @@ -490,7 +492,7 @@ namespace Sass { { for (i = 0, L = rhs->length(); i < L; ++i) { - if (SASS_MEMORY_CAST(Pseudo_Selector, (*rhs)[i]) || SASS_MEMORY_CAST(Wrapped_Selector, (*rhs)[i])) + if (Cast((*rhs)[i]) || Cast((*rhs)[i])) { found = true; break; } } } @@ -544,18 +546,18 @@ namespace Sass { return rhs; } - Simple_Selector_Ptr rhs_0 = &rhs->at(0); + Simple_Selector_Ptr rhs_0 = rhs->at(0); // otherwise, this is a tag name if (name() == "*") { if (typeid(*rhs_0) == typeid(Element_Selector)) { // if rhs is universal, just return this tagname + rhs's qualifiers - Element_Selector_Ptr ts = SASS_MEMORY_CAST_PTR(Element_Selector, rhs_0); + Element_Selector_Ptr ts = Cast(rhs_0); rhs->at(0) = this->unify_with(ts, ctx); return rhs; } - else if (SASS_MEMORY_CAST_PTR(Class_Selector, rhs_0) || SASS_MEMORY_CAST_PTR(Id_Selector, rhs_0)) { + else if (Cast(rhs_0) || Cast(rhs_0)) { // qualifier is `.class`, so we can prefix with `ns|*.class` if (has_ns() && !rhs_0->has_ns()) { if (ns() != "*") rhs->elements().insert(rhs->begin(), this); @@ -591,7 +593,7 @@ namespace Sass { { for (size_t i = 0, L = rhs->length(); i < L; ++i) { - if (Id_Selector_Ptr sel = SASS_MEMORY_CAST(Id_Selector, rhs->at(i))) { + if (Id_Selector_Ptr sel = Cast(rhs->at(i))) { if (sel->name() != name()) return 0; } } @@ -605,7 +607,7 @@ namespace Sass { { for (size_t i = 0, L = rhs->length(); i < L; ++i) { - if (Pseudo_Selector_Ptr sel = SASS_MEMORY_CAST(Pseudo_Selector, rhs->at(i))) { + if (Pseudo_Selector_Ptr sel = Cast(rhs->at(i))) { if (sel->is_pseudo_element() && sel->name() != name()) return 0; } } @@ -615,30 +617,27 @@ namespace Sass { bool Attribute_Selector::operator< (const Attribute_Selector& rhs) const { - if (is_ns_eq(ns(), rhs.ns())) { + if (is_ns_eq(rhs)) { if (name() == rhs.name()) { if (matcher() == rhs.matcher()) { bool no_lhs_val = value().isNull(); bool no_rhs_val = rhs.value().isNull(); - if (no_lhs_val && no_rhs_val) { - return true; - } - if (!no_lhs_val && !no_rhs_val) { - return *value() < *rhs.value(); - } + if (no_lhs_val && no_rhs_val) return false; // equal + else if (no_lhs_val) return true; // lhs is null + else if (no_rhs_val) return false; // rhs is null + return *value() < *rhs.value(); // both are given } else { return matcher() < rhs.matcher(); } } else { return name() < rhs.name(); } - } - return false; + } else { return ns() < rhs.ns(); } } bool Attribute_Selector::operator< (const Simple_Selector& rhs) const { - if (Attribute_Selector_Ptr_Const w = dynamic_cast(&rhs)) + if (Attribute_Selector_Ptr_Const w = Cast(&rhs)) { return *this < *w; } - if (is_ns_eq(ns(), rhs.ns())) + if (is_ns_eq(rhs)) { return name() < rhs.name(); } return ns() < rhs.ns(); } @@ -652,13 +651,13 @@ namespace Sass { if (no_lhs_val && no_rhs_val) { return (name() == rhs.name()) && (matcher() == rhs.matcher()) - && (is_ns_eq(ns(), rhs.ns())); + && (is_ns_eq(rhs)); } // both are defined, evaluate if (no_lhs_val == no_rhs_val) { return (name() == rhs.name()) && (matcher() == rhs.matcher()) - && (is_ns_eq(ns(), rhs.ns())) + && (is_ns_eq(rhs)) && (*value() == *rhs.value()); } // not equal @@ -668,97 +667,94 @@ namespace Sass { bool Attribute_Selector::operator== (const Simple_Selector& rhs) const { - if (Attribute_Selector_Ptr_Const w = dynamic_cast(&rhs)) + if (Attribute_Selector_Ptr_Const w = Cast(&rhs)) { return *this == *w; } - if (is_ns_eq(ns(), rhs.ns())) - { return name() == rhs.name(); } - return ns() == rhs.ns(); + return is_ns_eq(rhs) && + name() == rhs.name(); } bool Pseudo_Selector::operator== (const Pseudo_Selector& rhs) const { - if (is_ns_eq(ns(), rhs.ns()) && name() == rhs.name()) + if (is_ns_eq(rhs) && name() == rhs.name()) { String_Obj lhs_ex = expression(); String_Obj rhs_ex = rhs.expression(); if (rhs_ex && lhs_ex) return *lhs_ex == *rhs_ex; - else return lhs_ex == rhs_ex; + else return lhs_ex.ptr() == rhs_ex.ptr(); } else return false; } bool Pseudo_Selector::operator== (const Simple_Selector& rhs) const { - if (Pseudo_Selector_Ptr_Const w = dynamic_cast(&rhs)) + if (Pseudo_Selector_Ptr_Const w = Cast(&rhs)) { return *this == *w; } - if (is_ns_eq(ns(), rhs.ns())) - { return name() == rhs.name(); } - return ns() == rhs.ns(); + return is_ns_eq(rhs) && + name() == rhs.name(); } bool Pseudo_Selector::operator< (const Pseudo_Selector& rhs) const { - if (is_ns_eq(ns(), rhs.ns()) && name() == rhs.name()) + if (is_ns_eq(rhs) && name() == rhs.name()) { String_Obj lhs_ex = expression(); String_Obj rhs_ex = rhs.expression(); if (rhs_ex && lhs_ex) return *lhs_ex < *rhs_ex; - else return lhs_ex < rhs_ex; + else return lhs_ex.ptr() < rhs_ex.ptr(); } - if (is_ns_eq(ns(), rhs.ns())) + if (is_ns_eq(rhs)) { return name() < rhs.name(); } return ns() < rhs.ns(); } bool Pseudo_Selector::operator< (const Simple_Selector& rhs) const { - if (Pseudo_Selector_Ptr_Const w = dynamic_cast(&rhs)) + if (Pseudo_Selector_Ptr_Const w = Cast(&rhs)) { return *this < *w; } - if (is_ns_eq(ns(), rhs.ns())) + if (is_ns_eq(rhs)) { return name() < rhs.name(); } return ns() < rhs.ns(); } bool Wrapped_Selector::operator== (const Wrapped_Selector& rhs) const { - if (is_ns_eq(ns(), rhs.ns()) && name() == rhs.name()) + if (is_ns_eq(rhs) && name() == rhs.name()) { return *(selector()) == *(rhs.selector()); } else return false; } bool Wrapped_Selector::operator== (const Simple_Selector& rhs) const { - if (Wrapped_Selector_Ptr_Const w = dynamic_cast(&rhs)) + if (Wrapped_Selector_Ptr_Const w = Cast(&rhs)) { return *this == *w; } - if (is_ns_eq(ns(), rhs.ns())) - { return name() == rhs.name(); } - return ns() == rhs.ns(); + return is_ns_eq(rhs) && + name() == rhs.name(); } bool Wrapped_Selector::operator< (const Wrapped_Selector& rhs) const { - if (is_ns_eq(ns(), rhs.ns()) && name() == rhs.name()) + if (is_ns_eq(rhs) && name() == rhs.name()) { return *(selector()) < *(rhs.selector()); } - if (is_ns_eq(ns(), rhs.ns())) + if (is_ns_eq(rhs)) { return name() < rhs.name(); } return ns() < rhs.ns(); } bool Wrapped_Selector::operator< (const Simple_Selector& rhs) const { - if (Wrapped_Selector_Ptr_Const w = dynamic_cast(&rhs)) + if (Wrapped_Selector_Ptr_Const w = Cast(&rhs)) { return *this < *w; } - if (is_ns_eq(ns(), rhs.ns())) + if (is_ns_eq(rhs)) { return name() < rhs.name(); } return ns() < rhs.ns(); } @@ -767,28 +763,26 @@ namespace Sass { { if (this->name() != sub->name()) return false; if (this->name() == ":current") return false; - if (Selector_List_Obj rhs_list = SASS_MEMORY_CAST(Selector_List, sub->selector())) { - if (Selector_List_Obj lhs_list = SASS_MEMORY_CAST(Selector_List, selector())) { + if (Selector_List_Obj rhs_list = Cast(sub->selector())) { + if (Selector_List_Obj lhs_list = Cast(selector())) { return lhs_list->is_superselector_of(rhs_list); } - error("is_superselector expected a Selector_List", sub->pstate()); - } else { - error("is_superselector expected a Selector_List", sub->pstate()); } + error("is_superselector expected a Selector_List", sub->pstate()); return false; } bool Compound_Selector::is_superselector_of(Selector_List_Obj rhs, std::string wrapped) { for (Complex_Selector_Obj item : rhs->elements()) { - if (is_superselector_of(&item, wrapped)) return true; + if (is_superselector_of(item, wrapped)) return true; } return false; } bool Compound_Selector::is_superselector_of(Complex_Selector_Obj rhs, std::string wrapped) { - if (rhs->head()) return is_superselector_of(&rhs->head(), wrapped); + if (rhs->head()) return is_superselector_of(rhs->head(), wrapped); return false; } @@ -821,6 +815,9 @@ namespace Sass { return false; } + // would like to replace this without stringification + // https://github.com/sass/sass/issues/2229 + // SimpleSelectorSet lset, rset; std::set lset, rset; if (lbase && rbase) @@ -837,11 +834,11 @@ namespace Sass { for (size_t i = 0, iL = length(); i < iL; ++i) { - Selector_Obj lhs = &(*this)[i]; + Selector_Obj lhs = (*this)[i]; // very special case for wrapped matches selector - if (Wrapped_Selector_Obj wrapped = SASS_MEMORY_CAST(Wrapped_Selector, lhs)) { + if (Wrapped_Selector_Obj wrapped = Cast(lhs)) { if (wrapped->name() == ":not") { - if (Selector_List_Obj not_list = SASS_MEMORY_CAST(Selector_List, wrapped->selector())) { + if (Selector_List_Obj not_list = Cast(wrapped->selector())) { if (not_list->is_superselector_of(rhs, wrapped->name())) return false; } else { throw std::runtime_error("wrapped not selector is not a list"); @@ -849,8 +846,8 @@ namespace Sass { } if (wrapped->name() == ":matches" || wrapped->name() == ":-moz-any") { lhs = wrapped->selector(); - if (Selector_List_Obj list = SASS_MEMORY_CAST(Selector_List, wrapped->selector())) { - if (Compound_Selector_Obj comp = SASS_MEMORY_CAST(Compound_Selector, rhs)) { + if (Selector_List_Obj list = Cast(wrapped->selector())) { + if (Compound_Selector_Obj comp = Cast(rhs)) { if (!wrapping.empty() && wrapping != wrapped->name()) return false; if (wrapping.empty() || wrapping != wrapped->name()) {; if (list->is_superselector_of(comp, wrapped->name())) return true; @@ -858,8 +855,9 @@ namespace Sass { } } } - Simple_Selector_Ptr rhs_sel = rhs->elements().size() > i ? &(*rhs)[i] : 0; - if (Wrapped_Selector_Ptr wrapped_r = dynamic_cast(rhs_sel)) { + Simple_Selector_Ptr rhs_sel = NULL; + if (rhs->elements().size() > i) rhs_sel = (*rhs)[i]; + if (Wrapped_Selector_Ptr wrapped_r = Cast(rhs_sel)) { if (wrapped->name() == wrapped_r->name()) { if (wrapped->is_superselector_of(wrapped_r)) { continue; @@ -874,10 +872,10 @@ namespace Sass { for (size_t n = 0, nL = rhs->length(); n < nL; ++n) { - Selector_Obj r = &(*rhs)[n]; - if (Wrapped_Selector_Obj wrapped = SASS_MEMORY_CAST(Wrapped_Selector, r)) { + Selector_Obj r = (*rhs)[n]; + if (Wrapped_Selector_Obj wrapped = Cast(r)) { if (wrapped->name() == ":not") { - if (Selector_List_Obj ls = SASS_MEMORY_CAST(Selector_List, wrapped->selector())) { + if (Selector_List_Obj ls = Cast(wrapped->selector())) { ls->remove_parent_selectors(); if (is_superselector_of(ls, wrapped->name())) return false; } @@ -886,7 +884,7 @@ namespace Sass { if (!wrapping.empty()) { if (wrapping != wrapped->name()) return false; } - if (Selector_List_Obj ls = SASS_MEMORY_CAST(Selector_List, wrapped->selector())) { + if (Selector_List_Obj ls = Cast(wrapped->selector())) { ls->remove_parent_selectors(); return (is_superselector_of(ls, wrapped->name())); } @@ -941,7 +939,7 @@ namespace Sass { SASS_ASSERT(r_last_head, "rhs head is null"); // get the unification of the last compound selectors - Compound_Selector_Obj unified = r_last_head->unify_with(&l_last_head, ctx); + Compound_Selector_Obj unified = r_last_head->unify_with(l_last_head, ctx); // abort if we could not unify heads if (unified == 0) return 0; @@ -966,7 +964,7 @@ namespace Sass { { // create some temporaries to convert to node Complex_Selector_Obj fake = unified->to_complex(); - Node unified_node = complexSelectorToNode(&fake, ctx); + Node unified_node = complexSelectorToNode(fake, ctx); // add to permutate the list? rhsNode.plus(unified_node); } @@ -992,8 +990,8 @@ namespace Sass { // create temporary vectors and sort them std::vector l_lst = this->elements(); std::vector r_lst = rhs.elements(); - std::sort(l_lst.begin(), l_lst.end(), cmp_simple_selector()); - std::sort(r_lst.begin(), r_lst.end(), cmp_simple_selector()); + std::sort(l_lst.begin(), l_lst.end(), OrderNodes()); + std::sort(r_lst.begin(), r_lst.end(), OrderNodes()); // process loop while (true) { @@ -1016,10 +1014,6 @@ namespace Sass { return true; } - bool Complex_Selector_Pointer_Compare::operator() (const Complex_Selector_Obj& pLeft, const Complex_Selector_Obj& pRight) const { - return *pLeft < *pRight; - } - bool Complex_Selector::is_superselector_of(Compound_Selector_Obj rhs, std::string wrapping) { return last()->head() && last()->head()->is_superselector_of(rhs, wrapping); @@ -1043,7 +1037,7 @@ namespace Sass { { return false; } if (l_len == 1) - { return lhs->head()->is_superselector_of(&rhs->last()->head(), wrapping); } + { return lhs->head()->is_superselector_of(rhs->last()->head(), wrapping); } // we have to look one tail deeper, since we cary the // combinator around for it (which is important here) @@ -1054,7 +1048,7 @@ namespace Sass { if (lhs_tail->head() && !rhs_tail->head()) return false; if (!lhs_tail->head() && rhs_tail->head()) return false; if (lhs_tail->head() && rhs_tail->head()) { - if (!lhs_tail->head()->is_superselector_of(&rhs_tail->head())) return false; + if (!lhs_tail->head()->is_superselector_of(rhs_tail->head())) return false; } } @@ -1063,7 +1057,7 @@ namespace Sass { for (size_t i = 0, L = rhs->length(); i < L; ++i) { if (i == L-1) { return false; } - if (lhs->head() && marker->head() && lhs->head()->is_superselector_of(&marker->head(), wrapping)) + if (lhs->head() && marker->head() && lhs->head()->is_superselector_of(marker->head(), wrapping)) { found = true; break; } marker = marker->tail(); } @@ -1089,17 +1083,17 @@ namespace Sass { { return false; } if (!(lhs->combinator() == Complex_Selector::PRECEDES ? marker->combinator() != Complex_Selector::PARENT_OF : lhs->combinator() == marker->combinator())) { return false; } - return lhs->tail()->is_superselector_of(&marker->tail()); + return lhs->tail()->is_superselector_of(marker->tail()); } else if (marker->combinator() != Complex_Selector::ANCESTOR_OF) { if (marker->combinator() != Complex_Selector::PARENT_OF) { return false; } - return lhs->tail()->is_superselector_of(&marker->tail()); + return lhs->tail()->is_superselector_of(marker->tail()); } else { - return lhs->tail()->is_superselector_of(&marker->tail()); + return lhs->tail()->is_superselector_of(marker->tail()); } // catch-all return false; @@ -1112,15 +1106,6 @@ namespace Sass { return 1 + tail()->length(); } - Complex_Selector_Obj Complex_Selector::context(Context& ctx) - { - if (!tail()) return 0; - if (!head()) return tail()->context(ctx); - Complex_Selector_Obj cpy = SASS_MEMORY_NEW(Complex_Selector, pstate(), combinator(), head(), tail()->context(ctx)); - cpy->media_block(media_block()); - return cpy; - } - // append another complex selector at the end // check if we need to append some headers // then we need to check for the combinator @@ -1143,43 +1128,43 @@ namespace Sass { } else if (last()->head_ && last()->head_->length()) { Compound_Selector_Obj rh = last()->head(); size_t i = 0, L = h->length(); - if (SASS_MEMORY_CAST(Element_Selector, h->first())) { - if (Class_Selector_Ptr sq = SASS_MEMORY_CAST(Class_Selector, rh->last())) { + if (Cast(h->first())) { + if (Class_Selector_Ptr sq = Cast(rh->last())) { Class_Selector_Ptr sqs = SASS_MEMORY_COPY(sq); sqs->name(sqs->name() + (*h)[0]->name()); sqs->pstate((*h)[0]->pstate()); (*rh)[rh->length()-1] = sqs; rh->pstate(h->pstate()); - for (i = 1; i < L; ++i) rh->append(&(*h)[i]); - } else if (Id_Selector_Ptr sq = SASS_MEMORY_CAST(Id_Selector, rh->last())) { + for (i = 1; i < L; ++i) rh->append((*h)[i]); + } else if (Id_Selector_Ptr sq = Cast(rh->last())) { Id_Selector_Ptr sqs = SASS_MEMORY_COPY(sq); sqs->name(sqs->name() + (*h)[0]->name()); sqs->pstate((*h)[0]->pstate()); (*rh)[rh->length()-1] = sqs; rh->pstate(h->pstate()); - for (i = 1; i < L; ++i) rh->append(&(*h)[i]); - } else if (Element_Selector_Ptr ts = SASS_MEMORY_CAST(Element_Selector, rh->last())) { + for (i = 1; i < L; ++i) rh->append((*h)[i]); + } else if (Element_Selector_Ptr ts = Cast(rh->last())) { Element_Selector_Ptr tss = SASS_MEMORY_COPY(ts); tss->name(tss->name() + (*h)[0]->name()); tss->pstate((*h)[0]->pstate()); (*rh)[rh->length()-1] = tss; rh->pstate(h->pstate()); - for (i = 1; i < L; ++i) rh->append(&(*h)[i]); - } else if (Placeholder_Selector_Ptr ps = SASS_MEMORY_CAST(Placeholder_Selector, rh->last())) { + for (i = 1; i < L; ++i) rh->append((*h)[i]); + } else if (Placeholder_Selector_Ptr ps = Cast(rh->last())) { Placeholder_Selector_Ptr pss = SASS_MEMORY_COPY(ps); pss->name(pss->name() + (*h)[0]->name()); pss->pstate((*h)[0]->pstate()); (*rh)[rh->length()-1] = pss; rh->pstate(h->pstate()); - for (i = 1; i < L; ++i) rh->append(&(*h)[i]); + for (i = 1; i < L; ++i) rh->append((*h)[i]); } else { - last()->head_->concat(&h); + last()->head_->concat(h); } } else { - last()->head_->concat(&h); + last()->head_->concat(h); } } else { - last()->head_->concat(&h); + last()->head_->concat(h); } } else { // std::cerr << "has no or empty head\n"; @@ -1201,18 +1186,25 @@ namespace Sass { } } + } + Selector_List_Obj Selector_List::eval(Eval& eval) + { + Selector_List_Obj list = schema() ? + eval(schema()) : eval(this); + list->schema(schema()); + return list; } Selector_List_Ptr Selector_List::resolve_parent_refs(Context& ctx, std::vector& pstack, bool implicit_parent) { if (!this->has_parent_ref()) return this; Selector_List_Ptr ss = SASS_MEMORY_NEW(Selector_List, pstate()); - Selector_List_Ptr ps = &pstack.back(); + Selector_List_Ptr ps = pstack.back(); for (size_t pi = 0, pL = ps->length(); pi < pL; ++pi) { for (size_t si = 0, sL = this->length(); si < sL; ++si) { Selector_List_Obj rv = at(si)->resolve_parent_refs(ctx, pstack, implicit_parent); - ss->concat(&rv); + ss->concat(rv); } } return ss; @@ -1222,7 +1214,7 @@ namespace Sass { { Complex_Selector_Obj tail = this->tail(); Compound_Selector_Obj head = this->head(); - Selector_List_Ptr parents = &pstack.back(); + Selector_List_Ptr parents = pstack.back(); if (!this->has_real_parent_ref() && !implicit_parent) { Selector_List_Ptr retval = SASS_MEMORY_NEW(Selector_List, pstate()); @@ -1238,7 +1230,7 @@ namespace Sass { Selector_List_Obj retval; // we have a parent selector in a simple compound list // mix parent complex selector into the compound list - if (SASS_MEMORY_CAST(Parent_Selector, (*head)[0])) { + if (Cast((*head)[0])) { retval = SASS_MEMORY_NEW(Selector_List, pstate()); // it turns out that real parent references reach @@ -1246,7 +1238,7 @@ namespace Sass { if (parents == NULL && head->has_real_parent_ref()) { int i = pstack.size() - 1; while (!parents && i > -1) { - parents = &pstack.at(i--); + parents = pstack.at(i--); } } @@ -1258,11 +1250,15 @@ namespace Sass { Complex_Selector_Obj parent = (*parents)[i]; Complex_Selector_Obj s = SASS_MEMORY_CLONE(parent); Complex_Selector_Obj ss = SASS_MEMORY_CLONE(this); - ss->tail(t ? SASS_MEMORY_CLONE(t) : 0); + ss->tail(t ? SASS_MEMORY_CLONE(t) : NULL); Compound_Selector_Obj h = SASS_MEMORY_COPY(head_); // remove parent selector from sequence - if (h->length()) h->erase(h->begin()); - ss->head(h->length() ? &h : 0); + if (h->length()) { + h->erase(h->begin()); + ss->head(h); + } else { + ss->head(NULL); + } // adjust for parent selector (1 char) if (h->length()) { ParserState state(h->at(0)->pstate()); @@ -1288,13 +1284,17 @@ namespace Sass { // this is only if valid if the parent has no trailing op // otherwise we cannot append more simple selectors to head if (parent->last()->combinator() != ANCESTOR_OF) { - throw Exception::InvalidParent(&parent, &ss); + throw Exception::InvalidParent(parent, ss); } - ss->tail(tail ? SASS_MEMORY_CLONE(tail) : 0); + ss->tail(tail ? SASS_MEMORY_CLONE(tail) : NULL); Compound_Selector_Obj h = SASS_MEMORY_COPY(head_); // remove parent selector from sequence - if (h->length()) h->erase(h->begin()); - ss->head(h->length() ? &h : 0); + if (h->length()) { + h->erase(h->begin()); + ss->head(h); + } else { + ss->head(NULL); + } // \/ IMO ruby sass bug \/ ss->has_line_feed(false); // adjust for parent selector (1 char) @@ -1307,7 +1307,7 @@ namespace Sass { // keep old parser state s->pstate(pstate()); // append new tail - s->append(ctx, &ss); + s->append(ctx, ss); retval->append(s); } } @@ -1320,7 +1320,7 @@ namespace Sass { cpy->tail(SASS_MEMORY_CLONE(tails->at(n))); cpy->head(SASS_MEMORY_NEW(Compound_Selector, head->pstate())); for (size_t i = 1, L = this->head()->length(); i < L; ++i) - cpy->head()->append(&(*this->head())[i]); + cpy->head()->append((*this->head())[i]); if (!cpy->head()->length()) cpy->head(0); retval->append(cpy->skip_empty_reference()); } @@ -1330,7 +1330,7 @@ namespace Sass { Complex_Selector_Obj cpy = SASS_MEMORY_CLONE(this); cpy->head(SASS_MEMORY_NEW(Compound_Selector, head->pstate())); for (size_t i = 1, L = this->head()->length(); i < L; ++i) - cpy->head()->append(&(*this->head())[i]); + cpy->head()->append((*this->head())[i]); if (!cpy->head()->length()) cpy->head(0); retval->append(cpy->skip_empty_reference()); } @@ -1338,12 +1338,12 @@ namespace Sass { } // no parent selector in head else { - retval = this->tails(ctx, &tails); + retval = this->tails(ctx, tails); } for (Simple_Selector_Obj ss : head->elements()) { - if (Wrapped_Selector_Ptr ws = SASS_MEMORY_CAST(Wrapped_Selector, ss)) { - if (Selector_List_Ptr sl = SASS_MEMORY_CAST(Selector_List, ws->selector())) { + if (Wrapped_Selector_Ptr ws = Cast(ss)) { + if (Selector_List_Ptr sl = Cast(ws->selector())) { if (parents) ws->selector(sl->resolve_parent_refs(ctx, pstack, implicit_parent)); } } @@ -1354,7 +1354,7 @@ namespace Sass { } // has no head else { - return this->tails(ctx, &tails); + return this->tails(ctx, tails); } // unreachable @@ -1389,21 +1389,27 @@ namespace Sass { // get the head head = cur->head_; // abort (and return) if it is not a parent selector - if (!head || head->length() != 1 || !SASS_MEMORY_CAST(Parent_Selector, (*head)[0])) { + if (!head || head->length() != 1 || !Cast((*head)[0])) { break; } // advance to next cur = cur->tail_; } // result - return &cur; + return cur; } // return the last tail that is defined Complex_Selector_Obj Complex_Selector::last() { - // ToDo: implement with a while loop - return tail_? tail_->last() : this; + Complex_Selector_Ptr cur = this; + Complex_Selector_Ptr nxt = cur; + // loop until last + while (nxt) { + cur = nxt; + nxt = cur->tail(); + } + return cur; } Complex_Selector::Combinator Complex_Selector::clear_innermost() @@ -1474,7 +1480,31 @@ namespace Sass { } } - bool Selector_List::has_parent_ref() + size_t Wrapped_Selector::hash() + { + if (hash_ == 0) { + hash_combine(hash_, Simple_Selector::hash()); + if (selector_) hash_combine(hash_, selector_->hash()); + } + return hash_; + } + bool Wrapped_Selector::has_parent_ref() const { + // if (has_reference()) return true; + if (!selector()) return false; + return selector()->has_parent_ref(); + } + bool Wrapped_Selector::has_real_parent_ref() const { + // if (has_reference()) return true; + if (!selector()) return false; + return selector()->has_real_parent_ref(); + } + unsigned long Wrapped_Selector::specificity() const + { + return selector_ ? selector_->specificity() : 0; + } + + + bool Selector_List::has_parent_ref() const { for (Complex_Selector_Obj s : elements()) { if (s && s->has_parent_ref()) return true; @@ -1482,7 +1512,7 @@ namespace Sass { return false; } - bool Selector_List::has_real_parent_ref() + bool Selector_List::has_real_parent_ref() const { for (Complex_Selector_Obj s : elements()) { if (s && s->has_real_parent_ref()) return true; @@ -1490,18 +1520,18 @@ namespace Sass { return false; } - bool Selector_Schema::has_parent_ref() + bool Selector_Schema::has_parent_ref() const { - if (String_Schema_Obj schema = SASS_MEMORY_CAST(String_Schema, contents())) { - return schema->length() > 0 && SASS_MEMORY_CAST(Parent_Selector, schema->at(0)) != NULL; + if (String_Schema_Obj schema = Cast(contents())) { + return schema->length() > 0 && Cast(schema->at(0)) != NULL; } return false; } - bool Selector_Schema::has_real_parent_ref() + bool Selector_Schema::has_real_parent_ref() const { - if (String_Schema_Obj schema = SASS_MEMORY_CAST(String_Schema, contents())) { - Parent_Selector_Obj p = SASS_MEMORY_CAST(Parent_Selector, schema->at(0)); + if (String_Schema_Obj schema = Cast(contents())) { + Parent_Selector_Obj p = Cast(schema->at(0)); return schema->length() > 0 && p && p->is_real_parent_ref(); } return false; @@ -1518,7 +1548,7 @@ namespace Sass { { // Check every rhs selector against left hand list for(size_t i = 0, L = sub->length(); i < L; ++i) { - if (!is_superselector_of(&(*sub)[i], wrapping)) return false; + if (!is_superselector_of((*sub)[i], wrapping)) return false; } return true; } @@ -1529,7 +1559,7 @@ namespace Sass { { // Check every rhs selector against left hand list for(size_t i = 0, L = sub->length(); i < L; ++i) { - if (!is_superselector_of(&(*sub)[i], wrapping)) return false; + if (!is_superselector_of((*sub)[i], wrapping)) return false; } return true; } @@ -1562,12 +1592,12 @@ namespace Sass { for (size_t lhs_i = 0, lhs_L = length(); lhs_i < lhs_L; ++lhs_i) { Complex_Selector_Obj seq1 = (*this)[lhs_i]; for(size_t rhs_i = 0, rhs_L = rhs->length(); rhs_i < rhs_L; ++rhs_i) { - Complex_Selector_Ptr seq2 = &rhs->at(rhs_i); + Complex_Selector_Ptr seq2 = rhs->at(rhs_i); Selector_List_Obj result = seq1->unify_with(seq2, ctx); if( result ) { for(size_t i = 0, L = result->length(); i < L; ++i) { - unified_complex_selectors.push_back( &(*result)[i] ); + unified_complex_selectors.push_back( (*result)[i] ); } } } @@ -1594,7 +1624,7 @@ namespace Sass { Complex_Selector_Obj pIter = complex_sel; while (pIter) { Compound_Selector_Obj pHead = pIter->head(); - if (pHead && SASS_MEMORY_CAST(Parent_Selector, pHead->elements()[0]) == NULL) { + if (pHead && Cast(pHead->elements()[0]) == NULL) { compound_sel = pHead; break; } @@ -1609,19 +1639,11 @@ namespace Sass { compound_sel->is_optional(extendee->is_optional()); for (size_t i = 0, L = extender->length(); i < L; ++i) { - extends.put(compound_sel, std::make_pair(&(*extender)[i], &compound_sel)); + extends.put(compound_sel, std::make_pair((*extender)[i], compound_sel)); } } }; - std::vector Compound_Selector::to_str_vec() - { - std::vector result(length()); - for (size_t i = 0, L = length(); i < L; ++i) - { result.push_back((*this)[i]->to_string()); } - return result; - } - void Compound_Selector::append(Simple_Selector_Ptr element) { Vectorized::append(element); @@ -1646,15 +1668,15 @@ namespace Sass { break; } } - if (!found) result->append(&(*this)[i]); + if (!found) result->append((*this)[i]); } return result; } - void Compound_Selector::mergeSources(SourcesSet& sources, Context& ctx) + void Compound_Selector::mergeSources(ComplexSelectorSet& sources, Context& ctx) { - for (SourcesSet::iterator iterator = sources.begin(), endIterator = sources.end(); iterator != endIterator; ++iterator) { + for (ComplexSelectorSet::iterator iterator = sources.begin(), endIterator = sources.end(); iterator != endIterator; ++iterator) { this->sources_.insert(SASS_MEMORY_CLONE(*iterator)); } } @@ -1717,7 +1739,7 @@ namespace Sass { } bool Ruleset::is_invisible() const { - if (Selector_List_Ptr sl = SASS_MEMORY_CAST(Selector_List, selector())) { + if (Selector_List_Ptr sl = Cast(selector())) { for (size_t i = 0, L = sl->length(); i < L; ++i) if (!(*sl)[i]->has_placeholder()) return false; } @@ -2094,7 +2116,7 @@ namespace Sass { bool Custom_Warning::operator== (const Expression& rhs) const { - if (Custom_Warning_Ptr_Const r = dynamic_cast(&rhs)) { + if (Custom_Warning_Ptr_Const r = Cast(&rhs)) { return message() == r->message(); } return false; @@ -2102,30 +2124,15 @@ namespace Sass { bool Custom_Error::operator== (const Expression& rhs) const { - if (Custom_Error_Ptr_Const r = dynamic_cast(&rhs)) { + if (Custom_Error_Ptr_Const r = Cast(&rhs)) { return message() == r->message(); } return false; } - bool Number::eq (const Expression& rhs) const - { - if (Number_Ptr_Const r = dynamic_cast(&rhs)) { - size_t lhs_units = numerator_units_.size() + denominator_units_.size(); - size_t rhs_units = r->numerator_units_.size() + r->denominator_units_.size(); - if (!lhs_units && !rhs_units) { - return std::fabs(value() - r->value()) < NUMBER_EPSILON; - } - return (numerator_units_ == r->numerator_units_) && - (denominator_units_ == r->denominator_units_) && - std::fabs(value() - r->value()) < NUMBER_EPSILON; - } - return false; - } - bool Number::operator== (const Expression& rhs) const { - if (Number_Ptr_Const r = dynamic_cast(&rhs)) { + if (Number_Ptr_Const r = Cast(&rhs)) { size_t lhs_units = numerator_units_.size() + denominator_units_.size(); size_t rhs_units = r->numerator_units_.size() + r->denominator_units_.size(); // unitless and only having one unit seems equivalent (will change in future) @@ -2160,9 +2167,9 @@ namespace Sass { bool String_Quoted::operator== (const Expression& rhs) const { - if (String_Quoted_Ptr_Const qstr = dynamic_cast(&rhs)) { + if (String_Quoted_Ptr_Const qstr = Cast(&rhs)) { return (value() == qstr->value()); - } else if (String_Constant_Ptr_Const cstr = dynamic_cast(&rhs)) { + } else if (String_Constant_Ptr_Const cstr = Cast(&rhs)) { return (value() == cstr->value()); } return false; @@ -2174,9 +2181,9 @@ namespace Sass { bool String_Constant::operator== (const Expression& rhs) const { - if (String_Quoted_Ptr_Const qstr = dynamic_cast(&rhs)) { + if (String_Quoted_Ptr_Const qstr = Cast(&rhs)) { return (value() == qstr->value()); - } else if (String_Constant_Ptr_Const cstr = dynamic_cast(&rhs)) { + } else if (String_Constant_Ptr_Const cstr = Cast(&rhs)) { return (value() == cstr->value()); } return false; @@ -2193,7 +2200,7 @@ namespace Sass { bool String_Schema::operator== (const Expression& rhs) const { - if (String_Schema_Ptr_Const r = dynamic_cast(&rhs)) { + if (String_Schema_Ptr_Const r = Cast(&rhs)) { if (length() != r->length()) return false; for (size_t i = 0, L = length(); i < L; ++i) { Expression_Obj rv = (*r)[i]; @@ -2208,7 +2215,7 @@ namespace Sass { bool Boolean::operator== (const Expression& rhs) const { - if (Boolean_Ptr_Const r = dynamic_cast(&rhs)) { + if (Boolean_Ptr_Const r = Cast(&rhs)) { return (value() == r->value()); } return false; @@ -2216,7 +2223,7 @@ namespace Sass { bool Color::operator== (const Expression& rhs) const { - if (Color_Ptr_Const r = dynamic_cast(&rhs)) { + if (Color_Ptr_Const r = Cast(&rhs)) { return r_ == r->r() && g_ == r->g() && b_ == r->b() && @@ -2227,9 +2234,10 @@ namespace Sass { bool List::operator== (const Expression& rhs) const { - if (List_Ptr_Const r = dynamic_cast(&rhs)) { + if (List_Ptr_Const r = Cast(&rhs)) { if (length() != r->length()) return false; if (separator() != r->separator()) return false; + if (is_bracketed() != r->is_bracketed()) return false; for (size_t i = 0, L = length(); i < L; ++i) { Expression_Obj rv = r->at(i); Expression_Obj lv = this->at(i); @@ -2243,7 +2251,7 @@ namespace Sass { bool Map::operator== (const Expression& rhs) const { - if (Map_Ptr_Const r = dynamic_cast(&rhs)) { + if (Map_Ptr_Const r = Cast(&rhs)) { if (length() != r->length()) return false; for (auto key : keys()) { Expression_Obj lv = at(key); @@ -2267,7 +2275,7 @@ namespace Sass { // so we need to break before keywords for (size_t i = 0, L = length(); i < L; ++i) { Expression_Obj obj = this->at(i); - if (Argument* arg = dynamic_cast(&obj)) { + if (Argument_Ptr arg = Cast(obj)) { if (!arg->name().empty()) return i; } } @@ -2290,7 +2298,7 @@ namespace Sass { return is_interpolant() || (right() && right()->is_right_interpolant()); } - std::string AST_Node::to_string(Sass_Inspect_Options opt) const + const std::string AST_Node::to_string(Sass_Inspect_Options opt) const { Sass_Output_Options out(opt); Emitter emitter(out); @@ -2301,7 +2309,7 @@ namespace Sass { return i.get_buffer(); } - std::string AST_Node::to_string() const + const std::string AST_Node::to_string() const { return to_string({ NESTED, 5 }); } @@ -2322,13 +2330,13 @@ namespace Sass { Expression_Obj List::value_at_index(size_t i) { Expression_Obj obj = this->at(i); if (is_arglist_) { - if (Argument* arg = dynamic_cast(&obj)) { + if (Argument_Ptr arg = Cast(obj)) { return arg->value(); } else { - return &obj; + return obj; } } else { - return &obj; + return obj; } } @@ -2340,9 +2348,9 @@ namespace Sass { for (auto key : keys()) { List_Obj l = SASS_MEMORY_NEW(List, pstate, 2); - l->append(&key); + l->append(key); l->append(at(key)); - ret->append(&l); + ret->append(l); } return ret; diff --git a/src/libsass/src/ast.hpp b/src/libsass/src/ast.hpp index 3df08888e..d41e434c0 100755 --- a/src/libsass/src/ast.hpp +++ b/src/libsass/src/ast.hpp @@ -1,6 +1,7 @@ #ifndef SASS_AST_H #define SASS_AST_H +#include "sass.hpp" #include #include #include @@ -120,12 +121,11 @@ namespace Sass { ATTACH_VIRTUAL_AST_OPERATIONS(AST_Node); virtual std::string inspect() const { return to_string({ INSPECT, 5 }); } virtual std::string to_sass() const { return to_string({ TO_SASS, 5 }); } - virtual std::string to_string(Sass_Inspect_Options opt) const; - virtual std::string to_string() const; + virtual const std::string to_string(Sass_Inspect_Options opt) const; + virtual const std::string to_string() const; virtual void cloneChildren() {}; public: void update_pstate(const ParserState& pstate); - void set_pstate_offset(const Offset& offset); public: Offset off() { return pstate(); } Position pos() { return pstate(); } @@ -133,6 +133,21 @@ namespace Sass { }; inline AST_Node::~AST_Node() { } + ////////////////////////////////////////////////////////////////////// + // define cast template now (need complete type) + ////////////////////////////////////////////////////////////////////// + + template + T* Cast(AST_Node* ptr) { + return ptr && typeid(T) == typeid(*ptr) ? + static_cast(ptr) : NULL; + }; + + template + const T* Cast(const AST_Node* ptr) { + return ptr && typeid(T) == typeid(*ptr) ? + static_cast(ptr) : NULL; + }; ////////////////////////////////////////////////////////////////////// // Abstract base class for expressions. This side of the AST hierarchy @@ -186,7 +201,7 @@ namespace Sass { { } virtual operator bool() { return true; } virtual ~Expression() { } - virtual std::string type() { return ""; /* TODO: raise an error? */ } + virtual std::string type() const { return ""; /* TODO: raise an error? */ } virtual bool is_invisible() const { return false; } static std::string type_name() { return ""; } virtual bool is_false() { return false; } @@ -454,7 +469,6 @@ namespace Sass { //////////////////////// class Block : public Statement, public Vectorized { ADD_PROPERTY(bool, is_root) - ADD_PROPERTY(bool, is_at_root); // needed for properly formatted CSS emission protected: void adjust_after_pushing(Statement_Obj s) @@ -464,14 +478,12 @@ namespace Sass { Block(ParserState pstate, size_t s = 0, bool r = false) : Statement(pstate), Vectorized(s), - is_root_(r), - is_at_root_(false) + is_root_(r) { } Block(const Block* ptr) : Statement(ptr), Vectorized(*ptr), - is_root_(ptr->is_root_), - is_at_root_(ptr->is_at_root_) + is_root_(ptr->is_root_) { } virtual bool has_content() { @@ -509,17 +521,15 @@ namespace Sass { // of style declarations. ///////////////////////////////////////////////////////////////////////////// class Ruleset : public Has_Block { - ADD_PROPERTY(Selector_Obj, selector) - ADD_PROPERTY(bool, at_root); + ADD_PROPERTY(Selector_List_Obj, selector) ADD_PROPERTY(bool, is_root); public: - Ruleset(ParserState pstate, Selector_Obj s = 0, Block_Obj b = 0) - : Has_Block(pstate, b), selector_(s), at_root_(false), is_root_(false) + Ruleset(ParserState pstate, Selector_List_Obj s = 0, Block_Obj b = 0) + : Has_Block(pstate, b), selector_(s), is_root_(false) { statement_type(RULESET); } Ruleset(const Ruleset* ptr) : Has_Block(ptr), selector_(ptr->selector_), - at_root_(ptr->at_root_), is_root_(ptr->is_root_) { statement_type(RULESET); } bool is_invisible() const; @@ -551,7 +561,7 @@ namespace Sass { // Trace. ///////////////// class Trace : public Has_Block { - ADD_PROPERTY(std::string, name) + ADD_CONSTREF(std::string, name) public: Trace(ParserState pstate, std::string n, Block_Obj b = 0) : Has_Block(pstate, b), name_(n) @@ -573,9 +583,6 @@ namespace Sass { Media_Block(ParserState pstate, List_Obj mqs, Block_Obj b) : Has_Block(pstate, b), media_queries_(mqs) { statement_type(MEDIA); } - Media_Block(ParserState pstate, List_Obj mqs, Block_Obj b, Selector_Obj s) - : Has_Block(pstate, b), media_queries_(mqs) - { statement_type(MEDIA); } Media_Block(const Media_Block* ptr) : Has_Block(ptr), media_queries_(ptr->media_queries_) { statement_type(MEDIA); } @@ -590,11 +597,11 @@ namespace Sass { // optional statement block. /////////////////////////////////////////////////////////////////////// class Directive : public Has_Block { - ADD_PROPERTY(std::string, keyword) - ADD_PROPERTY(Selector_Obj, selector) + ADD_CONSTREF(std::string, keyword) + ADD_PROPERTY(Selector_List_Obj, selector) ADD_PROPERTY(Expression_Obj, value) public: - Directive(ParserState pstate, std::string kwd, Selector_Obj sel = 0, Block_Obj b = 0, Expression_Obj val = 0) + Directive(ParserState pstate, std::string kwd, Selector_List_Obj sel = 0, Block_Obj b = 0, Expression_Obj val = 0) : Has_Block(pstate, b), keyword_(kwd), selector_(sel), value_(val) // set value manually if needed { statement_type(DIRECTIVE); } Directive(const Directive* ptr) @@ -626,7 +633,7 @@ namespace Sass { class Keyframe_Rule : public Has_Block { // according to css spec, this should be // = | - ADD_PROPERTY(Selector_Obj, name) + ADD_PROPERTY(Selector_List_Obj, name) public: Keyframe_Rule(ParserState pstate, Block_Obj b) : Has_Block(pstate, b), name_() @@ -666,7 +673,7 @@ namespace Sass { // Assignments -- variable and value. ///////////////////////////////////// class Assignment : public Statement { - ADD_PROPERTY(std::string, variable) + ADD_CONSTREF(std::string, variable) ADD_PROPERTY(Expression_Obj, value) ADD_PROPERTY(bool, is_default) ADD_PROPERTY(bool, is_global) @@ -811,7 +818,7 @@ namespace Sass { ADD_PROPERTY(Block_Obj, alternative) public: If(ParserState pstate, Expression_Obj pred, Block_Obj con, Block_Obj alt = 0) - : Has_Block(pstate, &con), predicate_(pred), alternative_(alt) + : Has_Block(pstate, con), predicate_(pred), alternative_(alt) { statement_type(IF); } If(const If* ptr) : Has_Block(ptr), @@ -830,7 +837,7 @@ namespace Sass { // The Sass `@for` control directive. ///////////////////////////////////// class For : public Has_Block { - ADD_PROPERTY(std::string, variable) + ADD_CONSTREF(std::string, variable) ADD_PROPERTY(Expression_Obj, lower_bound) ADD_PROPERTY(Expression_Obj, upper_bound) ADD_PROPERTY(bool, is_inclusive) @@ -904,9 +911,9 @@ namespace Sass { // The Sass `@extend` directive. //////////////////////////////// class Extension : public Statement { - ADD_PROPERTY(Selector_Obj, selector) + ADD_PROPERTY(Selector_List_Obj, selector) public: - Extension(ParserState pstate, Selector_Obj s) + Extension(ParserState pstate, Selector_List_Obj s) : Statement(pstate), selector_(s) { statement_type(EXTEND); } Extension(const Extension* ptr) @@ -921,13 +928,12 @@ namespace Sass { // by a type tag. ///////////////////////////////////////////////////////////////////////////// struct Backtrace; - typedef Environment Env; typedef const char* Signature; typedef Expression_Ptr (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtrace*, std::vector); class Definition : public Has_Block { public: enum Type { MIXIN, FUNCTION }; - ADD_PROPERTY(std::string, name) + ADD_CONSTREF(std::string, name) ADD_PROPERTY(Parameters_Obj, parameters) ADD_PROPERTY(Env*, environment) ADD_PROPERTY(Type, type) @@ -1009,7 +1015,7 @@ namespace Sass { // Mixin calls (i.e., `@include ...`). ////////////////////////////////////// class Mixin_Call : public Has_Block { - ADD_PROPERTY(std::string, name) + ADD_CONSTREF(std::string, name) ADD_PROPERTY(Arguments_Obj, arguments) public: Mixin_Call(ParserState pstate, std::string n, Arguments_Obj args, Block_Obj b = 0) @@ -1028,7 +1034,7 @@ namespace Sass { // The @content directive for mixin content blocks. /////////////////////////////////////////////////// class Content : public Statement { - ADD_PROPERTY(Media_Block_Obj, media_block) + ADD_PROPERTY(Media_Block_Ptr, media_block) public: Content(ParserState pstate) : Statement(pstate) { statement_type(CONTENT); } @@ -1047,14 +1053,16 @@ namespace Sass { private: ADD_PROPERTY(enum Sass_Separator, separator) ADD_PROPERTY(bool, is_arglist) + ADD_PROPERTY(bool, is_bracketed) ADD_PROPERTY(bool, from_selector) public: List(ParserState pstate, - size_t size = 0, enum Sass_Separator sep = SASS_SPACE, bool argl = false) + size_t size = 0, enum Sass_Separator sep = SASS_SPACE, bool argl = false, bool bracket = false) : Value(pstate), Vectorized(size), separator_(sep), is_arglist_(argl), + is_bracketed_(bracket), from_selector_(false) { concrete_type(LIST); } List(const List* ptr) @@ -1062,15 +1070,16 @@ namespace Sass { Vectorized(*ptr), separator_(ptr->separator_), is_arglist_(ptr->is_arglist_), + is_bracketed_(ptr->is_bracketed_), from_selector_(ptr->from_selector_) { concrete_type(LIST); } - std::string type() { return is_arglist_ ? "arglist" : "list"; } + std::string type() const { return is_arglist_ ? "arglist" : "list"; } static std::string type_name() { return "list"; } const char* sep_string(bool compressed = false) const { return separator() == SASS_SPACE ? " " : (compressed ? "," : ", "); } - bool is_invisible() const { return empty(); } + bool is_invisible() const { return empty() && !is_bracketed(); } Expression_Obj value_at_index(size_t i); virtual size_t size() const; @@ -1079,6 +1088,7 @@ namespace Sass { { if (hash_ == 0) { hash_ = std::hash()(sep_string()); + hash_combine(hash_, std::hash()(is_bracketed())); for (size_t i = 0, L = length(); i < L; ++i) hash_combine(hash_, (elements()[i])->hash()); } @@ -1112,7 +1122,7 @@ namespace Sass { : Value(ptr), Hashed(*ptr) { concrete_type(MAP); } - std::string type() { return "map"; } + std::string type() const { return "map"; } static std::string type_name() { return "map"; } bool is_invisible() const { return empty(); } List_Obj to_list(Context& ctx, ParserState& pstate); @@ -1163,9 +1173,9 @@ namespace Sass { ////////////////////////////////////////////////////////////////////////// class Binary_Expression : public PreValue { private: - ADD_HASHED(Operand, op) - ADD_HASHED(Expression_Obj, left) - ADD_HASHED(Expression_Obj, right) + HASH_PROPERTY(Operand, op) + HASH_PROPERTY(Expression_Obj, left) + HASH_PROPERTY(Expression_Obj, right) size_t hash_; public: Binary_Expression(ParserState pstate, @@ -1180,7 +1190,7 @@ namespace Sass { hash_(ptr->hash_) { } const std::string type_name() { - switch (type()) { + switch (optype()) { case AND: return "and"; break; case OR: return "or"; break; case EQ: return "eq"; break; @@ -1200,7 +1210,7 @@ namespace Sass { } } const std::string separator() { - switch (type()) { + switch (optype()) { case AND: return "&&"; break; case OR: return "||"; break; case EQ: return "=="; break; @@ -1236,11 +1246,11 @@ namespace Sass { { try { - Binary_Expression_Ptr_Const m = dynamic_cast(&rhs); + Binary_Expression_Ptr_Const m = Cast(&rhs); if (m == 0) return false; return type() == m->type() && - left() == m->left() && - right() == m->right(); + *left() == *m->left() && + *right() == *m->right(); } catch (std::bad_cast&) { @@ -1251,13 +1261,13 @@ namespace Sass { virtual size_t hash() { if (hash_ == 0) { - hash_ = std::hash()(type()); + hash_ = std::hash()(optype()); hash_combine(hash_, left()->hash()); hash_combine(hash_, right()->hash()); } return hash_; } - enum Sass_OP type() const { return op_.operand; } + enum Sass_OP optype() const { return op_.operand; } ATTACH_AST_OPERATIONS(Binary_Expression) ATTACH_OPERATIONS() }; @@ -1269,21 +1279,21 @@ namespace Sass { public: enum Type { PLUS, MINUS, NOT }; private: - ADD_HASHED(Type, type) - ADD_HASHED(Expression_Obj, operand) + HASH_PROPERTY(Type, optype) + HASH_PROPERTY(Expression_Obj, operand) size_t hash_; public: Unary_Expression(ParserState pstate, Type t, Expression_Obj o) - : Expression(pstate), type_(t), operand_(o), hash_(0) + : Expression(pstate), optype_(t), operand_(o), hash_(0) { } Unary_Expression(const Unary_Expression* ptr) : Expression(ptr), - type_(ptr->type_), + optype_(ptr->optype_), operand_(ptr->operand_), hash_(ptr->hash_) { } const std::string type_name() { - switch (type_) { + switch (optype_) { case PLUS: return "plus"; break; case MINUS: return "minus"; break; case NOT: return "not"; break; @@ -1294,10 +1304,10 @@ namespace Sass { { try { - Unary_Expression_Ptr_Const m = dynamic_cast(&rhs); + Unary_Expression_Ptr_Const m = Cast(&rhs); if (m == 0) return false; return type() == m->type() && - operand() == m->operand(); + *operand() == *m->operand(); } catch (std::bad_cast&) { @@ -1308,7 +1318,7 @@ namespace Sass { virtual size_t hash() { if (hash_ == 0) { - hash_ = std::hash()(type_); + hash_ = std::hash()(optype_); hash_combine(hash_, operand()->hash()); }; return hash_; @@ -1321,8 +1331,8 @@ namespace Sass { // Individual argument objects for mixin and function calls. //////////////////////////////////////////////////////////// class Argument : public Expression { - ADD_HASHED(Expression_Obj, value) - ADD_HASHED(std::string, name) + HASH_PROPERTY(Expression_Obj, value) + HASH_CONSTREF(std::string, name) ADD_PROPERTY(bool, is_rest_argument) ADD_PROPERTY(bool, is_keyword_argument) size_t hash_; @@ -1352,7 +1362,7 @@ namespace Sass { { try { - Argument_Ptr_Const m = dynamic_cast(&rhs); + Argument_Ptr_Const m = Cast(&rhs); if (!(m && name() == m->name())) return false; return *value() == *m->value(); } @@ -1416,8 +1426,8 @@ namespace Sass { // Function calls. ////////////////// class Function_Call : public PreValue { - ADD_HASHED(std::string, name) - ADD_HASHED(Arguments_Obj, arguments) + HASH_CONSTREF(std::string, name) + HASH_PROPERTY(Arguments_Obj, arguments) ADD_PROPERTY(bool, via_call) ADD_PROPERTY(void*, cookie) size_t hash_; @@ -1441,11 +1451,11 @@ namespace Sass { { try { - Function_Call_Ptr_Const m = dynamic_cast(&rhs); + Function_Call_Ptr_Const m = Cast(&rhs); if (!(m && name() == m->name())) return false; if (!(m && arguments()->length() == m->arguments()->length())) return false; for (size_t i =0, L = arguments()->length(); i < L; ++i) - if (!((*arguments())[i] == (*m->arguments())[i])) return false; + if (!(*(*arguments())[i] == *(*m->arguments())[i])) return false; return true; } catch (std::bad_cast&) @@ -1491,7 +1501,7 @@ namespace Sass { // Variable references. /////////////////////// class Variable : public PreValue { - ADD_PROPERTY(std::string, name) + ADD_CONSTREF(std::string, name) public: Variable(ParserState pstate, std::string n) : PreValue(pstate), name_(n) @@ -1504,7 +1514,7 @@ namespace Sass { { try { - Variable_Ptr_Const e = dynamic_cast(&rhs); + Variable_Ptr_Const e = Cast(&rhs); return e && name() == e->name(); } catch (std::bad_cast&) @@ -1531,17 +1541,17 @@ namespace Sass { public: enum Type { NUMBER, PERCENTAGE, DIMENSION, HEX }; private: - ADD_HASHED(Type, type) - ADD_HASHED(std::string, value) + HASH_PROPERTY(Type, valtype) + HASH_CONSTREF(std::string, value) size_t hash_; public: Textual(ParserState pstate, Type t, std::string val) - : Expression(pstate, DELAYED), type_(t), value_(val), + : Expression(pstate, DELAYED), valtype_(t), value_(val), hash_(0) { } Textual(const Textual* ptr) : Expression(ptr), - type_(ptr->type_), + valtype_(ptr->valtype_), value_(ptr->value_), hash_(ptr->hash_) { } @@ -1550,7 +1560,7 @@ namespace Sass { { try { - Textual_Ptr_Const e = dynamic_cast(&rhs); + Textual_Ptr_Const e = Cast(&rhs); return e && value() == e->value() && type() == e->type(); } catch (std::bad_cast&) @@ -1564,7 +1574,7 @@ namespace Sass { { if (hash_ == 0) { hash_ = std::hash()(value_); - hash_combine(hash_, std::hash()(type_)); + hash_combine(hash_, std::hash()(valtype_)); } return hash_; } @@ -1577,7 +1587,7 @@ namespace Sass { // Numbers, percentages, dimensions, and colors. //////////////////////////////////////////////// class Number : public Value { - ADD_HASHED(double, value) + HASH_PROPERTY(double, value) ADD_PROPERTY(bool, zero) std::vector numerator_units_; std::vector denominator_units_; @@ -1599,7 +1609,7 @@ namespace Sass { std::vector& denominator_units() { return denominator_units_; } const std::vector& numerator_units() const { return numerator_units_; } const std::vector& denominator_units() const { return denominator_units_; } - std::string type() { return "number"; } + std::string type() const { return "number"; } static std::string type_name() { return "number"; } std::string unit() const; @@ -1624,7 +1634,6 @@ namespace Sass { virtual bool operator< (const Number& rhs) const; virtual bool operator== (const Expression& rhs) const; - virtual bool eq(const Expression& rhs) const; ATTACH_AST_OPERATIONS(Number) ATTACH_OPERATIONS() }; @@ -1633,11 +1642,11 @@ namespace Sass { // Colors. ////////// class Color : public Value { - ADD_HASHED(double, r) - ADD_HASHED(double, g) - ADD_HASHED(double, b) - ADD_HASHED(double, a) - ADD_PROPERTY(std::string, disp) + HASH_PROPERTY(double, r) + HASH_PROPERTY(double, g) + HASH_PROPERTY(double, b) + HASH_PROPERTY(double, a) + ADD_CONSTREF(std::string, disp) size_t hash_; public: Color(ParserState pstate, double r, double g, double b, double a = 1, const std::string disp = "") @@ -1653,7 +1662,7 @@ namespace Sass { disp_(ptr->disp_), hash_(ptr->hash_) { concrete_type(COLOR); } - std::string type() { return "color"; } + std::string type() const { return "color"; } static std::string type_name() { return "color"; } virtual size_t hash() @@ -1677,7 +1686,7 @@ namespace Sass { // Errors from Sass_Values. ////////////////////////////// class Custom_Error : public Value { - ADD_PROPERTY(std::string, message) + ADD_CONSTREF(std::string, message) public: Custom_Error(ParserState pstate, std::string msg) : Value(pstate), message_(msg) @@ -1694,7 +1703,7 @@ namespace Sass { // Warnings from Sass_Values. ////////////////////////////// class Custom_Warning : public Value { - ADD_PROPERTY(std::string, message) + ADD_CONSTREF(std::string, message) public: Custom_Warning(ParserState pstate, std::string msg) : Value(pstate), message_(msg) @@ -1711,7 +1720,7 @@ namespace Sass { // Booleans. //////////// class Boolean : public Value { - ADD_HASHED(bool, value) + HASH_PROPERTY(bool, value) size_t hash_; public: Boolean(ParserState pstate, bool val) @@ -1724,7 +1733,7 @@ namespace Sass { hash_(ptr->hash_) { concrete_type(BOOLEAN); } virtual operator bool() { return value_; } - std::string type() { return "bool"; } + std::string type() const { return "bool"; } static std::string type_name() { return "bool"; } virtual bool is_false() { return !value_; } @@ -1757,8 +1766,6 @@ namespace Sass { static std::string type_name() { return "string"; } virtual ~String() = 0; virtual void rtrim() = 0; - virtual void ltrim() = 0; - virtual void trim() = 0; virtual bool operator==(const Expression& rhs) const = 0; virtual bool operator<(const Expression& rhs) const { return this->to_string() < rhs.to_string(); @@ -1785,7 +1792,7 @@ namespace Sass { hash_(ptr->hash_) { concrete_type(STRING); } - std::string type() { return "string"; } + std::string type() const { return "string"; } static std::string type_name() { return "string"; } bool is_left_interpolant(void) const; @@ -1798,8 +1805,6 @@ namespace Sass { return false; } virtual void rtrim(); - virtual void ltrim(); - virtual void trim(); virtual size_t hash() { @@ -1825,7 +1830,7 @@ namespace Sass { class String_Constant : public String { ADD_PROPERTY(char, quote_mark) ADD_PROPERTY(bool, can_compress_whitespace) - ADD_HASHED(std::string, value) + HASH_CONSTREF(std::string, value) protected: size_t hash_; public: @@ -1848,12 +1853,10 @@ namespace Sass { String_Constant(ParserState pstate, const Token& tok) : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(std::string(tok.begin, tok.end))), hash_(0) { } - std::string type() { return "string"; } + std::string type() const { return "string"; } static std::string type_name() { return "string"; } virtual bool is_invisible() const; virtual void rtrim(); - virtual void ltrim(); - virtual void trim(); virtual size_t hash() { @@ -2103,7 +2106,7 @@ namespace Sass { if (s->statement_type() == Statement::DIRECTIVE) { - if (Directive_Obj dir = SASS_MEMORY_CAST(Directive, s)) + if (Directive_Obj dir = Cast(s)) { std::string keyword(dir->keyword()); if (keyword.length() > 0) keyword.erase(0, 1); @@ -2122,7 +2125,7 @@ namespace Sass { { return expression()->exclude("supports"); } - if (Directive_Obj dir = SASS_MEMORY_CAST(Directive, s)) + if (Directive_Obj dir = Cast(s)) { if (dir->is_keyframes()) return expression()->exclude("keyframes"); } @@ -2139,7 +2142,7 @@ namespace Sass { public: Null(ParserState pstate) : Value(pstate) { concrete_type(NULL_VAL); } Null(const Null* ptr) : Value(ptr) { concrete_type(NULL_VAL); } - std::string type() { return "null"; } + std::string type() const { return "null"; } static std::string type_name() { return "null"; } bool is_invisible() const { return true; } operator bool() { return false; } @@ -2172,7 +2175,7 @@ namespace Sass { // Individual parameter objects for mixins and functions. ///////////////////////////////////////////////////////// class Parameter : public AST_Node { - ADD_PROPERTY(std::string, name) + ADD_CONSTREF(std::string, name) ADD_PROPERTY(Expression_Obj, default_value) ADD_PROPERTY(bool, is_rest_parameter) public: @@ -2180,9 +2183,11 @@ namespace Sass { std::string n, Expression_Obj def = 0, bool rest = false) : AST_Node(pstate), name_(n), default_value_(def), is_rest_parameter_(rest) { - if (default_value_ && is_rest_parameter_) { - error("variable-length parameter may not have a default value", pstate_); - } + // tried to come up with a spec test for this, but it does no longer + // get past the parser (it error out earlier). A spec test was added! + // if (default_value_ && is_rest_parameter_) { + // error("variable-length parameter may not have a default value", pstate_); + // } } Parameter(const Parameter* ptr) : AST_Node(ptr), @@ -2190,9 +2195,11 @@ namespace Sass { default_value_(ptr->default_value_), is_rest_parameter_(ptr->is_rest_parameter_) { - if (default_value_ && is_rest_parameter_) { - error("variable-length parameter may not have a default value", pstate_); - } + // tried to come up with a spec test for this, but it does no longer + // get past the parser (it error out earlier). A spec test was added! + // if (default_value_ && is_rest_parameter_) { + // error("variable-length parameter may not have a default value", pstate_); + // } } ATTACH_AST_OPERATIONS(Parameter) ATTACH_OPERATIONS() @@ -2266,9 +2273,8 @@ namespace Sass { protected: size_t hash_; public: - Selector(ParserState pstate, bool r = false, bool h = false) + Selector(ParserState pstate) : Expression(pstate), - // has_reference_(r), has_line_feed_(false), has_line_break_(false), is_optional_(false), @@ -2286,21 +2292,19 @@ namespace Sass { { concrete_type(SELECTOR); } virtual ~Selector() = 0; virtual size_t hash() = 0; - virtual unsigned long specificity() { - return 0; - } + virtual unsigned long specificity() const = 0; virtual void set_media_block(Media_Block_Ptr mb) { media_block(mb); } - virtual bool has_parent_ref() { + virtual bool has_parent_ref() const { return false; } - virtual bool has_real_parent_ref() { + virtual bool has_real_parent_ref() const { return false; } // dispatch to correct handlers - virtual bool operator<(const Selector& rhs) const; - virtual bool operator==(const Selector& rhs) const; + virtual bool operator<(const Selector& rhs) const = 0; + virtual bool operator==(const Selector& rhs) const = 0; ATTACH_VIRTUAL_AST_OPERATIONS(Selector); }; inline Selector::~Selector() { } @@ -2309,20 +2313,34 @@ namespace Sass { // Interpolated selectors -- the interpolated String will be expanded and // re-parsed into a normal selector class. ///////////////////////////////////////////////////////////////////////// - class Selector_Schema : public Selector { + class Selector_Schema : public AST_Node { ADD_PROPERTY(String_Obj, contents) - ADD_PROPERTY(bool, at_root); + ADD_PROPERTY(bool, connect_parent); + // must not be a reference counted object + // otherwise we create circular references + ADD_PROPERTY(Media_Block_Ptr, media_block) + // store computed hash + size_t hash_; public: Selector_Schema(ParserState pstate, String_Obj c) - : Selector(pstate), contents_(c), at_root_(false) + : AST_Node(pstate), + contents_(c), + connect_parent_(true), + media_block_(NULL) { } Selector_Schema(const Selector_Schema* ptr) - : Selector(ptr), + : AST_Node(ptr), contents_(ptr->contents_), - at_root_(ptr->at_root_) + connect_parent_(ptr->connect_parent_), + media_block_(ptr->media_block_) { } - virtual bool has_parent_ref(); - virtual bool has_real_parent_ref(); + virtual bool has_parent_ref() const; + virtual bool has_real_parent_ref() const; + virtual bool operator<(const Selector& rhs) const; + virtual bool operator==(const Selector& rhs) const; + // selector schema is not yet a final selector, so we do not + // have a specificity for it yet. We need to + virtual unsigned long specificity() const { return 0; } virtual size_t hash() { if (hash_ == 0) { hash_combine(hash_, contents_->hash()); @@ -2337,8 +2355,8 @@ namespace Sass { // Abstract base class for simple selectors. //////////////////////////////////////////// class Simple_Selector : public Selector { - ADD_PROPERTY(std::string, ns) - ADD_PROPERTY(std::string, name) + ADD_CONSTREF(std::string, ns) + ADD_CONSTREF(std::string, name) ADD_PROPERTY(Simple_Type, simple_type) ADD_PROPERTY(bool, has_ns) public: @@ -2360,10 +2378,6 @@ namespace Sass { name_(ptr->name_), has_ns_(ptr->has_ns_) { simple_type(SIMPLE); } - virtual bool unique() const - { - return false; - } virtual std::string ns_name() const { std::string name(""); @@ -2380,6 +2394,8 @@ namespace Sass { } return hash_; } + // namespace compare functions + bool is_ns_eq(const Simple_Selector& r) const; // namespace query functions bool is_universal_ns() const { @@ -2413,10 +2429,9 @@ namespace Sass { virtual ~Simple_Selector() = 0; virtual Compound_Selector_Ptr unify_with(Compound_Selector_Ptr, Context&); - virtual bool has_parent_ref() { return false; }; - virtual bool has_real_parent_ref() { return false; }; - virtual bool is_pseudo_element() { return false; } - virtual bool is_pseudo_class() { return false; } + virtual bool has_parent_ref() const { return false; }; + virtual bool has_real_parent_ref() const { return false; }; + virtual bool is_pseudo_element() const { return false; } virtual bool is_superselector_of(Compound_Selector_Obj sub) { return false; } @@ -2448,14 +2463,14 @@ namespace Sass { Parent_Selector(const Parent_Selector* ptr) : Simple_Selector(ptr), real_(ptr->real_) { /* has_reference(true); */ } - bool is_real_parent_ref() { return real(); }; - virtual bool has_parent_ref() { return true; }; - virtual bool has_real_parent_ref() { return is_real_parent_ref(); }; - virtual unsigned long specificity() + bool is_real_parent_ref() const { return real(); }; + virtual bool has_parent_ref() const { return true; }; + virtual bool has_real_parent_ref() const { return is_real_parent_ref(); }; + virtual unsigned long specificity() const { return 0; } - std::string type() { return "selector"; } + std::string type() const { return "selector"; } static std::string type_name() { return "selector"; } ATTACH_AST_OPERATIONS(Parent_Selector) ATTACH_OPERATIONS() @@ -2472,7 +2487,7 @@ namespace Sass { Placeholder_Selector(const Placeholder_Selector* ptr) : Simple_Selector(ptr) { } - virtual unsigned long specificity() + virtual unsigned long specificity() const { return Constants::Specificity_Base; } @@ -2495,7 +2510,7 @@ namespace Sass { Element_Selector(const Element_Selector* ptr) : Simple_Selector(ptr) { } - virtual unsigned long specificity() + virtual unsigned long specificity() const { if (name() == "*") return 0; else return Constants::Specificity_Element; @@ -2517,11 +2532,7 @@ namespace Sass { Class_Selector(const Class_Selector* ptr) : Simple_Selector(ptr) { } - virtual bool unique() const - { - return false; - } - virtual unsigned long specificity() + virtual unsigned long specificity() const { return Constants::Specificity_Class; } @@ -2541,11 +2552,7 @@ namespace Sass { Id_Selector(const Id_Selector* ptr) : Simple_Selector(ptr) { } - virtual bool unique() const - { - return true; - } - virtual unsigned long specificity() + virtual unsigned long specificity() const { return Constants::Specificity_ID; } @@ -2558,7 +2565,7 @@ namespace Sass { // Attribute selectors -- e.g., [src*=".jpg"], etc. /////////////////////////////////////////////////// class Attribute_Selector : public Simple_Selector { - ADD_PROPERTY(std::string, matcher) + ADD_CONSTREF(std::string, matcher) // this cannot be changed to obj atm!!!!!!????!!!!!!! ADD_PROPERTY(String_Obj, value) // might be interpolated public: @@ -2579,7 +2586,7 @@ namespace Sass { } return hash_; } - virtual unsigned long specificity() + virtual unsigned long specificity() const { return Constants::Specificity_Attr; } @@ -2617,14 +2624,6 @@ namespace Sass { : Simple_Selector(ptr), expression_(ptr->expression_) { simple_type(PSEUDO_SEL); } - // A pseudo-class always consists of a "colon" (:) followed by the name - // of the pseudo-class and optionally by a value between parentheses. - virtual bool is_pseudo_class() - { - return (name_[0] == ':' && name_[1] != ':') - && ! is_pseudo_class_element(name_); - } - // A pseudo-element is made of two colons (::) followed by the name. // The `::` notation is introduced by the current document in order to // establish a discrimination between pseudo-classes and pseudo-elements. @@ -2633,7 +2632,7 @@ namespace Sass { // in CSS levels 1 and 2 (namely, :first-line, :first-letter, :before and // :after). This compatibility is not allowed for the new pseudo-elements // introduced in this specification. - virtual bool is_pseudo_element() + virtual bool is_pseudo_element() const { return (name_[0] == ':' && name_[1] == ':') || is_pseudo_class_element(name_); @@ -2646,7 +2645,7 @@ namespace Sass { } return hash_; } - virtual unsigned long specificity() + virtual unsigned long specificity() const { if (is_pseudo_element()) return Constants::Specificity_Element; @@ -2665,9 +2664,9 @@ namespace Sass { // Wrapped selector -- pseudo selector that takes a list of selectors as argument(s) e.g., :not(:first-of-type), :-moz-any(ol p.blah, ul, menu, dir) ///////////////////////////////////////////////// class Wrapped_Selector : public Simple_Selector { - ADD_PROPERTY(Selector_Obj, selector) + ADD_PROPERTY(Selector_List_Obj, selector) public: - Wrapped_Selector(ParserState pstate, std::string n, Selector_Obj sel) + Wrapped_Selector(ParserState pstate, std::string n, Selector_List_Obj sel) : Simple_Selector(pstate, n), selector_(sel) { simple_type(WRAPPED_SEL); } Wrapped_Selector(const Wrapped_Selector* ptr) @@ -2676,28 +2675,10 @@ namespace Sass { virtual bool is_superselector_of(Wrapped_Selector_Obj sub); // Selectors inside the negation pseudo-class are counted like any // other, but the negation itself does not count as a pseudo-class. - virtual size_t hash() - { - if (hash_ == 0) { - hash_combine(hash_, Simple_Selector::hash()); - if (selector_) hash_combine(hash_, selector_->hash()); - } - return hash_; - } - virtual bool has_parent_ref() { - // if (has_reference()) return true; - if (!selector()) return false; - return selector()->has_parent_ref(); - } - virtual bool has_real_parent_ref() { - // if (has_reference()) return true; - if (!selector()) return false; - return selector()->has_real_parent_ref(); - } - virtual unsigned long specificity() - { - return selector_ ? selector_->specificity() : 0; - } + virtual size_t hash(); + virtual bool has_parent_ref() const; + virtual bool has_real_parent_ref() const; + virtual unsigned long specificity() const; virtual bool operator==(const Simple_Selector& rhs) const; virtual bool operator==(const Wrapped_Selector& rhs) const; virtual bool operator<(const Simple_Selector& rhs) const; @@ -2707,18 +2688,13 @@ namespace Sass { ATTACH_OPERATIONS() }; - struct Complex_Selector_Pointer_Compare { - bool operator() (const Complex_Selector_Obj& pLeft, const Complex_Selector_Obj& pRight) const; - }; - //////////////////////////////////////////////////////////////////////////// // Simple selector sequences. Maintains flags indicating whether it contains // any parent references or placeholders, to simplify expansion. //////////////////////////////////////////////////////////////////////////// - typedef std::set SourcesSet; class Compound_Selector : public Selector, public Vectorized { private: - SourcesSet sources_; + ComplexSelectorSet sources_; ADD_PROPERTY(bool, extended); ADD_PROPERTY(bool, has_parent_reference); protected: @@ -2757,18 +2733,13 @@ namespace Sass { Complex_Selector_Obj to_complex(); Compound_Selector_Ptr unify_with(Compound_Selector_Ptr rhs, Context& ctx); // virtual Placeholder_Selector_Ptr find_placeholder(); - virtual bool has_parent_ref(); - virtual bool has_real_parent_ref(); - Simple_Selector_Ptr base() - { - // Implement non-const in terms of const. Safe to const_cast since this method is non-const - return const_cast(static_cast(this)->base()); - } - Simple_Selector_Ptr_Const base() const { + virtual bool has_parent_ref() const; + virtual bool has_real_parent_ref() const; + Simple_Selector_Ptr base() const { if (length() == 0) return 0; // ToDo: why is this needed? - if (SASS_MEMORY_CAST(Element_Selector, (*this)[0])) - return &(*this)[0]; + if (Cast((*this)[0])) + return (*this)[0]; return 0; } virtual bool is_superselector_of(Compound_Selector_Obj sub, std::string wrapped = ""); @@ -2782,7 +2753,7 @@ namespace Sass { } return Selector::hash_; } - virtual unsigned long specificity() + virtual unsigned long specificity() const { int sum = 0; for (size_t i = 0, L = length(); i < L; ++i) @@ -2802,17 +2773,18 @@ namespace Sass { bool is_empty_reference() { return length() == 1 && - SASS_MEMORY_CAST(Parent_Selector, (*this)[0]); + Cast((*this)[0]); } - std::vector to_str_vec(); // sometimes need to convert to a flat "by-value" data structure + virtual bool operator<(const Selector& rhs) const; + virtual bool operator==(const Selector& rhs) const; virtual bool operator<(const Compound_Selector& rhs) const; virtual bool operator==(const Compound_Selector& rhs) const; inline bool operator!=(const Compound_Selector& rhs) const { return !(*this == rhs); } - SourcesSet& sources() { return sources_; } + ComplexSelectorSet& sources() { return sources_; } void clearSources() { sources_.clear(); } - void mergeSources(SourcesSet& sources, Context& ctx); + void mergeSources(ComplexSelectorSet& sources, Context& ctx); Compound_Selector_Ptr minus(Compound_Selector_Ptr rhs, Context& ctx); virtual void cloneChildren(); @@ -2829,10 +2801,10 @@ namespace Sass { public: enum Combinator { ANCESTOR_OF, PARENT_OF, PRECEDES, ADJACENT_TO, REFERENCE }; private: - ADD_PROPERTY(Combinator, combinator) - ADD_PROPERTY(Compound_Selector_Obj, head) - ADD_PROPERTY(Complex_Selector_Obj, tail) - ADD_PROPERTY(String_Obj, reference); + HASH_CONSTREF(Combinator, combinator) + HASH_PROPERTY(Compound_Selector_Obj, head) + HASH_PROPERTY(Complex_Selector_Obj, tail) + HASH_PROPERTY(String_Obj, reference); public: bool contains_placeholder() { if (head() && head()->contains_placeholder()) return true; @@ -2855,8 +2827,8 @@ namespace Sass { head_(ptr->head_), tail_(ptr->tail_), reference_(ptr->reference_) {}; - virtual bool has_parent_ref(); - virtual bool has_real_parent_ref(); + virtual bool has_parent_ref() const; + virtual bool has_real_parent_ref() const; Complex_Selector_Obj skip_empty_reference() { @@ -2878,9 +2850,6 @@ namespace Sass { combinator() == Combinator::ANCESTOR_OF; } - Complex_Selector_Obj context(Context&); - - Selector_List_Ptr tails(Context& ctx, Selector_List_Ptr tails); // front returns the first real tail @@ -2928,55 +2897,57 @@ namespace Sass { if (tail_ && tail_->has_placeholder()) return true; return false; } + virtual bool operator<(const Selector& rhs) const; + virtual bool operator==(const Selector& rhs) const; virtual bool operator<(const Complex_Selector& rhs) const; virtual bool operator==(const Complex_Selector& rhs) const; inline bool operator!=(const Complex_Selector& rhs) const { return !(*this == rhs); } - SourcesSet sources() + const ComplexSelectorSet sources() { //s = Set.new //seq.map {|sseq_or_op| s.merge sseq_or_op.sources if sseq_or_op.is_a?(SimpleSequence)} //s - SourcesSet srcs; + ComplexSelectorSet srcs; Compound_Selector_Obj pHead = head(); Complex_Selector_Obj pTail = tail(); if (pHead) { - SourcesSet& headSources = pHead->sources(); + const ComplexSelectorSet& headSources = pHead->sources(); srcs.insert(headSources.begin(), headSources.end()); } if (pTail) { - SourcesSet tailSources = pTail->sources(); + const ComplexSelectorSet& tailSources = pTail->sources(); srcs.insert(tailSources.begin(), tailSources.end()); } return srcs; } - void addSources(SourcesSet& sources, Context& ctx) { + void addSources(ComplexSelectorSet& sources, Context& ctx) { // members.map! {|m| m.is_a?(SimpleSequence) ? m.with_more_sources(sources) : m} Complex_Selector_Ptr pIter = this; while (pIter) { - Compound_Selector_Ptr pHead = &pIter->head(); + Compound_Selector_Ptr pHead = pIter->head(); if (pHead) { pHead->mergeSources(sources, ctx); } - pIter = &pIter->tail(); + pIter = pIter->tail(); } } void clearSources() { Complex_Selector_Ptr pIter = this; while (pIter) { - Compound_Selector_Ptr pHead = &pIter->head(); + Compound_Selector_Ptr pHead = pIter->head(); if (pHead) { pHead->clearSources(); } - pIter = &pIter->tail(); + pIter = pIter->tail(); } } @@ -2985,29 +2956,32 @@ namespace Sass { ATTACH_OPERATIONS() }; - typedef std::deque ComplexSelectorDeque; - /////////////////////////////////// // Comma-separated selector groups. /////////////////////////////////// class Selector_List : public Selector, public Vectorized { - ADD_PROPERTY(std::vector, wspace) + ADD_PROPERTY(Selector_Schema_Obj, schema) + ADD_CONSTREF(std::vector, wspace) protected: void adjust_after_pushing(Complex_Selector_Obj c); public: Selector_List(ParserState pstate, size_t s = 0) - : Selector(pstate), Vectorized(s), wspace_(0) + : Selector(pstate), + Vectorized(s), + schema_(NULL), + wspace_(0) { } Selector_List(const Selector_List* ptr) : Selector(ptr), Vectorized(*ptr), + schema_(ptr->schema_), wspace_(ptr->wspace_) { } - std::string type() { return "list"; } + std::string type() const { return "list"; } // remove parent selector references // basically unwraps parsed selectors - virtual bool has_parent_ref(); - virtual bool has_real_parent_ref(); + virtual bool has_parent_ref() const; + virtual bool has_real_parent_ref() const; void remove_parent_selectors(); Selector_List_Ptr resolve_parent_refs(Context& ctx, std::vector& pstack, bool implicit_parent = true); virtual bool is_superselector_of(Compound_Selector_Obj sub, std::string wrapping = ""); @@ -3015,6 +2989,7 @@ namespace Sass { virtual bool is_superselector_of(Selector_List_Obj sub, std::string wrapping = ""); Selector_List_Ptr unify_with(Selector_List_Ptr, Context&); void populate_extends(Selector_List_Obj, Context&, Subset_Map&); + Selector_List_Obj eval(Eval& eval); virtual size_t hash() { if (Selector::hash_ == 0) { @@ -3023,7 +2998,7 @@ namespace Sass { } return Selector::hash_; } - virtual unsigned long specificity() + virtual unsigned long specificity() const { unsigned long sum = 0; unsigned long specificity = 0; @@ -3057,24 +3032,6 @@ namespace Sass { ATTACH_OPERATIONS() }; - template - bool selectors_equal(const SelectorType& one, const SelectorType& two, bool simpleSelectorOrderDependent) { - // Test for equality among selectors while differentiating between checks that demand the underlying Simple_Selector - // ordering to be the same or not. This works because operator< (which doesn't make a whole lot of sense for selectors, but - // is required for proper stl collection ordering) is implemented using string comparision. This gives stable sorting - // behavior, and can be used to determine if the selectors would have exactly idential output. operator== matches the - // ruby sass implementations for eql, which sometimes perform order independent comparisions (like set comparisons of the - // members of a SimpleSequence (Compound_Selector)). - // - // Due to the reliance on operator== and operater< behavior, this templated method is currently only intended for - // use with Compound_Selector and Complex_Selector objects. - if (simpleSelectorOrderDependent) { - return !(one < two) && !(two < one); - } else { - return one == two; - } - } - // compare function for sorting and probably other other uses struct cmp_complex_selector { inline bool operator() (const Complex_Selector_Obj l, const Complex_Selector_Obj r) { return (*l < *r); } }; struct cmp_compound_selector { inline bool operator() (const Compound_Selector_Obj l, const Compound_Selector_Obj r) { return (*l < *r); } }; diff --git a/src/libsass/src/ast_def_macros.hpp b/src/libsass/src/ast_def_macros.hpp index f8124629a..0ff30d1e3 100755 --- a/src/libsass/src/ast_def_macros.hpp +++ b/src/libsass/src/ast_def_macros.hpp @@ -44,7 +44,7 @@ public:\ type name(type name##__) { return name##_ = name##__; }\ private: -#define ADD_HASHED(type, name)\ +#define HASH_PROPERTY(type, name)\ protected:\ type name##_;\ public:\ @@ -52,4 +52,20 @@ public:\ type name(type name##__) { hash_ = 0; return name##_ = name##__; }\ private: +#define ADD_CONSTREF(type, name) \ +protected: \ + type name##_; \ +public: \ + const type& name() const { return name##_; } \ + void name(type name##__) { name##_ = name##__; } \ +private: + +#define HASH_CONSTREF(type, name) \ +protected: \ + type name##_; \ +public: \ + const type& name() const { return name##_; } \ + void name(type name##__) { hash_ = 0; name##_ = name##__; } \ +private: + #endif diff --git a/src/libsass/src/ast_fwd_decl.cpp b/src/libsass/src/ast_fwd_decl.cpp new file mode 100755 index 000000000..c9c76727a --- /dev/null +++ b/src/libsass/src/ast_fwd_decl.cpp @@ -0,0 +1,29 @@ +#include "ast.hpp" + +namespace Sass { + + #define IMPLEMENT_BASE_CAST(T) \ + template<> \ + T* Cast(AST_Node* ptr) { \ + return dynamic_cast(ptr); \ + }; \ + \ + template<> \ + const T* Cast(const AST_Node* ptr) { \ + return dynamic_cast(ptr); \ + }; \ + + IMPLEMENT_BASE_CAST(AST_Node) + IMPLEMENT_BASE_CAST(Expression) + IMPLEMENT_BASE_CAST(Statement) + IMPLEMENT_BASE_CAST(Has_Block) + IMPLEMENT_BASE_CAST(PreValue) + IMPLEMENT_BASE_CAST(Value) + IMPLEMENT_BASE_CAST(List) + IMPLEMENT_BASE_CAST(String) + IMPLEMENT_BASE_CAST(String_Constant) + IMPLEMENT_BASE_CAST(Supports_Condition) + IMPLEMENT_BASE_CAST(Selector) + IMPLEMENT_BASE_CAST(Simple_Selector) + +} diff --git a/src/libsass/src/ast_fwd_decl.hpp b/src/libsass/src/ast_fwd_decl.hpp index 374ca9198..a92cac2b3 100755 --- a/src/libsass/src/ast_fwd_decl.hpp +++ b/src/libsass/src/ast_fwd_decl.hpp @@ -1,7 +1,11 @@ #ifndef SASS_AST_FWD_DECL_H #define SASS_AST_FWD_DECL_H +#include +#include +#include #include +#include #include #include #include @@ -353,37 +357,94 @@ namespace Sass { IMPL_MEM_OBJ(Complex_Selector); IMPL_MEM_OBJ(Selector_List); + // ########################################################################### + // Implement compare, order and hashing operations for AST Nodes + // ########################################################################### - struct HashExpression { - size_t operator() (Expression_Obj ex) const; + struct HashNodes { + template + size_t operator() (const T& ex) const { + return ex.isNull() ? 0 : ex->hash(); + } }; - struct CompareExpression { - bool operator()(const Expression_Obj& lhs, const Expression_Obj& rhs) const; + struct OrderNodes { + template + bool operator() (const T& lhs, const T& rhs) const { + return !lhs.isNull() && !rhs.isNull() && *lhs < *rhs; + } }; - - struct HashSimpleSelector { - size_t operator() (Simple_Selector_Obj ex) const; + struct CompareNodes { + template + bool operator() (const T& lhs, const T& rhs) const { + return !lhs.isNull() && !rhs.isNull() && *lhs == *rhs; + } }; - struct CompareSimpleSelector { - bool operator()(Simple_Selector_Obj lhs, Simple_Selector_Obj rhs) const; - }; + // ########################################################################### + // some often used typedefs + // ########################################################################### typedef std::unordered_map< Expression_Obj, // key Expression_Obj, // value - HashExpression, // hasher - CompareExpression // compare + HashNodes, // hasher + CompareNodes // compare > ExpressionMap; typedef std::unordered_set< Expression_Obj, // value - HashExpression, // hasher - CompareExpression // compare + HashNodes, // hasher + CompareNodes // compare > ExpressionSet; - typedef std::string Subset_Map_Key; - typedef std::vector Subset_Map_Arr; - typedef std::pair Subset_Map_Val; + typedef std::string SubSetMapKey; + typedef std::vector SubSetMapKeys; + + typedef std::pair SubSetMapPair; + typedef std::pair SubSetMapLookup; + typedef std::vector SubSetMapPairs; + typedef std::vector SubSetMapLookups; + + typedef std::pair SubSetMapResult; + typedef std::vector SubSetMapResults; + + typedef std::deque ComplexSelectorDeque; + typedef std::set SimpleSelectorSet; + typedef std::set ComplexSelectorSet; + typedef std::unordered_set SimpleSelectorDict; + + // ########################################################################### + // explicit type conversion functions + // ########################################################################### + + template + T* Cast(AST_Node* ptr); + + template + const T* Cast(const AST_Node* ptr); + + // sometimes you know the class you want to cast to is final + // in this case a simple typeid check is faster and safe to use + + #define DECLARE_BASE_CAST(T) \ + template<> T* Cast(AST_Node* ptr); \ + template<> const T* Cast(const AST_Node* ptr); \ + + // ########################################################################### + // implement specialization for final classes + // ########################################################################### + + DECLARE_BASE_CAST(AST_Node) + DECLARE_BASE_CAST(Expression) + DECLARE_BASE_CAST(Statement) + DECLARE_BASE_CAST(Has_Block) + DECLARE_BASE_CAST(PreValue) + DECLARE_BASE_CAST(Value) + DECLARE_BASE_CAST(List) + DECLARE_BASE_CAST(String) + DECLARE_BASE_CAST(String_Constant) + DECLARE_BASE_CAST(Supports_Condition) + DECLARE_BASE_CAST(Selector) + DECLARE_BASE_CAST(Simple_Selector) } diff --git a/src/libsass/src/backtrace.hpp b/src/libsass/src/backtrace.hpp index 884413589..213da2f86 100755 --- a/src/libsass/src/backtrace.hpp +++ b/src/libsass/src/backtrace.hpp @@ -21,7 +21,7 @@ namespace Sass { caller(c) { } - std::string to_string(bool warning = false) + const std::string to_string(bool warning = false) { size_t i = -1; std::stringstream ss; diff --git a/src/libsass/src/bind.cpp b/src/libsass/src/bind.cpp index bd9d7ad34..ea11041c2 100755 --- a/src/libsass/src/bind.cpp +++ b/src/libsass/src/bind.cpp @@ -16,7 +16,7 @@ namespace Sass { std::map param_map; for (size_t i = 0, L = as->length(); i < L; ++i) { - if (auto str = SASS_MEMORY_CAST(String_Quoted, (*as)[i]->value())) { + if (auto str = Cast((*as)[i]->value())) { // force optional quotes (only if needed) if (str->quote_mark()) { str->quote_mark('*'); @@ -42,7 +42,7 @@ namespace Sass { if (ip >= LP) { // skip empty rest arguments if (a->is_rest_argument()) { - if (List_Obj l = SASS_MEMORY_CAST(List, a->value())) { + if (List_Obj l = Cast(a->value())) { if (l->length() == 0) { ++ ia; continue; } @@ -61,7 +61,7 @@ namespace Sass { if (a->is_rest_argument()) { // We should always get a list for rest arguments - if (List_Obj rest = SASS_MEMORY_CAST(List, a->value())) { + if (List_Obj rest = Cast(a->value())) { // create a new list object for wrapped items List_Ptr arglist = SASS_MEMORY_NEW(List, p->pstate(), @@ -70,12 +70,12 @@ namespace Sass { true); // wrap each item from list as an argument for (Expression_Obj item : rest->elements()) { - if (Argument_Obj arg = SASS_MEMORY_CAST(Argument, item)) { + if (Argument_Obj arg = Cast(item)) { arglist->append(SASS_MEMORY_COPY(arg)); // copy } else { arglist->append(SASS_MEMORY_NEW(Argument, item->pstate(), - &item, + item, "", false, false)); @@ -93,9 +93,9 @@ namespace Sass { // expand keyword arguments into their parameters List_Ptr arglist = SASS_MEMORY_NEW(List, p->pstate(), 0, SASS_COMMA, true); env->local_frame()[p->name()] = arglist; - Map_Obj argmap = SASS_MEMORY_CAST(Map, a->value()); + Map_Obj argmap = Cast(a->value()); for (auto key : argmap->keys()) { - std::string name = unquote(SASS_MEMORY_CAST(String_Constant, key)->value()); + std::string name = unquote(Cast(key)->value()); arglist->append(SASS_MEMORY_NEW(Argument, key->pstate(), argmap->at(key), @@ -117,25 +117,25 @@ namespace Sass { // get and post inc a = (*as)[ia++]; // maybe we have another list as argument - List_Obj ls = SASS_MEMORY_CAST(List, a->value()); + List_Obj ls = Cast(a->value()); // skip any list completely if empty if (ls && ls->empty() && a->is_rest_argument()) continue; Expression_Obj value = a->value(); - if (Argument_Obj arg = SASS_MEMORY_CAST(Argument, value)) { - arglist->append(&arg); + if (Argument_Obj arg = Cast(value)) { + arglist->append(arg); } // check if we have rest argument else if (a->is_rest_argument()) { // preserve the list separator from rest args - if (List_Obj rest = SASS_MEMORY_CAST(List, a->value())) { + if (List_Obj rest = Cast(a->value())) { arglist->separator(rest->separator()); for (size_t i = 0, L = rest->size(); i < L; ++i) { Expression_Obj obj = rest->at(i); arglist->append(SASS_MEMORY_NEW(Argument, obj->pstate(), - &obj, + obj, "", false, false)); @@ -155,7 +155,7 @@ namespace Sass { } } // assign new arglist to environment - env->local_frame()[p->name()] = &arglist; + env->local_frame()[p->name()] = arglist; } // consumed parameter ++ip; @@ -166,7 +166,7 @@ namespace Sass { // If the current argument is the rest argument, extract a value for processing else if (a->is_rest_argument()) { // normal param and rest arg - List_Obj arglist = SASS_MEMORY_CAST(List, a->value()); + List_Obj arglist = Cast(a->value()); // empty rest arg - treat all args as default values if (!arglist->length()) { break; @@ -187,8 +187,8 @@ namespace Sass { } // otherwise move one of the rest args into the param, converting to argument if necessary Expression_Obj obj = arglist->at(0); - if (!(a = SASS_MEMORY_CAST(Argument, obj))) { - Expression_Ptr a_to_convert = &obj; + if (!(a = Cast(obj))) { + Expression_Ptr a_to_convert = obj; a = SASS_MEMORY_NEW(Argument, a_to_convert->pstate(), a_to_convert, @@ -202,17 +202,17 @@ namespace Sass { } } else if (a->is_keyword_argument()) { - Map_Obj argmap = SASS_MEMORY_CAST(Map, a->value()); + Map_Obj argmap = Cast(a->value()); for (auto key : argmap->keys()) { - std::string name = "$" + unquote(SASS_MEMORY_CAST(String_Constant, key)->value()); + std::string name = "$" + unquote(Cast(key)->value()); if (!param_map.count(name)) { std::stringstream msg; msg << callee << " has no parameter named " << name; error(msg.str(), a->pstate()); } - env->local_frame()[name] = &argmap->at(&key); + env->local_frame()[name] = argmap->at(key); } ++ia; continue; @@ -228,7 +228,7 @@ namespace Sass { error(msg.str(), a->pstate()); } // ordinal arg -- bind it to the next param - env->local_frame()[p->name()] = &a->value(); + env->local_frame()[p->name()] = a->value(); ++ip; } else { @@ -250,7 +250,7 @@ namespace Sass { << "provided more than once in call to " << callee; error(msg.str(), a->pstate()); } - env->local_frame()[a->name()] = &a->value(); + env->local_frame()[a->name()] = a->value(); } } // EO while ia diff --git a/src/libsass/src/bind.hpp b/src/libsass/src/bind.hpp index 4d17d0197..93a503aa6 100755 --- a/src/libsass/src/bind.hpp +++ b/src/libsass/src/bind.hpp @@ -6,7 +6,6 @@ #include "ast_fwd_decl.hpp" namespace Sass { - typedef Environment Env; void bind(std::string type, std::string name, Parameters_Obj, Arguments_Obj, Context*, Env*, Eval*); } diff --git a/src/libsass/src/check_nesting.cpp b/src/libsass/src/check_nesting.cpp index 5fc8542e3..5d0a8366e 100755 --- a/src/libsass/src/check_nesting.cpp +++ b/src/libsass/src/check_nesting.cpp @@ -15,7 +15,7 @@ namespace Sass { { Statement_Ptr old_parent = this->parent; - if (At_Root_Block_Ptr root = SASS_MEMORY_CAST_PTR(At_Root_Block, parent)) { + if (At_Root_Block_Ptr root = Cast(parent)) { std::vector old_parents = this->parents; std::vector new_parents; @@ -39,8 +39,8 @@ namespace Sass { } } - At_Root_Block_Ptr ar = SASS_MEMORY_CAST_PTR(At_Root_Block, parent); - Statement_Ptr ret = this->visit_children(&ar->block()); + At_Root_Block_Ptr ar = Cast(parent); + Statement_Ptr ret = this->visit_children(ar->block()); this->parent = old_parent; this->parents = old_parents; @@ -54,11 +54,11 @@ namespace Sass { this->parents.push_back(parent); - Block_Ptr b = SASS_MEMORY_CAST_PTR(Block, parent); + Block_Ptr b = Cast(parent); if (!b) { - if (Has_Block_Ptr bb = SASS_MEMORY_CAST(Has_Block, *parent)) { - b = &bb->block(); + if (Has_Block_Ptr bb = Cast(parent)) { + b = bb->block(); } } @@ -99,8 +99,8 @@ namespace Sass { Statement_Ptr CheckNesting::fallback_impl(Statement_Ptr s) { - Block_Ptr b1 = SASS_MEMORY_CAST_PTR(Block, s); - Has_Block_Ptr b2 = SASS_MEMORY_CAST_PTR(Has_Block, s); + Block_Ptr b1 = Cast(s); + Has_Block_Ptr b2 = Cast(s); return b1 || b2 ? visit_children(s) : s; } @@ -108,16 +108,16 @@ namespace Sass { { if (!this->parent) return true; - if (SASS_MEMORY_CAST_PTR(Content, node)) + if (Cast(node)) { this->invalid_content_parent(this->parent); } if (is_charset(node)) { this->invalid_charset_parent(this->parent); } - if (SASS_MEMORY_CAST_PTR(Extension, node)) + if (Cast(node)) { this->invalid_extend_parent(this->parent); } - // if (SASS_MEMORY_CAST(Import, node)) + // if (Cast(node)) // { this->invalid_import_parent(this->parent); } if (this->is_mixin(node)) @@ -129,13 +129,13 @@ namespace Sass { if (this->is_function(this->parent)) { this->invalid_function_child(node); } - if (SASS_MEMORY_CAST_PTR(Declaration, node)) + if (Cast(node)) { this->invalid_prop_parent(this->parent); } - if (SASS_MEMORY_CAST_PTR(Declaration, this->parent)) + if (Cast(this->parent)) { this->invalid_prop_child(node); } - if (SASS_MEMORY_CAST_PTR(Return, node)) + if (Cast(node)) { this->invalid_return_parent(this->parent); } return true; @@ -166,8 +166,8 @@ namespace Sass { void CheckNesting::invalid_extend_parent(Statement_Ptr parent) { if (!( - SASS_MEMORY_CAST_PTR(Ruleset, parent) || - SASS_MEMORY_CAST_PTR(Mixin_Call, parent) || + Cast(parent) || + Cast(parent) || is_mixin(parent) )) { throw Exception::InvalidSass( @@ -181,12 +181,12 @@ namespace Sass { // { // for (auto pp : this->parents) { // if ( - // SASS_MEMORY_CAST(Each, pp) || - // SASS_MEMORY_CAST(For, pp) || - // SASS_MEMORY_CAST(If, pp) || - // SASS_MEMORY_CAST(While, pp) || - // SASS_MEMORY_CAST(Trace, pp) || - // SASS_MEMORY_CAST(Mixin_Call, pp) || + // Cast(pp) || + // Cast(pp) || + // Cast(pp) || + // Cast(pp) || + // Cast(pp) || + // Cast(pp) || // is_mixin(pp) // ) { // throw Exception::InvalidSass( @@ -212,12 +212,12 @@ namespace Sass { { for (Statement_Ptr pp : this->parents) { if ( - SASS_MEMORY_CAST_PTR(Each, pp) || - SASS_MEMORY_CAST_PTR(For, pp) || - SASS_MEMORY_CAST_PTR(If, pp) || - SASS_MEMORY_CAST_PTR(While, pp) || - SASS_MEMORY_CAST_PTR(Trace, pp) || - SASS_MEMORY_CAST_PTR(Mixin_Call, pp) || + Cast(pp) || + Cast(pp) || + Cast(pp) || + Cast(pp) || + Cast(pp) || + Cast(pp) || is_mixin(pp) ) { throw Exception::InvalidSass( @@ -232,12 +232,12 @@ namespace Sass { { for (Statement_Ptr pp : this->parents) { if ( - SASS_MEMORY_CAST_PTR(Each, pp) || - SASS_MEMORY_CAST_PTR(For, pp) || - SASS_MEMORY_CAST_PTR(If, pp) || - SASS_MEMORY_CAST_PTR(While, pp) || - SASS_MEMORY_CAST_PTR(Trace, pp) || - SASS_MEMORY_CAST_PTR(Mixin_Call, pp) || + Cast(pp) || + Cast(pp) || + Cast(pp) || + Cast(pp) || + Cast(pp) || + Cast(pp) || is_mixin(pp) ) { throw Exception::InvalidSass( @@ -251,19 +251,19 @@ namespace Sass { void CheckNesting::invalid_function_child(Statement_Ptr child) { if (!( - SASS_MEMORY_CAST_PTR(Each, child) || - SASS_MEMORY_CAST_PTR(For, child) || - SASS_MEMORY_CAST_PTR(If, child) || - SASS_MEMORY_CAST_PTR(While, child) || - SASS_MEMORY_CAST_PTR(Trace, child) || - SASS_MEMORY_CAST_PTR(Comment, child) || - SASS_MEMORY_CAST_PTR(Debug, child) || - SASS_MEMORY_CAST_PTR(Return, child) || - SASS_MEMORY_CAST_PTR(Variable, child) || + Cast(child) || + Cast(child) || + Cast(child) || + Cast(child) || + Cast(child) || + Cast(child) || + Cast(child) || + Cast(child) || + Cast(child) || // Ruby Sass doesn't distinguish variables and assignments - SASS_MEMORY_CAST_PTR(Assignment, child) || - SASS_MEMORY_CAST_PTR(Warning, child) || - SASS_MEMORY_CAST_PTR(Error, child) + Cast(child) || + Cast(child) || + Cast(child) )) { throw Exception::InvalidSass( child->pstate(), @@ -275,14 +275,14 @@ namespace Sass { void CheckNesting::invalid_prop_child(Statement_Ptr child) { if (!( - SASS_MEMORY_CAST_PTR(Each, child) || - SASS_MEMORY_CAST_PTR(For, child) || - SASS_MEMORY_CAST_PTR(If, child) || - SASS_MEMORY_CAST_PTR(While, child) || - SASS_MEMORY_CAST_PTR(Trace, child) || - SASS_MEMORY_CAST_PTR(Comment, child) || - SASS_MEMORY_CAST_PTR(Declaration, child) || - SASS_MEMORY_CAST_PTR(Mixin_Call, child) + Cast(child) || + Cast(child) || + Cast(child) || + Cast(child) || + Cast(child) || + Cast(child) || + Cast(child) || + Cast(child) )) { throw Exception::InvalidSass( child->pstate(), @@ -296,10 +296,10 @@ namespace Sass { if (!( is_mixin(parent) || is_directive_node(parent) || - SASS_MEMORY_CAST_PTR(Ruleset, parent) || - SASS_MEMORY_CAST_PTR(Keyframe_Rule, parent) || - SASS_MEMORY_CAST_PTR(Declaration, parent) || - SASS_MEMORY_CAST_PTR(Mixin_Call, parent) + Cast(parent) || + Cast(parent) || + Cast(parent) || + Cast(parent) )) { throw Exception::InvalidSass( parent->pstate(), @@ -326,51 +326,51 @@ namespace Sass { !is_root_node(grandparent) && !is_at_root_node(grandparent); - return SASS_MEMORY_CAST_PTR(Import, parent) || - SASS_MEMORY_CAST_PTR(Each, parent) || - SASS_MEMORY_CAST_PTR(For, parent) || - SASS_MEMORY_CAST_PTR(If, parent) || - SASS_MEMORY_CAST_PTR(While, parent) || - SASS_MEMORY_CAST_PTR(Trace, parent) || + return Cast(parent) || + Cast(parent) || + Cast(parent) || + Cast(parent) || + Cast(parent) || + Cast(parent) || valid_bubble_node; } bool CheckNesting::is_charset(Statement_Ptr n) { - Directive_Ptr d = SASS_MEMORY_CAST_PTR(Directive, n); + Directive_Ptr d = Cast(n); return d && d->keyword() == "charset"; } bool CheckNesting::is_mixin(Statement_Ptr n) { - Definition_Ptr def = SASS_MEMORY_CAST_PTR(Definition, n); + Definition_Ptr def = Cast(n); return def && def->type() == Definition::MIXIN; } bool CheckNesting::is_function(Statement_Ptr n) { - Definition_Ptr def = SASS_MEMORY_CAST_PTR(Definition, n); + Definition_Ptr def = Cast(n); return def && def->type() == Definition::FUNCTION; } bool CheckNesting::is_root_node(Statement_Ptr n) { - if (SASS_MEMORY_CAST_PTR(Ruleset, n)) return false; + if (Cast(n)) return false; - Block_Ptr b = SASS_MEMORY_CAST_PTR(Block, n); + Block_Ptr b = Cast(n); return b && b->is_root(); } bool CheckNesting::is_at_root_node(Statement_Ptr n) { - return SASS_MEMORY_CAST_PTR(At_Root_Block, n) != NULL; + return Cast(n) != NULL; } bool CheckNesting::is_directive_node(Statement_Ptr n) { - return SASS_MEMORY_CAST_PTR(Directive, n) || - SASS_MEMORY_CAST_PTR(Import, n) || - SASS_MEMORY_CAST_PTR(Media_Block, n) || - SASS_MEMORY_CAST_PTR(Supports_Block, n); + return Cast(n) || + Cast(n) || + Cast(n) || + Cast(n); } } diff --git a/src/libsass/src/check_nesting.hpp b/src/libsass/src/check_nesting.hpp index c3a165a81..ec9ee2ae0 100755 --- a/src/libsass/src/check_nesting.hpp +++ b/src/libsass/src/check_nesting.hpp @@ -6,8 +6,6 @@ namespace Sass { - typedef Environment Env; - class CheckNesting : public Operation_CRTP { std::vector parents; @@ -27,7 +25,7 @@ namespace Sass { template Statement_Ptr fallback(U x) { - Statement_Ptr n = SASS_MEMORY_CAST_PTR(Statement, x); + Statement_Ptr n = Cast(x); if (this->should_visit(n)) { return fallback_impl(n); } diff --git a/src/libsass/src/color_maps.hpp b/src/libsass/src/color_maps.hpp index a225f42d9..d4fd41607 100755 --- a/src/libsass/src/color_maps.hpp +++ b/src/libsass/src/color_maps.hpp @@ -1,3 +1,4 @@ + #ifndef SASS_COLOR_MAPS_H #define SASS_COLOR_MAPS_H @@ -319,14 +320,11 @@ namespace Sass { extern const Color transparent; } - extern const std::map colors_to_names; - extern const std::map names_to_colors; - - extern Color_Ptr_Const name_to_color(const char*); - extern Color_Ptr_Const name_to_color(const std::string&); - extern const char* color_to_name(const int); - extern const char* color_to_name(const Color&); - extern const char* color_to_name(const double); + Color_Ptr_Const name_to_color(const char*); + Color_Ptr_Const name_to_color(const std::string&); + const char* color_to_name(const int); + const char* color_to_name(const Color&); + const char* color_to_name(const double); } diff --git a/src/libsass/src/context.cpp b/src/libsass/src/context.cpp index 91b69f310..42b41c364 100755 --- a/src/libsass/src/context.cpp +++ b/src/libsass/src/context.cpp @@ -87,8 +87,9 @@ namespace Sass { { - // add cwd to include paths - include_paths.push_back(CWD); + // Sass 3.4: The current working directory will no longer be placed onto the Sass load path by default. + // If you need the current working directory to be available, set SASS_PATH=. in your shell's environment. + // include_paths.push_back(CWD); // collect more paths from different options collect_include_paths(c_options.include_path); @@ -391,8 +392,8 @@ namespace Sass { String_Constant_Ptr loc = SASS_MEMORY_NEW(String_Constant, pstate, unquote(load_path)); Argument_Obj loc_arg = SASS_MEMORY_NEW(Argument, pstate, loc); Arguments_Obj loc_args = SASS_MEMORY_NEW(Arguments, pstate); - loc_args->append(&loc_arg); - Function_Call_Ptr new_url = SASS_MEMORY_NEW(Function_Call, pstate, "url", &loc_args); + loc_args->append(loc_arg); + Function_Call_Ptr new_url = SASS_MEMORY_NEW(Function_Call, pstate, "url", loc_args); imp->urls().push_back(new_url); } else { @@ -528,11 +529,11 @@ namespace Sass { Import_Obj imp = SASS_MEMORY_NEW(Import, pstate); // dispatch headers which will add custom functions // custom headers are added to the import instance - call_headers(entry_path, ctx_path, pstate, &imp); + call_headers(entry_path, ctx_path, pstate, imp); // increase head count to skip later head_imports += resources.size() - 1; // add the statement if we have urls - if (!imp->urls().empty()) root->append(&imp); + if (!imp->urls().empty()) root->append(imp); // process all other resources (add Import_Stub nodes) for (size_t i = 0, S = imp->incs().size(); i < S; ++i) { root->append(SASS_MEMORY_NEW(Import_Stub, pstate, imp->incs()[i])); @@ -650,24 +651,24 @@ namespace Sass { Cssize cssize(*this, &backtrace); CheckNesting check_nesting; // check nesting - check_nesting(&root); + check_nesting(root); // expand and eval the tree - root = expand(&root); + root = expand(root); // check nesting - check_nesting(&root); + check_nesting(root); // merge and bubble certain rules - root = cssize(&root); + root = cssize(root); // should we extend something? if (!subset_map.empty()) { // create crtp visitor object Extend extend(*this, subset_map); // extend tree nodes - extend(&root); + extend(root); } // clean up by removing empty placeholders // ToDo: maybe we can do this somewhere else? - Remove_Placeholders remove_placeholders(*this); + Remove_Placeholders remove_placeholders; root->perform(&remove_placeholders); // return processed tree return root; @@ -810,6 +811,7 @@ namespace Sass { register_function(ctx, append_sig, append, env); register_function(ctx, zip_sig, zip, env); register_function(ctx, list_separator_sig, list_separator, env); + register_function(ctx, is_bracketed_sig, is_bracketed, env); // Map Functions register_function(ctx, map_get_sig, map_get, env); register_function(ctx, map_merge_sig, map_merge, env); diff --git a/src/libsass/src/context.hpp b/src/libsass/src/context.hpp index 86c2e87cb..44a32ed06 100755 --- a/src/libsass/src/context.hpp +++ b/src/libsass/src/context.hpp @@ -50,6 +50,7 @@ namespace Sass { std::map sheets; Subset_Map subset_map; std::vector import_stack; + std::vector callee_stack; struct Sass_Compiler* c_compiler; diff --git a/src/libsass/src/cssize.cpp b/src/libsass/src/cssize.cpp index 63e6a7d58..ae112f391 100755 --- a/src/libsass/src/cssize.cpp +++ b/src/libsass/src/cssize.cpp @@ -38,10 +38,10 @@ namespace Sass { Statement_Ptr Cssize::operator()(Declaration_Ptr d) { - String_Obj property = SASS_MEMORY_CAST(String, d->property()); + String_Obj property = Cast(d->property()); - if (Declaration_Ptr dd = dynamic_cast(parent())) { - String_Obj parent_property = SASS_MEMORY_CAST(String, dd->property()); + if (Declaration_Ptr dd = Cast(parent())) { + String_Obj parent_property = Cast(dd->property()); property = SASS_MEMORY_NEW(String_Constant, d->property()->pstate(), parent_property->to_string() + "-" + property->to_string()); @@ -58,13 +58,13 @@ namespace Sass { dd->is_indented(d->is_indented()); dd->tabs(d->tabs()); - p_stack.push_back(&dd); - Block_Obj bb = d->block() ? operator()(&d->block()) : NULL; + p_stack.push_back(dd); + Block_Obj bb = d->block() ? operator()(d->block()) : NULL; p_stack.pop_back(); if (bb && bb->length()) { if (dd->value() && !dd->value()->is_invisible()) { - bb->unshift(&dd); + bb->unshift(dd); } return bb.detach(); } @@ -89,7 +89,7 @@ namespace Sass { r->pstate(), r->keyword(), r->selector(), - r->block() ? operator()(&r->block()) : 0); + r->block() ? operator()(r->block()) : 0); if (r->value()) rr->value(r->value()); p_stack.pop_back(); @@ -99,10 +99,10 @@ namespace Sass { Statement_Obj s = r->block()->at(i); if (s->statement_type() != Statement::BUBBLE) directive_exists = true; else { - Bubble_Obj s_obj = SASS_MEMORY_CAST(Bubble, s); + Bubble_Obj s_obj = Cast(s); s = s_obj->node(); if (s->statement_type() != Statement::DIRECTIVE) directive_exists = false; - else directive_exists = (static_cast(&s)->keyword() == rr->keyword()); + else directive_exists = (Cast(s)->keyword() == rr->keyword()); } } @@ -110,12 +110,14 @@ namespace Sass { Block_Ptr result = SASS_MEMORY_NEW(Block, rr->pstate()); if (!(directive_exists || rr->is_keyframes())) { - Directive_Ptr empty_node = SASS_MEMORY_CAST(Directive, rr); + Directive_Ptr empty_node = Cast(rr); empty_node->block(SASS_MEMORY_NEW(Block, rr->block() ? rr->block()->pstate() : rr->pstate())); result->append(empty_node); } - Block_Obj ss = debubble(rr->block() ? &rr->block() : SASS_MEMORY_NEW(Block, rr->pstate()), &rr); + Block_Obj db = rr->block(); + if (db.isNull()) db = SASS_MEMORY_NEW(Block, rr->pstate()); + Block_Obj ss = debubble(db, rr); for (size_t i = 0, L = ss->length(); i < L; ++i) { result->append(ss->at(i)); } @@ -129,10 +131,10 @@ namespace Sass { Keyframe_Rule_Obj rr = SASS_MEMORY_NEW(Keyframe_Rule, r->pstate(), - operator()(&r->block())); - if (&r->name()) rr->name(r->name()); + operator()(r->block())); + if (!r->name().isNull()) rr->name(r->name()); - return debubble(&rr->block(), &rr); + return debubble(rr->block(), rr); } Statement_Ptr Cssize::operator()(Ruleset_Ptr r) @@ -142,10 +144,10 @@ namespace Sass { // string schema is not a statement! // r->block() is already a string schema // and that is comming from propset expand - Block_Ptr bb = operator()(&r->block()); + Block_Ptr bb = operator()(r->block()); // this should protect us (at least a bit) from our mess // fixing this properly is harder that it should be ... - if (dynamic_cast(bb) == NULL) { + if (Cast(bb) == NULL) { error("Illegal nesting: Only properties may be nested beneath properties.", r->block()->pstate()); } Ruleset_Obj rr = SASS_MEMORY_NEW(Ruleset, @@ -165,7 +167,7 @@ namespace Sass { Block_Ptr rules = SASS_MEMORY_NEW(Block, rr->block()->pstate()); for (size_t i = 0, L = rr->block()->length(); i < L; i++) { - Statement_Ptr s = &rr->block()->at(i); + Statement_Ptr s = rr->block()->at(i); if (bubblable(s)) rules->append(s); if (!bubblable(s)) props->append(s); } @@ -173,16 +175,16 @@ namespace Sass { if (props->length()) { Block_Obj bb = SASS_MEMORY_NEW(Block, rr->block()->pstate()); - bb->concat(&props); + bb->concat(props); rr->block(bb); for (size_t i = 0, L = rules->length(); i < L; i++) { - Statement_Ptr stm = &rules->at(i); + Statement_Ptr stm = rules->at(i); stm->tabs(stm->tabs() + 1); } - rules->unshift(&rr); + rules->unshift(rr); } Block_Ptr ptr = rules; @@ -194,7 +196,7 @@ namespace Sass { } if (!(!rules->length() || - !bubblable(&rules->last()) || + !bubblable(rules->last()) || parent()->statement_type() == Statement::RULESET)) { rules->last()->group_end(true); @@ -219,13 +221,13 @@ namespace Sass { Media_Block_Obj mm = SASS_MEMORY_NEW(Media_Block, m->pstate(), - &m->media_queries(), - operator()(&m->block())); + m->media_queries(), + operator()(m->block())); mm->tabs(m->tabs()); p_stack.pop_back(); - return debubble(&mm->block(), &mm); + return debubble(mm->block(), mm); } Statement_Ptr Cssize::operator()(Supports_Block_Ptr m) @@ -240,13 +242,13 @@ namespace Sass { Supports_Block_Obj mm = SASS_MEMORY_NEW(Supports_Block, m->pstate(), - &m->condition(), - operator()(&m->block())); + m->condition(), + operator()(m->block())); mm->tabs(m->tabs()); p_stack.pop_back(); - return debubble(&mm->block(), &mm); + return debubble(mm->block(), mm); } Statement_Ptr Cssize::operator()(At_Root_Block_Ptr m) @@ -259,13 +261,13 @@ namespace Sass { if (!tmp) { - Block_Ptr bb = operator()(&m->block()); + Block_Ptr bb = operator()(m->block()); for (size_t i = 0, L = bb->length(); i < L; ++i) { // (bb->elements())[i]->tabs(m->tabs()); Statement_Obj stm = bb->at(i); - if (bubblable(&stm)) stm->tabs(stm->tabs() + m->tabs()); + if (bubblable(stm)) stm->tabs(stm->tabs() + m->tabs()); } - if (bb->length() && bubblable(&bb->last())) bb->last()->group_end(m->group_end()); + if (bb->length() && bubblable(bb->last())) bb->last()->group_end(m->group_end()); return bb; } @@ -280,13 +282,13 @@ namespace Sass { Statement_Ptr Cssize::bubble(Directive_Ptr m) { Block_Ptr bb = SASS_MEMORY_NEW(Block, this->parent()->pstate()); - Has_Block_Obj new_rule = static_cast(SASS_MEMORY_COPY(this->parent())); + Has_Block_Obj new_rule = Cast(SASS_MEMORY_COPY(this->parent())); new_rule->block(bb); new_rule->tabs(this->parent()->tabs()); - new_rule->block()->concat(&m->block()); + new_rule->block()->concat(m->block()); Block_Obj wrapper_block = SASS_MEMORY_NEW(Block, m->block() ? m->block()->pstate() : m->pstate()); - wrapper_block->append(&new_rule); + wrapper_block->append(new_rule); Directive_Obj mm = SASS_MEMORY_NEW(Directive, m->pstate(), m->keyword(), @@ -294,20 +296,20 @@ namespace Sass { wrapper_block); if (m->value()) mm->value(m->value()); - Bubble_Ptr bubble = SASS_MEMORY_NEW(Bubble, mm->pstate(), &mm); + Bubble_Ptr bubble = SASS_MEMORY_NEW(Bubble, mm->pstate(), mm); return bubble; } Statement_Ptr Cssize::bubble(At_Root_Block_Ptr m) { Block_Ptr bb = SASS_MEMORY_NEW(Block, this->parent()->pstate()); - Has_Block_Obj new_rule = static_cast(SASS_MEMORY_COPY(this->parent())); + Has_Block_Obj new_rule = Cast(SASS_MEMORY_COPY(this->parent())); new_rule->block(bb); new_rule->tabs(this->parent()->tabs()); - new_rule->block()->concat(&m->block()); + new_rule->block()->concat(m->block()); Block_Ptr wrapper_block = SASS_MEMORY_NEW(Block, m->block()->pstate()); - wrapper_block->append(&new_rule); + wrapper_block->append(new_rule); At_Root_Block_Ptr mm = SASS_MEMORY_NEW(At_Root_Block, m->pstate(), wrapper_block, @@ -318,7 +320,7 @@ namespace Sass { Statement_Ptr Cssize::bubble(Supports_Block_Ptr m) { - Ruleset_Obj parent = static_cast(SASS_MEMORY_COPY(this->parent())); + Ruleset_Obj parent = Cast(SASS_MEMORY_COPY(this->parent())); Block_Ptr bb = SASS_MEMORY_NEW(Block, parent->block()->pstate()); Ruleset_Ptr new_rule = SASS_MEMORY_NEW(Ruleset, @@ -326,13 +328,13 @@ namespace Sass { parent->selector(), bb); new_rule->tabs(parent->tabs()); - new_rule->block()->concat(&m->block()); + new_rule->block()->concat(m->block()); Block_Ptr wrapper_block = SASS_MEMORY_NEW(Block, m->block()->pstate()); wrapper_block->append(new_rule); Supports_Block_Ptr mm = SASS_MEMORY_NEW(Supports_Block, m->pstate(), - &m->condition(), + m->condition(), wrapper_block); mm->tabs(m->tabs()); @@ -343,7 +345,7 @@ namespace Sass { Statement_Ptr Cssize::bubble(Media_Block_Ptr m) { - Ruleset_Obj parent = static_cast(SASS_MEMORY_COPY(this->parent())); + Ruleset_Obj parent = Cast(SASS_MEMORY_COPY(this->parent())); Block_Ptr bb = SASS_MEMORY_NEW(Block, parent->block()->pstate()); Ruleset_Ptr new_rule = SASS_MEMORY_NEW(Ruleset, @@ -351,32 +353,31 @@ namespace Sass { parent->selector(), bb); new_rule->tabs(parent->tabs()); - new_rule->block()->concat(&m->block()); + new_rule->block()->concat(m->block()); Block_Ptr wrapper_block = SASS_MEMORY_NEW(Block, m->block()->pstate()); wrapper_block->append(new_rule); Media_Block_Obj mm = SASS_MEMORY_NEW(Media_Block, m->pstate(), - &m->media_queries(), - wrapper_block, - 0); + m->media_queries(), + wrapper_block); mm->tabs(m->tabs()); - return SASS_MEMORY_NEW(Bubble, mm->pstate(), &mm); + return SASS_MEMORY_NEW(Bubble, mm->pstate(), mm); } bool Cssize::bubblable(Statement_Ptr s) { - return dynamic_cast(s) || s->bubbles(); + return Cast(s) || s->bubbles(); } Block_Ptr Cssize::flatten(Block_Ptr b) { Block_Ptr result = SASS_MEMORY_NEW(Block, b->pstate(), 0, b->is_root()); for (size_t i = 0, L = b->length(); i < L; ++i) { - Statement_Ptr ss = &b->at(i); - if (Block_Ptr bb = SASS_MEMORY_CAST_PTR(Block, ss)) { + Statement_Ptr ss = b->at(i); + if (Block_Ptr bb = Cast(ss)) { Block_Obj bs = flatten(bb); for (size_t j = 0, K = bs->length(); j < K; ++j) { result->append(bs->at(j)); @@ -395,7 +396,7 @@ namespace Sass { for (size_t i = 0, L = b->length(); i < L; ++i) { Statement_Obj value = b->at(i); - bool key = dynamic_cast(&value) != NULL; + bool key = Cast(value) != NULL; if (!results.empty() && results.back().first == key) { @@ -424,17 +425,17 @@ namespace Sass { if (!is_bubble) { if (!parent) { - result->append(&slice); + result->append(slice); } else if (previous_parent) { - previous_parent->block()->concat(&slice); + previous_parent->block()->concat(slice); } else { - previous_parent = static_cast(SASS_MEMORY_COPY(parent)); + previous_parent = Cast(SASS_MEMORY_COPY(parent)); previous_parent->block(slice); previous_parent->tabs(parent->tabs()); - result->append(&previous_parent); + result->append(previous_parent); } continue; } @@ -444,25 +445,30 @@ namespace Sass { Statement_Ptr ss = NULL; Statement_Obj stm = slice->at(j); // this has to go now here (too bad) - Bubble_Obj node = SASS_MEMORY_CAST(Bubble, stm); + Bubble_Obj node = Cast(stm); Media_Block_Ptr m1 = NULL; Media_Block_Ptr m2 = NULL; - if (parent) m1 = SASS_MEMORY_CAST(Media_Block, *parent); - if (node) m2 = SASS_MEMORY_CAST(Media_Block, node->node()); + if (parent) m1 = Cast(parent); + if (node) m2 = Cast(node->node()); if (!parent || parent->statement_type() != Statement::MEDIA || node->node()->statement_type() != Statement::MEDIA || - (m1 && m2 && &m1->media_queries() == &m2->media_queries()) + (m1 && m2 && *m1->media_queries() == *m2->media_queries()) ) { - ss = &node->node(); + ss = node->node(); } else { - List_Obj mq = merge_media_queries(static_cast(&node->node()), static_cast(parent)); + List_Obj mq = merge_media_queries( + Cast(node->node()), + Cast(parent) + ); if (!mq->length()) continue; - static_cast(&node->node())->media_queries(mq); - ss = &node->node(); + if (Media_Block* b = Cast(node->node())) { + b->media_queries(mq); + } + ss = node->node(); } if (!ss) continue; @@ -483,7 +489,7 @@ namespace Sass { children->length(), children->is_root()); - Block_Ptr wrapper = flatten(&bb); + Block_Ptr wrapper = flatten(bb); wrapper_block->append(wrapper); if (wrapper->length()) { @@ -491,12 +497,12 @@ namespace Sass { } if (wrapper_block) { - result->append(&wrapper_block); + result->append(wrapper_block); } } } - return flatten(&result); + return flatten(result); } Statement_Ptr Cssize::fallback_impl(AST_Node_Ptr n) @@ -508,7 +514,7 @@ namespace Sass { { for (size_t i = 0, L = b->length(); i < L; ++i) { Statement_Obj ith = b->at(i)->perform(this); - if (Block_Ptr bb = SASS_MEMORY_CAST(Block, ith)) { + if (Block_Ptr bb = Cast(ith)) { for (size_t j = 0, K = bb->length(); j < K; ++j) { cur->append(bb->at(j)); } @@ -530,8 +536,8 @@ namespace Sass { for (size_t j = 0, K = m2->media_queries()->length(); j < K; j++) { Expression_Obj l1 = m1->media_queries()->at(i); Expression_Obj l2 = m2->media_queries()->at(j); - Media_Query_Ptr mq1 = SASS_MEMORY_CAST(Media_Query, l1); - Media_Query_Ptr mq2 = SASS_MEMORY_CAST(Media_Query, l2); + Media_Query_Ptr mq1 = Cast(l1); + Media_Query_Ptr mq2 = Cast(l2); Media_Query_Ptr mq = merge_media_query(mq1, mq2); if (mq) qq->append(mq); } @@ -548,9 +554,9 @@ namespace Sass { std::string mod; 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 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 t2 = &mq2->media_type() ? mq2->media_type()->to_string(ctx.c_options) : ""; + std::string t2 = mq2->media_type() ? mq2->media_type()->to_string(ctx.c_options) : ""; if (t1.empty()) t1 = t2; diff --git a/src/libsass/src/cssize.hpp b/src/libsass/src/cssize.hpp index 20b79668f..506b075f7 100755 --- a/src/libsass/src/cssize.hpp +++ b/src/libsass/src/cssize.hpp @@ -8,7 +8,6 @@ namespace Sass { - typedef Environment Env; struct Backtrace; class Cssize : public Operation_CRTP { diff --git a/src/libsass/src/debugger.hpp b/src/libsass/src/debugger.hpp index 9d38dd2ce..ea21ddbbc 100755 --- a/src/libsass/src/debugger.hpp +++ b/src/libsass/src/debugger.hpp @@ -10,11 +10,15 @@ using namespace Sass; inline void debug_ast(AST_Node_Ptr node, std::string ind = "", Env* env = 0); -inline void debug_sources_set(SourcesSet& set, std::string ind = "") +inline void debug_ast(const AST_Node* node, std::string ind = "", Env* env = 0) { + debug_ast(const_cast(node), ind, env); +} + +inline void debug_sources_set(ComplexSelectorSet& set, std::string ind = "") { if (ind == "") std::cerr << "#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; for(auto const &pair : set) { - debug_ast(&pair, ind + ""); + debug_ast(pair, ind + ""); // debug_ast(set[pair], ind + "first: "); } if (ind == "") std::cerr << "#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; @@ -64,30 +68,30 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) { if (node == 0) return; if (ind == "") std::cerr << "####################################################################\n"; - if (dynamic_cast(node)) { - Bubble_Ptr bubble = dynamic_cast(node); + if (Cast(node)) { + Bubble_Ptr bubble = Cast(node); std::cerr << ind << "Bubble " << bubble; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << bubble->tabs(); std::cerr << std::endl; - debug_ast(&bubble->node(), ind + " ", env); - } else if (dynamic_cast(node)) { - Trace_Ptr trace = dynamic_cast(node); + debug_ast(bubble->node(), ind + " ", env); + } else if (Cast(node)) { + Trace_Ptr trace = Cast(node); std::cerr << ind << "Trace " << trace; std::cerr << " (" << pstate_source_position(node) << ")" << " [name:" << trace->name() << "]" << std::endl; - debug_ast(&trace->block(), ind + " ", env); - } else if (dynamic_cast(node)) { - At_Root_Block_Ptr root_block = dynamic_cast(node); + debug_ast(trace->block(), ind + " ", env); + } else if (Cast(node)) { + At_Root_Block_Ptr root_block = Cast(node); std::cerr << ind << "At_Root_Block " << root_block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << root_block->tabs(); std::cerr << std::endl; - debug_ast(&root_block->expression(), ind + ":", env); - debug_ast(&root_block->block(), ind + " ", env); - } else if (dynamic_cast(node)) { - Selector_List_Ptr selector = dynamic_cast(node); + debug_ast(root_block->expression(), ind + ":", env); + debug_ast(root_block->block(), ind + " ", env); + } else if (Cast(node)) { + Selector_List_Ptr selector = Cast(node); std::cerr << ind << "Selector_List " << selector; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " <" << selector->hash() << ">"; @@ -99,15 +103,16 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) std::cerr << (selector->has_line_break() ? " [line-break]": " -"); std::cerr << (selector->has_line_feed() ? " [line-feed]": " -"); std::cerr << std::endl; + debug_ast(selector->schema(), "#{} "); - for(const Complex_Selector_Obj& i : selector->elements()) { debug_ast(&i, ind + " ", env); } + for(const Complex_Selector_Obj& i : selector->elements()) { debug_ast(i, ind + " ", env); } -// } else if (dynamic_cast(node)) { -// Expression_Ptr expression = dynamic_cast(node); +// } else if (Cast(node)) { +// Expression_Ptr expression = Cast(node); // std::cerr << ind << "Expression " << expression << " " << expression->concrete_type() << std::endl; - } else if (dynamic_cast(node)) { - Parent_Selector_Ptr selector = dynamic_cast(node); + } else if (Cast(node)) { + Parent_Selector_Ptr selector = Cast(node); std::cerr << ind << "Parent_Selector " << selector; // if (selector->not_selector()) cerr << " [in_declaration]"; std::cerr << " (" << pstate_source_position(node) << ")"; @@ -116,8 +121,8 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) std::cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << std::endl; // debug_ast(selector->selector(), ind + "->", env); - } else if (dynamic_cast(node)) { - Complex_Selector_Ptr selector = dynamic_cast(node); + } else if (Cast(node)) { + Complex_Selector_Ptr selector = Cast(node); std::cerr << ind << "Complex_Selector " << selector << " (" << pstate_source_position(node) << ")" << " <" << selector->hash() << ">" @@ -141,16 +146,16 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) } // if (del = "/") del += selector->reference()->perform(&to_string) + "/"; std::cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << std::endl; - debug_ast(&selector->head(), ind + " " /* + "[" + del + "]" */, env); + debug_ast(selector->head(), ind + " " /* + "[" + del + "]" */, env); if (selector->tail()) { - debug_ast(&selector->tail(), ind + "{" + del + "}", env); + debug_ast(selector->tail(), ind + "{" + del + "}", env); } else if(del != " ") { std::cerr << ind << " |" << del << "| {trailing op}" << std::endl; } - SourcesSet set = selector->sources(); + ComplexSelectorSet set = selector->sources(); // debug_sources_set(set, ind + " @--> "); - } else if (dynamic_cast(node)) { - Compound_Selector_Ptr selector = dynamic_cast(node); + } else if (Cast(node)) { + Compound_Selector_Ptr selector = Cast(node); std::cerr << ind << "Compound_Selector " << selector; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " <" << selector->hash() << ">"; @@ -162,9 +167,9 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) std::cerr << (selector->has_line_break() ? " [line-break]": " -"); std::cerr << (selector->has_line_feed() ? " [line-feed]": " -"); std::cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << std::endl; - for(const Simple_Selector_Obj& i : selector->elements()) { debug_ast(&i, ind + " ", env); } - } else if (dynamic_cast(node)) { - Wrapped_Selector_Ptr selector = dynamic_cast(node); + for(const Simple_Selector_Obj& i : selector->elements()) { debug_ast(i, ind + " ", env); } + } else if (Cast(node)) { + Wrapped_Selector_Ptr selector = Cast(node); std::cerr << ind << "Wrapped_Selector " << selector; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " <" << selector->hash() << ">"; @@ -174,9 +179,9 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) std::cerr << (selector->has_line_break() ? " [line-break]": " -"); std::cerr << (selector->has_line_feed() ? " [line-feed]": " -"); std::cerr << std::endl; - debug_ast(&selector->selector(), ind + " () ", env); - } else if (dynamic_cast(node)) { - Pseudo_Selector_Ptr selector = dynamic_cast(node); + debug_ast(selector->selector(), ind + " () ", env); + } else if (Cast(node)) { + Pseudo_Selector_Ptr selector = Cast(node); std::cerr << ind << "Pseudo_Selector " << selector; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " <" << selector->hash() << ">"; @@ -186,9 +191,9 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) std::cerr << (selector->has_line_break() ? " [line-break]": " -"); std::cerr << (selector->has_line_feed() ? " [line-feed]": " -"); std::cerr << std::endl; - debug_ast(&selector->expression(), ind + " <= ", env); - } else if (dynamic_cast(node)) { - Attribute_Selector_Ptr selector = dynamic_cast(node); + debug_ast(selector->expression(), ind + " <= ", env); + } else if (Cast(node)) { + Attribute_Selector_Ptr selector = Cast(node); std::cerr << ind << "Attribute_Selector " << selector; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " <" << selector->hash() << ">"; @@ -198,9 +203,9 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) std::cerr << (selector->has_line_break() ? " [line-break]": " -"); std::cerr << (selector->has_line_feed() ? " [line-feed]": " -"); std::cerr << std::endl; - debug_ast(&selector->value(), ind + "[" + selector->matcher() + "] ", env); - } else if (dynamic_cast(node)) { - Class_Selector_Ptr selector = dynamic_cast(node); + debug_ast(selector->value(), ind + "[" + selector->matcher() + "] ", env); + } else if (Cast(node)) { + Class_Selector_Ptr selector = Cast(node); std::cerr << ind << "Class_Selector " << selector; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " <" << selector->hash() << ">"; @@ -210,8 +215,8 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) std::cerr << (selector->has_line_break() ? " [line-break]": " -"); std::cerr << (selector->has_line_feed() ? " [line-feed]": " -"); std::cerr << std::endl; - } else if (dynamic_cast(node)) { - Id_Selector_Ptr selector = dynamic_cast(node); + } else if (Cast(node)) { + Id_Selector_Ptr selector = Cast(node); std::cerr << ind << "Id_Selector " << selector; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " <" << selector->hash() << ">"; @@ -221,8 +226,8 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) std::cerr << (selector->has_line_break() ? " [line-break]": " -"); std::cerr << (selector->has_line_feed() ? " [line-feed]": " -"); std::cerr << std::endl; - } else if (dynamic_cast(node)) { - Element_Selector_Ptr selector = dynamic_cast(node); + } else if (Cast(node)) { + Element_Selector_Ptr selector = Cast(node); std::cerr << ind << "Element_Selector " << selector; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " <" << selector->hash() << ">"; @@ -233,9 +238,9 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) std::cerr << (selector->has_line_feed() ? " [line-feed]": " -"); std::cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">"; std::cerr << std::endl; - } else if (dynamic_cast(node)) { + } else if (Cast(node)) { - Placeholder_Selector_Ptr selector = dynamic_cast(node); + Placeholder_Selector_Ptr selector = Cast(node); std::cerr << ind << "Placeholder_Selector [" << selector->ns_name() << "] " << selector; std::cerr << " (" << pstate_source_position(selector) << ")" << " <" << selector->hash() << ">" @@ -245,212 +250,210 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) << (selector->has_line_feed() ? " [line-feed]": " -") << std::endl; - } else if (dynamic_cast(node)) { - Simple_Selector* selector = dynamic_cast(node); + } else if (Cast(node)) { + Simple_Selector* selector = Cast(node); std::cerr << ind << "Simple_Selector " << selector; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << std::endl; - } else if (dynamic_cast(node)) { - Selector_Schema_Ptr selector = dynamic_cast(node); + } else if (Cast(node)) { + Selector_Schema_Ptr selector = Cast(node); std::cerr << ind << "Selector_Schema " << selector; std::cerr << " (" << pstate_source_position(node) << ")" - << (selector->at_root() && selector->at_root() ? " [@ROOT]" : "") << " [@media:" << selector->media_block() << "]" - << (selector->has_line_break() ? " [line-break]": " -") - << (selector->has_line_feed() ? " [line-feed]": " -") + << (selector->connect_parent() ? " [connect-parent]": " -") << std::endl; - debug_ast(&selector->contents(), ind + " "); + debug_ast(selector->contents(), ind + " "); // for(auto i : selector->elements()) { debug_ast(i, ind + " ", env); } - } else if (dynamic_cast(node)) { - Selector_Ptr selector = dynamic_cast(node); + } else if (Cast(node)) { + Selector_Ptr selector = Cast(node); std::cerr << ind << "Selector " << selector; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << std::endl; - } else if (dynamic_cast(node)) { - Media_Query_Expression_Ptr block = dynamic_cast(node); + } else if (Cast(node)) { + Media_Query_Expression_Ptr block = Cast(node); std::cerr << ind << "Media_Query_Expression " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << (block->is_interpolated() ? " [is_interpolated]": " -") << std::endl; - debug_ast(&block->feature(), ind + " feature) "); - debug_ast(&block->value(), ind + " value) "); + debug_ast(block->feature(), ind + " feature) "); + debug_ast(block->value(), ind + " value) "); - } else if (dynamic_cast(node)) { - Media_Query_Ptr block = dynamic_cast(node); + } else if (Cast(node)) { + Media_Query_Ptr block = Cast(node); std::cerr << ind << "Media_Query " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << (block->is_negated() ? " [is_negated]": " -") << (block->is_restricted() ? " [is_restricted]": " -") << std::endl; - debug_ast(&block->media_type(), ind + " "); - for(const auto& i : block->elements()) { debug_ast(&i, ind + " ", env); } + debug_ast(block->media_type(), ind + " "); + for(const auto& i : block->elements()) { debug_ast(i, ind + " ", env); } - } else if (dynamic_cast(node)) { - Media_Block_Ptr block = dynamic_cast(node); + } else if (Cast(node)) { + Media_Block_Ptr block = Cast(node); std::cerr << ind << "Media_Block " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; - debug_ast(&block->media_queries(), ind + " =@ "); - if (block->block()) for(const Statement_Obj& i : block->block()->elements()) { debug_ast(&i, ind + " ", env); } - } else if (dynamic_cast(node)) { - Supports_Block_Ptr block = dynamic_cast(node); + debug_ast(block->media_queries(), ind + " =@ "); + if (block->block()) for(const Statement_Obj& i : block->block()->elements()) { debug_ast(i, ind + " ", env); } + } else if (Cast(node)) { + Supports_Block_Ptr block = Cast(node); std::cerr << ind << "Supports_Block " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; - debug_ast(&block->condition(), ind + " =@ "); - debug_ast(&block->block(), ind + " <>"); - } else if (dynamic_cast(node)) { - Supports_Operator_Ptr block = dynamic_cast(node); + debug_ast(block->condition(), ind + " =@ "); + debug_ast(block->block(), ind + " <>"); + } else if (Cast(node)) { + Supports_Operator_Ptr block = Cast(node); std::cerr << ind << "Supports_Operator " << block; std::cerr << " (" << pstate_source_position(node) << ")" << std::endl; - debug_ast(&block->left(), ind + " left) "); - debug_ast(&block->right(), ind + " right) "); - } else if (dynamic_cast(node)) { - Supports_Negation_Ptr block = dynamic_cast(node); + debug_ast(block->left(), ind + " left) "); + debug_ast(block->right(), ind + " right) "); + } else if (Cast(node)) { + Supports_Negation_Ptr block = Cast(node); std::cerr << ind << "Supports_Negation " << block; std::cerr << " (" << pstate_source_position(node) << ")" << std::endl; - debug_ast(&block->condition(), ind + " condition) "); - } else if (dynamic_cast(node)) { - At_Root_Query_Ptr block = dynamic_cast(node); + debug_ast(block->condition(), ind + " condition) "); + } else if (Cast(node)) { + At_Root_Query_Ptr block = Cast(node); std::cerr << ind << "At_Root_Query " << block; std::cerr << " (" << pstate_source_position(node) << ")" << std::endl; - debug_ast(&block->feature(), ind + " feature) "); - debug_ast(&block->value(), ind + " value) "); - } else if (dynamic_cast(node)) { - Supports_Declaration_Ptr block = dynamic_cast(node); + debug_ast(block->feature(), ind + " feature) "); + debug_ast(block->value(), ind + " value) "); + } else if (Cast(node)) { + Supports_Declaration_Ptr block = Cast(node); std::cerr << ind << "Supports_Declaration " << block; std::cerr << " (" << pstate_source_position(node) << ")" << std::endl; - debug_ast(&block->feature(), ind + " feature) "); - debug_ast(&block->value(), ind + " value) "); - } else if (dynamic_cast(node)) { - Block_Ptr root_block = dynamic_cast(node); + debug_ast(block->feature(), ind + " feature) "); + debug_ast(block->value(), ind + " value) "); + } else if (Cast(node)) { + Block_Ptr root_block = Cast(node); std::cerr << ind << "Block " << root_block; std::cerr << " (" << pstate_source_position(node) << ")"; if (root_block->is_root()) std::cerr << " [root]"; std::cerr << " " << root_block->tabs() << std::endl; - for(const Statement_Obj& i : root_block->elements()) { debug_ast(&i, ind + " ", env); } - } else if (dynamic_cast(node)) { - Warning_Ptr block = dynamic_cast(node); + for(const Statement_Obj& i : root_block->elements()) { debug_ast(i, ind + " ", env); } + } else if (Cast(node)) { + Warning_Ptr block = Cast(node); std::cerr << ind << "Warning " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; - debug_ast(&block->message(), ind + " : "); - } else if (dynamic_cast(node)) { - Error_Ptr block = dynamic_cast(node); + debug_ast(block->message(), ind + " : "); + } else if (Cast(node)) { + Error_Ptr block = Cast(node); std::cerr << ind << "Error " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; - } else if (dynamic_cast(node)) { - Debug_Ptr block = dynamic_cast(node); + } else if (Cast(node)) { + Debug_Ptr block = Cast(node); std::cerr << ind << "Debug " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; - debug_ast(&block->value(), ind + " "); - } else if (dynamic_cast(node)) { - Comment_Ptr block = dynamic_cast(node); + debug_ast(block->value(), ind + " "); + } else if (Cast(node)) { + Comment_Ptr block = Cast(node); std::cerr << ind << "Comment " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << " <" << prettyprint(block->pstate().token.ws_before()) << ">" << std::endl; - debug_ast(&block->text(), ind + "// ", env); - } else if (dynamic_cast(node)) { - If_Ptr block = dynamic_cast(node); + debug_ast(block->text(), ind + "// ", env); + } else if (Cast(node)) { + If_Ptr block = Cast(node); std::cerr << ind << "If " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; - debug_ast(&block->predicate(), ind + " = "); - debug_ast(&block->block(), ind + " <>"); - debug_ast(&block->alternative(), ind + " ><"); - } else if (dynamic_cast(node)) { - Return_Ptr block = dynamic_cast(node); + debug_ast(block->predicate(), ind + " = "); + debug_ast(block->block(), ind + " <>"); + debug_ast(block->alternative(), ind + " ><"); + } else if (Cast(node)) { + Return_Ptr block = Cast(node); std::cerr << ind << "Return " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; - } else if (dynamic_cast(node)) { - Extension_Ptr block = dynamic_cast(node); + } else if (Cast(node)) { + Extension_Ptr block = Cast(node); std::cerr << ind << "Extension " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; - debug_ast(&block->selector(), ind + "-> ", env); - } else if (dynamic_cast(node)) { - Content_Ptr block = dynamic_cast(node); + debug_ast(block->selector(), ind + "-> ", env); + } else if (Cast(node)) { + Content_Ptr block = Cast(node); std::cerr << ind << "Content " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [@media:" << block->media_block() << "]"; std::cerr << " " << block->tabs() << std::endl; - } else if (dynamic_cast(node)) { - Import_Stub_Ptr block = dynamic_cast(node); + } else if (Cast(node)) { + Import_Stub_Ptr block = Cast(node); std::cerr << ind << "Import_Stub " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [" << block->imp_path() << "] "; std::cerr << " " << block->tabs() << std::endl; - } else if (dynamic_cast(node)) { - Import_Ptr block = dynamic_cast(node); + } else if (Cast(node)) { + Import_Ptr block = Cast(node); std::cerr << ind << "Import " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; // std::vector files_; - for (auto imp : block->urls()) debug_ast(&imp, ind + "@: ", env); - debug_ast(&block->import_queries(), ind + "@@ "); - } else if (dynamic_cast(node)) { - Assignment_Ptr block = dynamic_cast(node); + for (auto imp : block->urls()) debug_ast(imp, ind + "@: ", env); + debug_ast(block->import_queries(), ind + "@@ "); + } else if (Cast(node)) { + Assignment_Ptr block = Cast(node); std::cerr << ind << "Assignment " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " <<" << block->variable() << ">> " << block->tabs() << std::endl; - debug_ast(&block->value(), ind + "=", env); - } else if (dynamic_cast(node)) { - Declaration_Ptr block = dynamic_cast(node); + debug_ast(block->value(), ind + "=", env); + } else if (Cast(node)) { + Declaration_Ptr block = Cast(node); std::cerr << ind << "Declaration " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; - debug_ast(&block->property(), ind + " prop: ", env); - debug_ast(&block->value(), ind + " value: ", env); - debug_ast(&block->block(), ind + " ", env); - } else if (dynamic_cast(node)) { - Keyframe_Rule_Ptr has_block = dynamic_cast(node); + debug_ast(block->property(), ind + " prop: ", env); + debug_ast(block->value(), ind + " value: ", env); + debug_ast(block->block(), ind + " ", env); + } else if (Cast(node)) { + Keyframe_Rule_Ptr has_block = Cast(node); std::cerr << ind << "Keyframe_Rule " << has_block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << has_block->tabs() << std::endl; - if (has_block->name()) debug_ast(&has_block->name(), ind + "@"); - if (has_block->block()) for(const Statement_Obj& i : has_block->block()->elements()) { debug_ast(&i, ind + " ", env); } - } else if (dynamic_cast(node)) { - Directive_Ptr block = dynamic_cast(node); + if (has_block->name()) debug_ast(has_block->name(), ind + "@"); + if (has_block->block()) for(const Statement_Obj& i : has_block->block()->elements()) { debug_ast(i, ind + " ", env); } + } else if (Cast(node)) { + Directive_Ptr block = Cast(node); std::cerr << ind << "Directive " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [" << block->keyword() << "] " << block->tabs() << std::endl; - debug_ast(&block->selector(), ind + "~", env); - debug_ast(&block->value(), ind + "+", env); - if (block->block()) for(const Statement_Obj& i : block->block()->elements()) { debug_ast(&i, ind + " ", env); } - } else if (dynamic_cast(node)) { - Each_Ptr block = dynamic_cast(node); + debug_ast(block->selector(), ind + "~", env); + debug_ast(block->value(), ind + "+", env); + if (block->block()) for(const Statement_Obj& i : block->block()->elements()) { debug_ast(i, ind + " ", env); } + } else if (Cast(node)) { + Each_Ptr block = Cast(node); std::cerr << ind << "Each " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; - if (block->block()) for(const Statement_Obj& i : block->block()->elements()) { debug_ast(&i, ind + " ", env); } - } else if (dynamic_cast(node)) { - For_Ptr block = dynamic_cast(node); + if (block->block()) for(const Statement_Obj& i : block->block()->elements()) { debug_ast(i, ind + " ", env); } + } else if (Cast(node)) { + For_Ptr block = Cast(node); std::cerr << ind << "For " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; - if (block->block()) for(const Statement_Obj& i : block->block()->elements()) { debug_ast(&i, ind + " ", env); } - } else if (dynamic_cast(node)) { - While_Ptr block = dynamic_cast(node); + if (block->block()) for(const Statement_Obj& i : block->block()->elements()) { debug_ast(i, ind + " ", env); } + } else if (Cast(node)) { + While_Ptr block = Cast(node); std::cerr << ind << "While " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; - if (block->block()) for(const Statement_Obj& i : block->block()->elements()) { debug_ast(&i, ind + " ", env); } - } else if (dynamic_cast(node)) { - Definition_Ptr block = dynamic_cast(node); + if (block->block()) for(const Statement_Obj& i : block->block()->elements()) { debug_ast(i, ind + " ", env); } + } else if (Cast(node)) { + Definition_Ptr block = Cast(node); std::cerr << ind << "Definition " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [name: " << block->name() << "] "; @@ -459,35 +462,34 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) // std::cerr << " [signature: " << block->signature() << "] "; std::cerr << " [native: " << block->native_function() << "] "; std::cerr << " " << block->tabs() << std::endl; - debug_ast(&block->parameters(), ind + " params: ", env); - if (block->block()) debug_ast(&block->block(), ind + " ", env); - } else if (dynamic_cast(node)) { - Mixin_Call_Ptr block = dynamic_cast(node); + debug_ast(block->parameters(), ind + " params: ", env); + if (block->block()) debug_ast(block->block(), ind + " ", env); + } else if (Cast(node)) { + Mixin_Call_Ptr block = Cast(node); std::cerr << ind << "Mixin_Call " << block << " " << block->tabs(); std::cerr << " (" << pstate_source_position(block) << ")"; std::cerr << " [" << block->name() << "]"; std::cerr << " [has_content: " << block->has_content() << "] " << std::endl; - debug_ast(&block->arguments(), ind + " args: "); - if (block->block()) debug_ast(&block->block(), ind + " ", env); - } else if (Ruleset_Ptr ruleset = dynamic_cast(node)) { + debug_ast(block->arguments(), ind + " args: "); + if (block->block()) debug_ast(block->block(), ind + " ", env); + } else if (Ruleset_Ptr ruleset = Cast(node)) { std::cerr << ind << "Ruleset " << ruleset; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [indent: " << ruleset->tabs() << "]"; std::cerr << (ruleset->is_invisible() ? " [INVISIBLE]" : ""); - std::cerr << (ruleset->at_root() ? " [@ROOT]" : ""); std::cerr << (ruleset->is_root() ? " [root]" : ""); std::cerr << std::endl; - debug_ast(&ruleset->selector(), ind + ">"); - debug_ast(&ruleset->block(), ind + " "); - } else if (dynamic_cast(node)) { - Block_Ptr block = dynamic_cast(node); + debug_ast(ruleset->selector(), ind + ">"); + debug_ast(ruleset->block(), ind + " "); + } else if (Cast(node)) { + Block_Ptr block = Cast(node); std::cerr << ind << "Block " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << (block->is_invisible() ? " [INVISIBLE]" : ""); std::cerr << " [indent: " << block->tabs() << "]" << std::endl; - for(const Statement_Obj& i : block->elements()) { debug_ast(&i, ind + " ", env); } - } else if (dynamic_cast(node)) { - Textual_Ptr expression = dynamic_cast(node); + for(const Statement_Obj& i : block->elements()) { debug_ast(i, ind + " ", env); } + } else if (Cast(node)) { + Textual_Ptr expression = Cast(node); std::cerr << ind << "Textual " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; if (expression->type() == Textual::NUMBER) std::cerr << " [NUMBER]"; @@ -498,24 +500,24 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) std::cerr << " [interpolant: " << expression->is_interpolant() << "] "; if (expression->is_delayed()) std::cerr << " [delayed]"; std::cerr << std::endl; - } else if (dynamic_cast(node)) { - Variable_Ptr expression = dynamic_cast(node); + } else if (Cast(node)) { + Variable_Ptr expression = Cast(node); std::cerr << ind << "Variable " << expression; std::cerr << " [interpolant: " << expression->is_interpolant() << "] "; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [" << expression->name() << "]" << std::endl; std::string name(expression->name()); - if (env && env->has(name)) debug_ast(SASS_MEMORY_CAST(Expression, (*env)[name]), ind + " -> ", env); - } else if (dynamic_cast(node)) { - Function_Call_Schema_Ptr expression = dynamic_cast(node); + if (env && env->has(name)) debug_ast(Cast((*env)[name]), ind + " -> ", env); + } else if (Cast(node)) { + Function_Call_Schema_Ptr expression = Cast(node); std::cerr << ind << "Function_Call_Schema " << expression; std::cerr << " [interpolant: " << expression->is_interpolant() << "] "; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << "" << std::endl; - debug_ast(&expression->name(), ind + "name: ", env); - debug_ast(&expression->arguments(), ind + " args: ", env); - } else if (dynamic_cast(node)) { - Function_Call_Ptr expression = dynamic_cast(node); + debug_ast(expression->name(), ind + "name: ", env); + debug_ast(expression->arguments(), ind + " args: ", env); + } else if (Cast(node)) { + Function_Call_Ptr expression = Cast(node); std::cerr << ind << "Function_Call " << expression; std::cerr << " [interpolant: " << expression->is_interpolant() << "] "; std::cerr << " (" << pstate_source_position(node) << ")"; @@ -523,9 +525,9 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) if (expression->is_delayed()) std::cerr << " [delayed]"; if (expression->is_interpolant()) std::cerr << " [interpolant]"; std::cerr << std::endl; - debug_ast(&expression->arguments(), ind + " args: ", env); - } else if (dynamic_cast(node)) { - Arguments_Ptr expression = dynamic_cast(node); + debug_ast(expression->arguments(), ind + " args: ", env); + } else if (Cast(node)) { + Arguments_Ptr expression = Cast(node); std::cerr << ind << "Arguments " << expression; if (expression->is_delayed()) std::cerr << " [delayed]"; std::cerr << " (" << pstate_source_position(node) << ")"; @@ -533,41 +535,41 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) if (expression->has_rest_argument()) std::cerr << " [has_rest_argument]"; if (expression->has_keyword_argument()) std::cerr << " [has_keyword_argument]"; std::cerr << std::endl; - for(const Argument_Obj& i : expression->elements()) { debug_ast(&i, ind + " ", env); } - } else if (dynamic_cast(node)) { - Argument_Ptr expression = dynamic_cast(node); + for(const Argument_Obj& i : expression->elements()) { debug_ast(i, ind + " ", env); } + } else if (Cast(node)) { + Argument_Ptr expression = Cast(node); std::cerr << ind << "Argument " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; - std::cerr << " [" << expression->value() << "]"; + std::cerr << " [" << expression->value().ptr() << "]"; std::cerr << " [name: " << expression->name() << "] "; std::cerr << " [rest: " << expression->is_rest_argument() << "] "; std::cerr << " [keyword: " << expression->is_keyword_argument() << "] " << std::endl; - debug_ast(&expression->value(), ind + " value: ", env); - } else if (dynamic_cast(node)) { - Parameters_Ptr expression = dynamic_cast(node); + debug_ast(expression->value(), ind + " value: ", env); + } else if (Cast(node)) { + Parameters_Ptr expression = Cast(node); std::cerr << ind << "Parameters " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [has_optional: " << expression->has_optional_parameters() << "] "; std::cerr << " [has_rest: " << expression->has_rest_parameter() << "] "; std::cerr << std::endl; - for(const Parameter_Obj& i : expression->elements()) { debug_ast(&i, ind + " ", env); } - } else if (dynamic_cast(node)) { - Parameter_Ptr expression = dynamic_cast(node); + for(const Parameter_Obj& i : expression->elements()) { debug_ast(i, ind + " ", env); } + } else if (Cast(node)) { + Parameter_Ptr expression = Cast(node); std::cerr << ind << "Parameter " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [name: " << expression->name() << "] "; - std::cerr << " [default: " << expression->default_value() << "] "; + std::cerr << " [default: " << expression->default_value().ptr() << "] "; std::cerr << " [rest: " << expression->is_rest_parameter() << "] " << std::endl; - } else if (dynamic_cast(node)) { - Unary_Expression_Ptr expression = dynamic_cast(node); + } else if (Cast(node)) { + Unary_Expression_Ptr expression = Cast(node); std::cerr << ind << "Unary_Expression " << expression; std::cerr << " [interpolant: " << expression->is_interpolant() << "] "; std::cerr << " [delayed: " << expression->is_delayed() << "] "; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [" << expression->type() << "]" << std::endl; - debug_ast(&expression->operand(), ind + " operand: ", env); - } else if (dynamic_cast(node)) { - Binary_Expression_Ptr expression = dynamic_cast(node); + debug_ast(expression->operand(), ind + " operand: ", env); + } else if (Cast(node)) { + Binary_Expression_Ptr expression = Cast(node); std::cerr << ind << "Binary_Expression " << expression; if (expression->is_interpolant()) std::cerr << " [is interpolant] "; if (expression->is_left_interpolant()) std::cerr << " [left interpolant] "; @@ -577,67 +579,69 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) std::cerr << " [ws_after: " << expression->op().ws_after << "] "; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [" << expression->type_name() << "]" << std::endl; - debug_ast(&expression->left(), ind + " left: ", env); - debug_ast(&expression->right(), ind + " right: ", env); - } else if (dynamic_cast(node)) { - Map_Ptr expression = dynamic_cast(node); + debug_ast(expression->left(), ind + " left: ", env); + debug_ast(expression->right(), ind + " right: ", env); + } else if (Cast(node)) { + Map_Ptr expression = Cast(node); std::cerr << ind << "Map " << expression; std::cerr << " [interpolant: " << expression->is_interpolant() << "] "; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [Hashed]" << std::endl; for (const auto& i : expression->elements()) { - debug_ast(&i.first, ind + " key: "); - debug_ast(&i.second, ind + " val: "); + debug_ast(i.first, ind + " key: "); + debug_ast(i.second, ind + " val: "); } - } else if (dynamic_cast(node)) { - List_Ptr expression = dynamic_cast(node); + } else if (Cast(node)) { + List_Ptr expression = Cast(node); std::cerr << ind << "List " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " (" << expression->length() << ") " << - (expression->separator() == SASS_COMMA ? "Comma " : expression->separator() == SASS_HASH ? "Map" : "Space ") << + (expression->separator() == SASS_COMMA ? "Comma " : expression->separator() == SASS_HASH ? "Map " : "Space ") << " [delayed: " << expression->is_delayed() << "] " << " [interpolant: " << expression->is_interpolant() << "] " << " [listized: " << expression->from_selector() << "] " << " [arglist: " << expression->is_arglist() << "] " << + " [bracketed: " << expression->is_bracketed() << "] " << + " [expanded: " << expression->is_expanded() << "] " << " [hash: " << expression->hash() << "] " << std::endl; - for(const auto& i : expression->elements()) { debug_ast(&i, ind + " ", env); } - } else if (dynamic_cast(node)) { - Content_Ptr expression = dynamic_cast(node); + for(const auto& i : expression->elements()) { debug_ast(i, ind + " ", env); } + } else if (Cast(node)) { + Content_Ptr expression = Cast(node); std::cerr << ind << "Content " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [@media:" << expression->media_block() << "]"; std::cerr << " [Statement]" << std::endl; - } else if (dynamic_cast(node)) { - Boolean_Ptr expression = dynamic_cast(node); + } else if (Cast(node)) { + Boolean_Ptr expression = Cast(node); std::cerr << ind << "Boolean " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [interpolant: " << expression->is_interpolant() << "] "; std::cerr << " [" << expression->value() << "]" << std::endl; - } else if (dynamic_cast(node)) { - Color_Ptr expression = dynamic_cast(node); + } else if (Cast(node)) { + Color_Ptr expression = Cast(node); std::cerr << ind << "Color " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [delayed: " << expression->is_delayed() << "] "; std::cerr << " [interpolant: " << expression->is_interpolant() << "] "; std::cerr << " [" << expression->r() << ":" << expression->g() << ":" << expression->b() << "@" << expression->a() << "]" << std::endl; - } else if (dynamic_cast(node)) { - Number_Ptr expression = dynamic_cast(node); + } else if (Cast(node)) { + Number_Ptr expression = Cast(node); std::cerr << ind << "Number " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [interpolant: " << expression->is_interpolant() << "] "; std::cerr << " [" << expression->value() << expression->unit() << "]" << " [hash: " << expression->hash() << "] " << std::endl; - } else if (dynamic_cast(node)) { - Null_Ptr expression = dynamic_cast(node); + } else if (Cast(node)) { + Null_Ptr expression = Cast(node); std::cerr << ind << "Null " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [interpolant: " << expression->is_interpolant() << "] " // " [hash: " << expression->hash() << "] " << std::endl; - } else if (dynamic_cast(node)) { - String_Quoted_Ptr expression = dynamic_cast(node); + } else if (Cast(node)) { + String_Quoted_Ptr expression = Cast(node); std::cerr << ind << "String_Quoted " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [" << prettyprint(expression->value()) << "]"; @@ -645,8 +649,8 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) if (expression->is_interpolant()) std::cerr << " [interpolant]"; if (expression->quote_mark()) std::cerr << " [quote_mark: " << expression->quote_mark() << "]"; std::cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << std::endl; - } else if (dynamic_cast(node)) { - String_Constant_Ptr expression = dynamic_cast(node); + } else if (Cast(node)) { + String_Constant_Ptr expression = Cast(node); std::cerr << ind << "String_Constant " << expression; if (expression->concrete_type()) { std::cerr << " " << expression->concrete_type(); @@ -656,8 +660,8 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) if (expression->is_delayed()) std::cerr << " [delayed]"; if (expression->is_interpolant()) std::cerr << " [interpolant]"; std::cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << std::endl; - } else if (dynamic_cast(node)) { - String_Schema_Ptr expression = dynamic_cast(node); + } else if (Cast(node)) { + String_Schema_Ptr expression = Cast(node); std::cerr << ind << "String_Schema " << expression; std::cerr << " (" << pstate_source_position(expression) << ")"; std::cerr << " " << expression->concrete_type(); @@ -668,16 +672,16 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) if (expression->is_left_interpolant()) std::cerr << " [left interpolant] "; if (expression->is_right_interpolant()) std::cerr << " [right interpolant] "; std::cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << std::endl; - for(const auto& i : expression->elements()) { debug_ast(&i, ind + " ", env); } - } else if (dynamic_cast(node)) { - String_Ptr expression = dynamic_cast(node); + for(const auto& i : expression->elements()) { debug_ast(i, ind + " ", env); } + } else if (Cast(node)) { + String_Ptr expression = Cast(node); std::cerr << ind << "String " << expression; std::cerr << " " << expression->concrete_type(); std::cerr << " (" << pstate_source_position(node) << ")"; if (expression->is_interpolant()) std::cerr << " [interpolant]"; std::cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << std::endl; - } else if (dynamic_cast(node)) { - Expression_Ptr expression = dynamic_cast(node); + } else if (Cast(node)) { + Expression_Ptr expression = Cast(node); std::cerr << ind << "Expression " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; switch (expression->concrete_type()) { @@ -696,14 +700,14 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) case Expression::Concrete_Type::NUM_TYPES: std::cerr << " [NUM_TYPES]"; break; } std::cerr << std::endl; - } else if (dynamic_cast(node)) { - Has_Block_Ptr has_block = dynamic_cast(node); + } else if (Cast(node)) { + Has_Block_Ptr has_block = Cast(node); std::cerr << ind << "Has_Block " << has_block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << has_block->tabs() << std::endl; - if (has_block->block()) for(const Statement_Obj& i : has_block->block()->elements()) { debug_ast(&i, ind + " ", env); } - } else if (dynamic_cast(node)) { - Statement_Ptr statement = dynamic_cast(node); + if (has_block->block()) for(const Statement_Obj& i : has_block->block()->elements()) { debug_ast(i, ind + " ", env); } + } else if (Cast(node)) { + Statement_Ptr statement = Cast(node); std::cerr << ind << "Statement " << statement; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << statement->tabs() << std::endl; @@ -735,7 +739,7 @@ inline void debug_node(Node* node, std::string ind = "") std::cerr << node << " "; if (node->got_line_feed) std::cerr << "[LF] "; std::cerr << std::endl; - debug_ast(&node->selector(), ind + " "); + debug_ast(node->selector(), ind + " "); } else if (node->isCollection()) { std::cerr << ind; std::cerr << "Collection "; @@ -776,21 +780,18 @@ inline void debug_subset_map(Sass::Subset_Map& map, std::string ind = "") { if (ind == "") std::cerr << "#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; for(auto const &it : map.values()) { - debug_ast(&it.first, ind + "first: "); - debug_ast(&it.second, ind + "second: "); + debug_ast(it.first, ind + "first: "); + debug_ast(it.second, ind + "second: "); } if (ind == "") std::cerr << "#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; } -typedef std::pair ExtensionPair; -typedef std::vector SubsetMapEntries; - -inline void debug_subset_entries(SubsetMapEntries* entries, std::string ind = "") +inline void debug_subset_entries(SubSetMapPairs* entries, std::string ind = "") { if (ind == "") std::cerr << "#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; for(auto const &pair : *entries) { - debug_ast(&pair.first, ind + "first: "); - debug_ast(&pair.second, ind + "second: "); + debug_ast(pair.first, ind + "first: "); + debug_ast(pair.second, ind + "second: "); } if (ind == "") std::cerr << "#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; } diff --git a/src/libsass/src/environment.cpp b/src/libsass/src/environment.cpp index 083a53cc6..7a7e9b1d1 100755 --- a/src/libsass/src/environment.cpp +++ b/src/libsass/src/environment.cpp @@ -178,8 +178,8 @@ namespace Sass { std::cerr << prefix << std::string(indent, ' ') << "== " << this << std::endl; for (typename std::map::iterator i = local_frame_.begin(); i != local_frame_.end(); ++i) { if (!ends_with(i->first, "[f]") && !ends_with(i->first, "[f]4") && !ends_with(i->first, "[f]2")) { - std::cerr << prefix << std::string(indent, ' ') << i->first << " " << i->second; - if (Value_Ptr val = SASS_MEMORY_CAST_PTR(Value, i->second)) + std::cerr << prefix << std::string(indent, ' ') << i->first << " " << i->second; + if (Value_Ptr val = Cast(i->second)) { std::cerr << " : " << val->to_string(); } std::cerr << std::endl; } diff --git a/src/libsass/src/environment.hpp b/src/libsass/src/environment.hpp index 199b690db..dd985b15c 100755 --- a/src/libsass/src/environment.hpp +++ b/src/libsass/src/environment.hpp @@ -87,6 +87,9 @@ namespace Sass { }; + // define typedef for our use case + typedef Environment Env; + } #endif diff --git a/src/libsass/src/eval.cpp b/src/libsass/src/eval.cpp index 2ab20c90e..219d47e45 100755 --- a/src/libsass/src/eval.cpp +++ b/src/libsass/src/eval.cpp @@ -24,6 +24,7 @@ #include "parser.hpp" #include "expand.hpp" #include "color_maps.hpp" +#include "sass_functions.hpp" namespace Sass { @@ -86,7 +87,7 @@ namespace Sass { if (a->is_global()) { if (a->is_default()) { if (env->has_global(var)) { - Expression_Ptr e = SASS_MEMORY_CAST(Expression, env->get_global(var)); + Expression_Ptr e = Cast(env->get_global(var)); if (!e || e->concrete_type() == Expression::NULL_VAL) { env->set_global(var, a->value()->perform(this)); } @@ -105,7 +106,7 @@ namespace Sass { while (cur && cur->is_lexical()) { if (cur->has_local(var)) { if (AST_Node_Obj node = cur->get_local(var)) { - Expression_Ptr e = SASS_MEMORY_CAST(Expression, node); + Expression_Ptr e = Cast(node); if (!e || e->concrete_type() == Expression::NULL_VAL) { cur->set_local(var, a->value()->perform(this)); } @@ -121,7 +122,7 @@ namespace Sass { } else if (env->has_global(var)) { if (AST_Node_Obj node = env->get_global(var)) { - Expression_Ptr e = SASS_MEMORY_CAST(Expression, node); + Expression_Ptr e = Cast(node); if (!e || e->concrete_type() == Expression::NULL_VAL) { env->set_global(var, a->value()->perform(this)); } @@ -170,8 +171,8 @@ namespace Sass { if (high->concrete_type() != Expression::NUMBER) { throw Exception::TypeMismatch(*high, "integer"); } - Number_Obj sass_start = SASS_MEMORY_CAST(Number, low); - Number_Obj sass_end = SASS_MEMORY_CAST(Number, high); + Number_Obj sass_start = Cast(low); + Number_Obj sass_end = Cast(high); // check if units are valid for sequence if (sass_start->unit() != sass_end->unit()) { std::stringstream msg; msg << "Incompatible units: '" @@ -224,19 +225,19 @@ namespace Sass { List_Obj list = 0; Map_Ptr map = 0; if (expr->concrete_type() == Expression::MAP) { - map = SASS_MEMORY_CAST(Map, expr); + map = Cast(expr); } - else if (Selector_List_Ptr ls = SASS_MEMORY_CAST(Selector_List, expr)) { + else if (Selector_List_Ptr ls = Cast(expr)) { Listize listize; Expression_Obj rv = ls->perform(&listize); - list = dynamic_cast(&rv); + list = Cast(rv); } else if (expr->concrete_type() != Expression::LIST) { list = SASS_MEMORY_NEW(List, expr->pstate(), 1, SASS_COMMA); list->append(expr); } else { - list = SASS_MEMORY_CAST(List, expr); + list = Cast(expr); } Block_Obj body = e->block(); @@ -252,8 +253,8 @@ namespace Sass { variable->append(value); env.set_local(variables[0], variable); } else { - env.set_local(variables[0], &key); - env.set_local(variables[1], &value); + env.set_local(variables[0], key); + env.set_local(variables[1], value); } val = body->perform(this); @@ -261,15 +262,15 @@ namespace Sass { } } else { - if (list->length() == 1 && SASS_MEMORY_CAST(Selector_List, list)) { - list = SASS_MEMORY_CAST(List, list); + if (list->length() == 1 && Cast(list)) { + list = Cast(list); } for (size_t i = 0, L = list->length(); i < L; ++i) { - Expression_Ptr e = &list->at(i); + Expression_Ptr e = list->at(i); // unwrap value if the expression is an argument - if (Argument_Ptr arg = SASS_MEMORY_CAST_PTR(Argument, e)) e = &arg->value(); + if (Argument_Ptr arg = Cast(e)) e = arg->value(); // check if we got passed a list of args (investigate) - if (List_Ptr scalars = SASS_MEMORY_CAST_PTR(List, e)) { + if (List_Ptr scalars = Cast(e)) { if (variables.size() == 1) { Expression_Ptr var = scalars; env.set_local(variables[0], var); @@ -278,7 +279,7 @@ namespace Sass { for (size_t j = 0, K = variables.size(); j < K; ++j) { Expression_Ptr res = j >= scalars->length() ? SASS_MEMORY_NEW(Null, expr->pstate()) - : &scalars->at(j); + : scalars->at(j); env.set_local(variables[j], res); } } @@ -334,17 +335,28 @@ namespace Sass { // try to use generic function if (env->has("@warn[f]")) { - Definition_Ptr def = SASS_MEMORY_CAST(Definition, (*env)["@warn[f]"]); + // add call stack entry + ctx.callee_stack.push_back({ + "@warn", + w->pstate().path, + w->pstate().line + 1, + w->pstate().column + 1, + SASS_CALLEE_FUNCTION, + { env } + }); + + Definition_Ptr def = Cast((*env)["@warn[f]"]); // Block_Obj body = def->block(); // Native_Function func = def->native_function(); Sass_Function_Entry c_function = def->c_function(); Sass_Function_Fn c_func = sass_function_get_function(c_function); To_C to_c; - union Sass_Value* c_args = sass_make_list(1, SASS_COMMA); + union Sass_Value* c_args = sass_make_list(1, SASS_COMMA, false); sass_list_set_value(c_args, 0, message->perform(&to_c)); union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_compiler); ctx.c_options.output_style = outstyle; + ctx.callee_stack.pop_back(); sass_delete_value(c_args); sass_delete_value(c_val); return 0; @@ -370,17 +382,28 @@ namespace Sass { // try to use generic function if (env->has("@error[f]")) { - Definition_Ptr def = SASS_MEMORY_CAST(Definition, (*env)["@error[f]"]); + // add call stack entry + ctx.callee_stack.push_back({ + "@error", + e->pstate().path, + e->pstate().line + 1, + e->pstate().column + 1, + SASS_CALLEE_FUNCTION, + { env } + }); + + Definition_Ptr def = Cast((*env)["@error[f]"]); // Block_Obj body = def->block(); // Native_Function func = def->native_function(); Sass_Function_Entry c_function = def->c_function(); Sass_Function_Fn c_func = sass_function_get_function(c_function); To_C to_c; - union Sass_Value* c_args = sass_make_list(1, SASS_COMMA); + union Sass_Value* c_args = sass_make_list(1, SASS_COMMA, false); sass_list_set_value(c_args, 0, message->perform(&to_c)); union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_compiler); ctx.c_options.output_style = outstyle; + ctx.callee_stack.pop_back(); sass_delete_value(c_args); sass_delete_value(c_val); return 0; @@ -403,17 +426,28 @@ namespace Sass { // try to use generic function if (env->has("@debug[f]")) { - Definition_Ptr def = SASS_MEMORY_CAST(Definition, (*env)["@debug[f]"]); + // add call stack entry + ctx.callee_stack.push_back({ + "@debug", + d->pstate().path, + d->pstate().line + 1, + d->pstate().column + 1, + SASS_CALLEE_FUNCTION, + { env } + }); + + Definition_Ptr def = Cast((*env)["@debug[f]"]); // Block_Obj body = def->block(); // Native_Function func = def->native_function(); Sass_Function_Entry c_function = def->c_function(); Sass_Function_Fn c_func = sass_function_get_function(c_function); To_C to_c; - union Sass_Value* c_args = sass_make_list(1, SASS_COMMA); + union Sass_Value* c_args = sass_make_list(1, SASS_COMMA, false); sass_list_set_value(c_args, 0, message->perform(&to_c)); union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_compiler); ctx.c_options.output_style = outstyle; + ctx.callee_stack.pop_back(); sass_delete_value(c_args); sass_delete_value(c_val); return 0; @@ -441,8 +475,8 @@ namespace Sass { l->length() / 2); for (size_t i = 0, L = l->length(); i < L; i += 2) { - Expression_Ptr key = (*l)[i+0]->perform(this); - Expression_Ptr val = (*l)[i+1]->perform(this); + Expression_Obj key = (*l)[i+0]->perform(this); + Expression_Obj val = (*l)[i+1]->perform(this); // make sure the color key never displays its real name key->is_delayed(true); // verified *lm << std::make_pair(key, val); @@ -461,7 +495,8 @@ namespace Sass { l->pstate(), l->length(), l->separator(), - l->is_arglist()); + l->is_arglist(), + l->is_bracketed()); for (size_t i = 0, L = l->length(); i < L; ++i) { ll->append((*l)[i]->perform(this)); } @@ -504,14 +539,14 @@ namespace Sass { String_Schema_Obj ret_schema; Binary_Expression_Obj b = b_in; - enum Sass_OP op_type = b->type(); + enum Sass_OP op_type = b->optype(); // only the last item will be used to eval the binary expression - if (String_Schema_Ptr s_l = SASS_MEMORY_CAST(String_Schema, b->left())) { + if (String_Schema_Ptr s_l = Cast(b->left())) { if (!s_l->has_interpolant() && (!s_l->is_right_interpolant())) { ret_schema = SASS_MEMORY_NEW(String_Schema, b->pstate()); Binary_Expression_Obj bin_ex = SASS_MEMORY_NEW(Binary_Expression, b->pstate(), - b->op(), &s_l->last(), b->right()); + b->op(), s_l->last(), b->right()); bin_ex->is_delayed(b->left()->is_delayed() || b->right()->is_delayed()); // unverified for (size_t i = 0; i < s_l->length() - 1; ++i) { ret_schema->append(s_l->at(i)->perform(this)); @@ -520,12 +555,12 @@ namespace Sass { return ret_schema->perform(this); } } - if (String_Schema_Ptr s_r = SASS_MEMORY_CAST(String_Schema, b->right())) { + if (String_Schema_Ptr s_r = Cast(b->right())) { if (!s_r->has_interpolant() && (!s_r->is_left_interpolant() || op_type == Sass_OP::DIV)) { ret_schema = SASS_MEMORY_NEW(String_Schema, b->pstate()); Binary_Expression_Obj bin_ex = SASS_MEMORY_NEW(Binary_Expression, b->pstate(), - b->op(), b->left(), &s_r->first()); + b->op(), b->left(), s_r->first()); bin_ex->is_delayed(b->left()->is_delayed() || b->right()->is_delayed()); // verified ret_schema->append(bin_ex->perform(this)); for (size_t i = 1; i < s_r->length(); ++i) { @@ -580,17 +615,17 @@ namespace Sass { } // not a logical connective, so go ahead and eval the rhs rhs = rhs->perform(this); - AST_Node_Obj lu = &lhs; - AST_Node_Obj ru = &rhs; + AST_Node_Obj lu = lhs; + AST_Node_Obj ru = rhs; Expression::Concrete_Type l_type = lhs->concrete_type(); Expression::Concrete_Type r_type = rhs->concrete_type(); // Is one of the operands an interpolant? - String_Schema_Obj s1 = SASS_MEMORY_CAST(String_Schema, b->left()); - String_Schema_Obj s2 = SASS_MEMORY_CAST(String_Schema, b->right()); - Binary_Expression_Obj b1 = SASS_MEMORY_CAST(Binary_Expression, b->left()); - Binary_Expression_Obj b2 = SASS_MEMORY_CAST(Binary_Expression, b->right()); + String_Schema_Obj s1 = Cast(b->left()); + String_Schema_Obj s2 = Cast(b->right()); + Binary_Expression_Obj b1 = Cast(b->left()); + Binary_Expression_Obj b2 = Cast(b->right()); bool schema_op = false; @@ -604,7 +639,7 @@ namespace Sass { 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 || op_type == Sass_OP::EQ) { // If possible upgrade LHS to a number (for number to string compare) - if (String_Constant_Ptr str = SASS_MEMORY_CAST(String_Constant, lhs)) { + if (String_Constant_Ptr str = Cast(lhs)) { std::string value(str->value()); const char* start = value.c_str(); if (Prelexer::sequence < Prelexer::dimension, Prelexer::end_of_file >(start) != 0) { @@ -613,7 +648,7 @@ namespace Sass { } } // If possible upgrade RHS to a number (for string to number compare) - if (String_Constant_Ptr str = SASS_MEMORY_CAST(String_Constant, rhs)) { + if (String_Constant_Ptr str = Cast(rhs)) { std::string value(str->value()); const char* start = value.c_str(); if (Prelexer::sequence < Prelexer::dimension, Prelexer::number >(start) != 0) { @@ -624,13 +659,13 @@ namespace Sass { } To_Value to_value(ctx); - Value_Obj v_l = dynamic_cast(lhs->perform(&to_value)); - Value_Obj v_r = dynamic_cast(rhs->perform(&to_value)); + Value_Obj v_l = Cast(lhs->perform(&to_value)); + Value_Obj v_r = Cast(rhs->perform(&to_value)); l_type = lhs->concrete_type(); r_type = rhs->concrete_type(); if (s2 && s2->has_interpolants() && s2->length()) { - Textual_Obj front = SASS_MEMORY_CAST(Textual, s2->elements().front()); + Textual_Obj front = Cast(s2->elements().front()); if (front && !front->is_interpolant()) { // XXX: this is never hit via spec tests @@ -679,30 +714,30 @@ namespace Sass { try { ParserState pstate(b->pstate()); if (l_type == Expression::NUMBER && r_type == Expression::NUMBER) { - Number_Ptr l_n = SASS_MEMORY_CAST(Number, lhs); - Number_Ptr r_n = SASS_MEMORY_CAST(Number, rhs); + Number_Ptr l_n = Cast(lhs); + Number_Ptr r_n = Cast(rhs); rv = op_numbers(op_type, *l_n, *r_n, ctx.c_options, &pstate); } else if (l_type == Expression::NUMBER && r_type == Expression::COLOR) { - Number_Ptr l_n = SASS_MEMORY_CAST(Number, lhs); - Color_Ptr r_c = SASS_MEMORY_CAST(Color, rhs); + Number_Ptr l_n = Cast(lhs); + Color_Ptr r_c = Cast(rhs); rv = op_number_color(op_type, *l_n, *r_c, ctx.c_options, &pstate); } else if (l_type == Expression::COLOR && r_type == Expression::NUMBER) { - Color_Ptr l_c = SASS_MEMORY_CAST(Color, lhs); - Number_Ptr r_n = SASS_MEMORY_CAST(Number, rhs); + Color_Ptr l_c = Cast(lhs); + Number_Ptr r_n = Cast(rhs); rv = op_color_number(op_type, *l_c, *r_n, ctx.c_options, &pstate); } else if (l_type == Expression::COLOR && r_type == Expression::COLOR) { - Color_Ptr l_c = SASS_MEMORY_CAST(Color, lhs); - Color_Ptr r_c = SASS_MEMORY_CAST(Color, rhs); + Color_Ptr l_c = Cast(lhs); + Color_Ptr r_c = Cast(rhs); rv = op_colors(op_type, *l_c, *r_c, ctx.c_options, &pstate); } else { To_Value to_value(ctx); // this will leak if perform does not return a value! - Value_Obj v_l = SASS_MEMORY_CAST_PTR(Value, lhs->perform(&to_value)); - Value_Obj v_r = SASS_MEMORY_CAST_PTR(Value, rhs->perform(&to_value)); + Value_Obj v_l = Cast(lhs->perform(&to_value)); + Value_Obj v_r = Cast(rhs->perform(&to_value)); bool interpolant = b->is_right_interpolant() || b->is_left_interpolant() || b->is_interpolant(); @@ -716,12 +751,12 @@ namespace Sass { throw Exception::InvalidValue(*v_r); } Value_Ptr ex = op_strings(b->op(), *v_l, *v_r, ctx.c_options, &pstate, !interpolant); // pass true to compress - if (String_Constant_Ptr str = dynamic_cast(ex)) + if (String_Constant_Ptr str = Cast(ex)) { if (str->concrete_type() == Expression::STRING) { - String_Constant_Ptr lstr = SASS_MEMORY_CAST(String_Constant, lhs); - String_Constant_Ptr rstr = SASS_MEMORY_CAST(String_Constant, rhs); + String_Constant_Ptr lstr = Cast(lhs); + String_Constant_Ptr rstr = Cast(rhs); if (op_type != Sass_OP::SUB) { if (String_Constant_Ptr org = lstr ? lstr : rstr) { str->quote_mark(org->quote_mark()); } @@ -753,31 +788,32 @@ namespace Sass { Expression_Ptr Eval::operator()(Unary_Expression_Ptr u) { Expression_Obj operand = u->operand()->perform(this); - if (u->type() == Unary_Expression::NOT) { + if (u->optype() == Unary_Expression::NOT) { Boolean_Ptr result = SASS_MEMORY_NEW(Boolean, u->pstate(), (bool)*operand); result->value(!result->value()); return result; } - else if (operand->concrete_type() == Expression::NUMBER) { - Number_Ptr result = SASS_MEMORY_NEW(Number, static_cast(&operand)); - result->value(u->type() == Unary_Expression::MINUS - ? -result->value() - : result->value()); - return result; + else if (Number_Obj nr = Cast(operand)) { + // negate value for minus unary expression + if (u->optype() == Unary_Expression::MINUS) { + Number_Obj cpy = SASS_MEMORY_COPY(nr); + cpy->value( - cpy->value() ); // negate value + return cpy.detach(); // return the copy + } + // nothing for positive + return nr.detach(); } else { // Special cases: +/- variables which evaluate to null ouput just +/-, // but +/- null itself outputs the string - if (operand->concrete_type() == Expression::NULL_VAL && SASS_MEMORY_CAST(Variable, u->operand())) { + if (operand->concrete_type() == Expression::NULL_VAL && Cast(u->operand())) { u->operand(SASS_MEMORY_NEW(String_Quoted, u->pstate(), "")); } // Never apply unary opertions on colors @see #2140 - else if (operand->concrete_type() == Expression::COLOR) { - Color_Ptr c = dynamic_cast(&operand); - + else if (Color_Ptr color = Cast(operand)) { // Use the color name if this was eval with one - if (c->disp().length() > 0) { - operand = SASS_MEMORY_NEW(String_Constant, operand->pstate(), c->disp()); + if (color->disp().length() > 0) { + operand = SASS_MEMORY_NEW(String_Constant, operand->pstate(), color->disp()); u->operand(operand); } } @@ -785,10 +821,9 @@ namespace Sass { u->operand(operand); } - String_Constant_Ptr result = SASS_MEMORY_NEW(String_Quoted, - u->pstate(), - u->inspect()); - return result; + return SASS_MEMORY_NEW(String_Quoted, + u->pstate(), + u->inspect()); } // unreachable return u; @@ -811,15 +846,15 @@ namespace Sass { if (!env->has(full_name) || (!c->via_call() && Prelexer::re_special_fun(name.c_str()))) { if (!env->has("*[f]")) { for (Argument_Obj arg : args->elements()) { - if (List_Obj ls = SASS_MEMORY_CAST(List, arg->value())) { + if (List_Obj ls = Cast(arg->value())) { if (ls->size() == 0) error("() isn't a valid CSS value.", c->pstate()); } } - args = SASS_MEMORY_CAST_PTR(Arguments, args->perform(this)); + args = Cast(args->perform(this)); Function_Call_Obj lit = SASS_MEMORY_NEW(Function_Call, c->pstate(), c->name(), - &args); + args); if (args->has_named_arguments()) { error("Function " + c->name() + " doesn't support keyword arguments", c->pstate()); } @@ -839,9 +874,9 @@ namespace Sass { args->set_delayed(false); // verified } if (full_name != "if[f]") { - args = SASS_MEMORY_CAST_PTR(Arguments, args->perform(this)); + args = Cast(args->perform(this)); } - Definition_Ptr def = SASS_MEMORY_CAST(Definition, (*env)[full_name]); + Definition_Ptr def = Cast((*env)[full_name]); if (def->is_overload_stub()) { std::stringstream ss; @@ -849,7 +884,7 @@ namespace Sass { // account for rest arguments if (args->has_rest_argument() && args->length() > 0) { // get the rest arguments list - List_Ptr rest = SASS_MEMORY_CAST(List, args->last()->value()); + List_Ptr rest = Cast(args->last()->value()); // arguments before rest argument plus rest if (rest) L += rest->length() - 1; } @@ -857,7 +892,7 @@ namespace Sass { full_name = ss.str(); std::string resolved_name(full_name); if (!env->has(resolved_name)) error("overloaded function `" + std::string(c->name()) + "` given wrong number of arguments", c->pstate()); - def = SASS_MEMORY_CAST(Definition, (*env)[resolved_name]); + def = Cast((*env)[resolved_name]); } Expression_Obj result = c; @@ -873,6 +908,15 @@ namespace Sass { bind(std::string("Function"), c->name(), params, args, &ctx, &fn_env, this); Backtrace here(backtrace(), c->pstate(), ", in function `" + c->name() + "`"); exp.backtrace_stack.push_back(&here); + ctx.callee_stack.push_back({ + c->name().c_str(), + c->pstate().path, + c->pstate().line + 1, + c->pstate().column + 1, + SASS_CALLEE_FUNCTION, + { env } + }); + // eval the body if user-defined or special, invoke underlying CPP function if native if (body /* && !Prelexer::re_special_fun(name.c_str()) */) { result = body->perform(this); @@ -884,6 +928,7 @@ namespace Sass { error(std::string("Function ") + c->name() + " did not return a value", c->pstate()); } exp.backtrace_stack.pop_back(); + ctx.callee_stack.pop_back(); } // else if it's a user-defined c function @@ -893,8 +938,8 @@ namespace Sass { if (full_name == "*[f]") { String_Quoted_Obj str = SASS_MEMORY_NEW(String_Quoted, c->pstate(), c->name()); Arguments_Obj new_args = SASS_MEMORY_NEW(Arguments, c->pstate()); - new_args->append(SASS_MEMORY_NEW(Argument, c->pstate(), &str)); - new_args->concat(&args); + new_args->append(SASS_MEMORY_NEW(Argument, c->pstate(), str)); + new_args->concat(args); args = new_args; } @@ -904,14 +949,22 @@ namespace Sass { Backtrace here(backtrace(), c->pstate(), ", in function `" + c->name() + "`"); exp.backtrace_stack.push_back(&here); + ctx.callee_stack.push_back({ + c->name().c_str(), + c->pstate().path, + c->pstate().line + 1, + c->pstate().column + 1, + SASS_CALLEE_C_FUNCTION, + { env } + }); To_C to_c; - union Sass_Value* c_args = sass_make_list(params->length(), SASS_COMMA); + union Sass_Value* c_args = sass_make_list(params->length(), SASS_COMMA, false); for(size_t i = 0; i < params->length(); i++) { Parameter_Obj param = params->at(i); std::string key = param->name(); AST_Node_Obj node = fn_env.get_local(key); - Expression_Obj arg = SASS_MEMORY_CAST(Expression, node); + Expression_Obj arg = Cast(node); sass_list_set_value(c_args, i, arg->perform(&to_c)); } union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_compiler); @@ -923,6 +976,7 @@ namespace Sass { result = cval_to_astnode(c_val, backtrace(), c->pstate()); exp.backtrace_stack.pop_back(); + ctx.callee_stack.pop_back(); sass_delete_value(c_args); if (c_val != c_args) sass_delete_value(c_val); @@ -955,15 +1009,15 @@ namespace Sass { Expression_Obj value = 0; Env* env = environment(); if (env->has(name)) { - value = SASS_MEMORY_CAST(Expression, (*env)[name]); + value = Cast((*env)[name]); } else error("Undefined variable: \"" + v->name() + "\".", v->pstate()); - if (typeid(*value) == typeid(Argument)) { - value = SASS_MEMORY_CAST(Argument, value)->value(); + if (Argument* arg = Cast(value)) { + value = arg->value(); } // behave according to as ruby sass (add leading zero) - if (Number_Ptr nr = SASS_MEMORY_CAST(Number, value)) { + if (Number_Ptr nr = Cast(value)) { nr->zero(true); } @@ -971,7 +1025,7 @@ namespace Sass { if (force) value->is_expanded(false); value->set_delayed(false); // verified value = value->perform(this); - if(!force) (*env)[name] = &value; + if(!force) (*env)[name] = value; return value.detach(); } @@ -993,7 +1047,7 @@ namespace Sass { if (unit_pos == std::string::npos) unit_pos = text.length(); const std::string& num = text.substr(num_pos, unit_pos - num_pos); - switch (t->type()) + switch (t->valtype()) { case Textual::NUMBER: result = SASS_MEMORY_NEW(Number, @@ -1068,7 +1122,7 @@ namespace Sass { bool needs_closing_brace = false; - if (Arguments_Ptr args = SASS_MEMORY_CAST(Arguments, ex)) { + if (Arguments_Ptr args = Cast(ex)) { List_Ptr ll = SASS_MEMORY_NEW(List, args->pstate(), 0, SASS_COMMA); for(auto arg : args->elements()) { ll->append(arg->value()); @@ -1078,15 +1132,15 @@ namespace Sass { res += "("; ex = ll; } - if (Number_Ptr nr = SASS_MEMORY_CAST(Number, ex)) { + if (Number_Ptr nr = Cast(ex)) { if (!nr->is_valid_css_unit()) { throw Exception::InvalidValue(*nr); } } - if (Argument_Ptr arg = SASS_MEMORY_CAST(Argument, ex)) { - ex = &arg->value(); + if (Argument_Ptr arg = Cast(ex)) { + ex = arg->value(); } - if (String_Quoted_Ptr sq = SASS_MEMORY_CAST(String_Quoted, ex)) { + if (String_Quoted_Ptr sq = Cast(ex)) { if (was_itpl) { bool was_interpolant = ex->is_interpolant(); ex = SASS_MEMORY_NEW(String_Constant, sq->pstate(), sq->value()); @@ -1094,22 +1148,22 @@ namespace Sass { } } - if (SASS_MEMORY_CAST(Null, ex)) { return; } + if (Cast(ex)) { return; } // parent selector needs another go - if (SASS_MEMORY_CAST(Parent_Selector, ex)) { + if (Cast(ex)) { // XXX: this is never hit via spec tests ex = ex->perform(this); } - if (List_Ptr l = SASS_MEMORY_CAST(List, ex)) { + if (List_Ptr l = Cast(ex)) { List_Obj ll = SASS_MEMORY_NEW(List, l->pstate(), 0, l->separator()); // this fixes an issue with bourbon sample, not really sure why - // if (l->size() && dynamic_cast((*l)[0])) { res += ""; } + // if (l->size() && Cast((*l)[0])) { res += ""; } for(Expression_Obj item : *l) { item->is_interpolant(l->is_interpolant()); - std::string rl(""); interpolation(ctx, rl, &item, into_quotes, l->is_interpolant()); - bool is_null = dynamic_cast(&item) != 0; // rl != "" + std::string rl(""); interpolation(ctx, rl, item, into_quotes, l->is_interpolant()); + bool is_null = Cast(item) != 0; // rl != "" if (!is_null) ll->append(SASS_MEMORY_NEW(String_Quoted, item->pstate(), rl)); } // Check indicates that we probably should not get a list @@ -1151,9 +1205,9 @@ namespace Sass { size_t L = s->length(); bool into_quotes = false; if (L > 1) { - if (!SASS_MEMORY_CAST(String_Quoted, (*s)[0]) && !SASS_MEMORY_CAST(String_Quoted, (*s)[L - 1])) { - if (String_Constant_Ptr l = SASS_MEMORY_CAST(String_Constant, (*s)[0])) { - if (String_Constant_Ptr r = SASS_MEMORY_CAST(String_Constant, (*s)[L - 1])) { + if (!Cast((*s)[0]) && !Cast((*s)[L - 1])) { + if (String_Constant_Ptr l = Cast((*s)[0])) { + if (String_Constant_Ptr r = Cast((*s)[L - 1])) { if (r->value().size() > 0) { if (l->value()[0] == '"' && r->value()[r->value().size() - 1] == '"') into_quotes = true; if (l->value()[0] == '\'' && r->value()[r->value().size() - 1] == '\'') into_quotes = true; @@ -1166,12 +1220,12 @@ namespace Sass { bool was_interpolant = false; std::string res(""); for (size_t i = 0; i < L; ++i) { - bool is_quoted = SASS_MEMORY_CAST(String_Quoted, (*s)[i]) != NULL; + bool is_quoted = Cast((*s)[i]) != NULL; if (was_quoted && !(*s)[i]->is_interpolant() && !was_interpolant) { res += " "; } else if (i > 0 && is_quoted && !(*s)[i]->is_interpolant() && !was_interpolant) { res += " "; } Expression_Obj ex = (*s)[i]->perform(this); interpolation(ctx, res, ex, into_quotes, ex->is_interpolant()); - was_quoted = SASS_MEMORY_CAST(String_Quoted, (*s)[i]) != NULL; + was_quoted = Cast((*s)[i]) != NULL; was_interpolant = (*s)[i]->is_interpolant(); } @@ -1217,8 +1271,8 @@ namespace Sass { Expression_Ptr right = c->right()->perform(this); Supports_Operator_Ptr cc = SASS_MEMORY_NEW(Supports_Operator, c->pstate(), - dynamic_cast(left), - dynamic_cast(right), + Cast(left), + Cast(right), c->operand()); return cc; } @@ -1228,7 +1282,7 @@ namespace Sass { Expression_Ptr condition = c->condition()->perform(this); Supports_Negation_Ptr cc = SASS_MEMORY_NEW(Supports_Negation, c->pstate(), - dynamic_cast(condition)); + Cast(condition)); return cc; } @@ -1260,7 +1314,7 @@ namespace Sass { value = (value ? value->perform(this) : 0); Expression_Ptr ee = SASS_MEMORY_NEW(At_Root_Query, e->pstate(), - dynamic_cast(&feature), + Cast(feature), value); return ee; } @@ -1268,10 +1322,10 @@ namespace Sass { Expression_Ptr Eval::operator()(Media_Query_Ptr q) { String_Obj t = q->media_type(); - t = static_cast(&t ? t->perform(this) : 0); + t = static_cast(t.isNull() ? 0 : t->perform(this)); Media_Query_Obj qq = SASS_MEMORY_NEW(Media_Query, q->pstate(), - &t, + t, q->length(), q->is_negated(), q->is_restricted()); @@ -1285,18 +1339,18 @@ namespace Sass { { Expression_Obj feature = e->feature(); feature = (feature ? feature->perform(this) : 0); - if (feature && SASS_MEMORY_CAST(String_Quoted, feature)) { + if (feature && Cast(feature)) { feature = SASS_MEMORY_NEW(String_Quoted, feature->pstate(), - SASS_MEMORY_CAST(String_Quoted, feature)->value()); + Cast(feature)->value()); } Expression_Obj value = e->value(); value = (value ? value->perform(this) : 0); - if (value && SASS_MEMORY_CAST(String_Quoted, value)) { + if (value && Cast(value)) { // XXX: this is never hit via spec tests value = SASS_MEMORY_NEW(String_Quoted, value->pstate(), - SASS_MEMORY_CAST(String_Quoted, value)->value()); + Cast(value)->value()); } return SASS_MEMORY_NEW(Media_Query_Expression, e->pstate(), @@ -1328,7 +1382,7 @@ namespace Sass { SASS_COMMA, true); wrapper->append(val); - val = &wrapper; + val = wrapper; } } return SASS_MEMORY_NEW(Argument, @@ -1345,7 +1399,7 @@ namespace Sass { if (a->length() == 0) return aa.detach(); for (size_t i = 0, L = a->length(); i < L; ++i) { Expression_Obj rv = (*a)[i]->perform(this); - Argument_Ptr arg = SASS_MEMORY_CAST(Argument, rv); + Argument_Ptr arg = Cast(rv); if (!(arg->is_rest_argument() || arg->is_keyword_argument())) { aa->append(arg); } @@ -1353,11 +1407,11 @@ namespace Sass { if (a->has_rest_argument()) { Expression_Obj rest = a->get_rest_argument()->perform(this); - Expression_Obj splat = SASS_MEMORY_CAST(Argument, rest)->value()->perform(this); + Expression_Obj splat = Cast(rest)->value()->perform(this); Sass_Separator separator = SASS_COMMA; - List_Ptr ls = SASS_MEMORY_CAST(List, splat); - Map_Ptr ms = SASS_MEMORY_CAST(Map, splat); + List_Ptr ls = Cast(splat); + Map_Ptr ms = Cast(splat); List_Obj arglist = SASS_MEMORY_NEW(List, splat->pstate(), @@ -1375,13 +1429,13 @@ namespace Sass { arglist->append(splat); } if (arglist->length()) { - aa->append(SASS_MEMORY_NEW(Argument, splat->pstate(), &arglist, "", true)); + aa->append(SASS_MEMORY_NEW(Argument, splat->pstate(), arglist, "", true)); } } if (a->has_keyword_argument()) { Expression_Obj rv = a->get_keyword_argument()->perform(this); - Argument_Ptr rvarg = SASS_MEMORY_CAST(Argument, rv); + Argument_Ptr rvarg = Cast(rv); Expression_Obj kwarg = rvarg->value()->perform(this); aa->append(SASS_MEMORY_NEW(Argument, kwarg->pstate(), kwarg, "", false, true)); @@ -1409,10 +1463,10 @@ namespace Sass { bool Eval::lt(Expression_Obj lhs, Expression_Obj rhs, std::string op) { - Number_Obj l = SASS_MEMORY_CAST(Number, lhs); - Number_Obj r = SASS_MEMORY_CAST(Number, rhs); + Number_Obj l = Cast(lhs); + Number_Obj r = Cast(rhs); // use compare operator from ast node - if (!l || !r) throw Exception::UndefinedOperation(&lhs, &rhs, op); + if (!l || !r) throw Exception::UndefinedOperation(lhs, rhs, op); // use compare operator from ast node return *l < *r; } @@ -1540,8 +1594,8 @@ namespace Sass { Expression::Concrete_Type rtype = rhs.concrete_type(); enum Sass_OP op = operand.operand; - String_Quoted_Ptr lqstr = dynamic_cast(&lhs); - String_Quoted_Ptr rqstr = dynamic_cast(&rhs); + String_Quoted_Ptr lqstr = Cast(&lhs); + String_Quoted_Ptr rqstr = Cast(&rhs); std::string lstr(lqstr ? lqstr->value() : lhs.to_string(opt)); std::string rstr(rqstr ? rqstr->value() : rhs.to_string(opt)); @@ -1612,6 +1666,7 @@ namespace Sass { for (size_t i = 0, L = sass_list_get_length(v); i < L; ++i) { l->append(cval_to_astnode(sass_list_get_value(v, i), backtrace, pstate)); } + l->is_bracketed(sass_list_get_is_bracketed(v)); e = l; } break; case SASS_MAP: { @@ -1644,7 +1699,7 @@ namespace Sass { sl->media_block(s->media_block()); sl->is_optional(s->is_optional()); for (size_t i = 0, iL = s->length(); i < iL; ++i) { - rv.push_back(operator()(&(*s)[i])); + rv.push_back(operator()((*s)[i])); } // we should actually permutate parent first @@ -1690,19 +1745,20 @@ namespace Sass { // the parser will look for a brace to end the selector Expression_Obj sel = s->contents()->perform(this); std::string result_str(sel->to_string(ctx.c_options)); - result_str = unquote(Util::rtrim(result_str)) + "\n{"; + result_str = unquote(Util::rtrim(result_str)); Parser p = Parser::from_c_str(result_str.c_str(), ctx, s->pstate()); p.last_media_block = s->media_block(); - Selector_List_Obj sl = p.parse_selector_list(exp.block_stack.back()->is_root()); - if (s->has_parent_ref()) sl->remove_parent_selectors(); - return operator()(&sl); + // a selector schema may or may not connect to parent? + bool chroot = s->connect_parent() == false; + Selector_List_Obj sl = p.parse_selector_list(chroot); + return operator()(sl); } Expression_Ptr Eval::operator()(Parent_Selector_Ptr p) { if (Selector_List_Obj pr = selector()) { exp.selector_stack.pop_back(); - Selector_List_Obj rv = operator()(&pr); + Selector_List_Obj rv = operator()(pr); exp.selector_stack.push_back(rv); return rv.detach(); } else { diff --git a/src/libsass/src/expand.cpp b/src/libsass/src/expand.cpp index d38a01296..1057d980f 100755 --- a/src/libsass/src/expand.cpp +++ b/src/libsass/src/expand.cpp @@ -9,6 +9,7 @@ #include "backtrace.hpp" #include "context.hpp" #include "parser.hpp" +#include "sass_functions.hpp" namespace Sass { @@ -40,11 +41,6 @@ namespace Sass { backtrace_stack.push_back(bt); } - Context& Expand::context() - { - return ctx; - } - Env* Expand::environment() { if (env_stack.size() > 0) @@ -78,7 +74,7 @@ namespace Sass { b->length(), b->is_root()); // setup block and env stack - this->block_stack.push_back(&bb); + this->block_stack.push_back(bb); this->env_stack.push_back(&env); // operate on block // this may throw up! @@ -95,12 +91,14 @@ namespace Sass { LOCAL_FLAG(old_at_root_without_rule, at_root_without_rule); if (in_keyframes) { - Block_Ptr bb = operator()(&r->block()); + Block_Ptr bb = operator()(r->block()); Keyframe_Rule_Obj k = SASS_MEMORY_NEW(Keyframe_Rule, r->pstate(), bb); if (r->selector()) { - selector_stack.push_back(0); - k->name(SASS_MEMORY_CAST_PTR(Selector_List, r->selector()->perform(&eval))); - selector_stack.pop_back(); + if (Selector_List_Ptr s = r->selector()) { + selector_stack.push_back(0); + k->name(s->eval(eval)); + selector_stack.pop_back(); + } } return k.detach(); } @@ -108,50 +106,52 @@ namespace Sass { // reset when leaving scope LOCAL_FLAG(at_root_without_rule, false); - // do some special checks for the base level rules + // `&` is allowed in `@at-root`! + bool has_parent_selector = false; + for (size_t i = 0, L = selector_stack.size(); i < L && !has_parent_selector; i++) { + Selector_List_Obj ll = selector_stack.at(i); + has_parent_selector = ll != 0 && ll->length() > 0; + } + + Selector_List_Obj sel = r->selector(); + if (sel) sel = sel->eval(eval); + + // check for parent selectors in base level rules if (r->is_root()) { - if (Selector_List_Ptr selector_list = SASS_MEMORY_CAST(Selector_List, r->selector())) { + if (Selector_List_Ptr selector_list = Cast(r->selector())) { for (Complex_Selector_Obj complex_selector : selector_list->elements()) { - Complex_Selector_Ptr tail = &complex_selector; + Complex_Selector_Ptr tail = complex_selector; while (tail) { if (tail->head()) for (Simple_Selector_Obj header : tail->head()->elements()) { - if (SASS_MEMORY_CAST(Parent_Selector, header) == NULL) continue; // skip all others + Parent_Selector_Ptr ptr = Cast(header); + if (ptr == NULL || (!ptr->real() || has_parent_selector)) continue; std::string sel_str(complex_selector->to_string(ctx.c_options)); error("Base-level rules cannot contain the parent-selector-referencing character '&'.", header->pstate(), backtrace()); } - tail = &tail->tail(); + tail = tail->tail(); } } } } - - Expression_Obj ex = 0; - if (r->selector()) ex = r->selector()->perform(&eval); - Selector_List_Obj sel = SASS_MEMORY_CAST(Selector_List, ex); - if (sel == 0) throw std::runtime_error("Expanded null selector"); - - if (sel->length() == 0 || sel->has_parent_ref()) { - bool has_parent_selector = false; - for (size_t i = 0, L = selector_stack.size(); i < L && !has_parent_selector; i++) { - Selector_List_Obj ll = selector_stack.at(i); - has_parent_selector = ll != 0 && ll->length() > 0; - } - if (sel->has_real_parent_ref() && !has_parent_selector) { - error("Base-level rules cannot contain the parent-selector-referencing character '&'.", sel->pstate(), backtrace()); + else { + if (sel->length() == 0 || sel->has_parent_ref()) { + if (sel->has_real_parent_ref() && !has_parent_selector) { + error("Base-level rules cannot contain the parent-selector-referencing character '&'.", sel->pstate(), backtrace()); + } } } - selector_stack.push_back(&sel); + selector_stack.push_back(sel); Env env(environment()); if (block_stack.back()->is_root()) { env_stack.push_back(&env); } sel->set_media_block(media_block_stack.back()); Block_Obj blk = 0; - if (r->block()) blk = operator()(&r->block()); + if (r->block()) blk = operator()(r->block()); Ruleset_Ptr rr = SASS_MEMORY_NEW(Ruleset, r->pstate(), - &sel, + sel, blk); selector_stack.pop_back(); if (block_stack.back()->is_root()) { @@ -169,8 +169,8 @@ namespace Sass { Expression_Obj condition = f->condition()->perform(&eval); Supports_Block_Obj ff = SASS_MEMORY_NEW(Supports_Block, f->pstate(), - SASS_MEMORY_CAST(Supports_Condition, condition), - operator()(&f->block())); + Cast(condition), + operator()(f->block())); return ff.detach(); } @@ -182,14 +182,13 @@ namespace Sass { char* str = sass_copy_c_string(str_mq.c_str()); ctx.strings.push_back(str); Parser p(Parser::from_c_str(str, ctx, mq->pstate())); - mq = &p.parse_media_queries(); // re-assign now - List_Obj ls = SASS_MEMORY_CAST_PTR(List, mq->perform(&eval)); - Block_Obj blk = operator()(&m->block()); + mq = p.parse_media_queries(); // re-assign now + List_Obj ls = Cast(mq->perform(&eval)); + Block_Obj blk = operator()(m->block()); Media_Block_Ptr mm = SASS_MEMORY_NEW(Media_Block, m->pstate(), ls, - blk, - 0); + blk); media_block_stack.pop_back(); mm->tabs(m->tabs()); return mm; @@ -198,7 +197,7 @@ namespace Sass { Statement_Ptr Expand::operator()(At_Root_Block_Ptr a) { Block_Obj ab = a->block(); - Expression_Obj ae = &a->expression(); + Expression_Obj ae = a->expression(); if (ae) ae = ae->perform(&eval); else ae = SASS_MEMORY_NEW(At_Root_Query, a->pstate()); @@ -208,23 +207,23 @@ namespace Sass { ; - Block_Obj bb = ab ? operator()(&ab) : NULL; + Block_Obj bb = ab ? operator()(ab) : NULL; At_Root_Block_Obj aa = SASS_MEMORY_NEW(At_Root_Block, a->pstate(), bb, - SASS_MEMORY_CAST(At_Root_Query, ae)); + Cast(ae)); return aa.detach(); } Statement_Ptr Expand::operator()(Directive_Ptr a) { LOCAL_FLAG(in_keyframes, a->is_keyframes()); - Block_Ptr ab = &a->block(); - Selector_Ptr as = &a->selector(); - Expression_Ptr av = &a->value(); + Block_Ptr ab = a->block(); + Selector_List_Ptr as = a->selector(); + Expression_Ptr av = a->value(); selector_stack.push_back(0); if (av) av = av->perform(&eval); - if (as) as = SASS_MEMORY_CAST_PTR(Selector, as->perform(&eval)); + if (as) as = eval(as); selector_stack.pop_back(); Block_Ptr bb = ab ? operator()(ab) : NULL; Directive_Ptr aa = SASS_MEMORY_NEW(Directive, @@ -241,14 +240,14 @@ namespace Sass { Block_Obj ab = d->block(); String_Obj old_p = d->property(); Expression_Obj prop = old_p->perform(&eval); - String_Obj new_p = SASS_MEMORY_CAST(String, prop); + String_Obj new_p = Cast(prop); // we might get a color back if (!new_p) { 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); - Block_Obj bb = ab ? operator()(&ab) : NULL; + Block_Obj bb = ab ? operator()(ab) : NULL; if (!bb) { if (!value || (value->is_invisible() && !d->is_important())) return 0; } @@ -269,7 +268,7 @@ namespace Sass { if (a->is_global()) { if (a->is_default()) { if (env->has_global(var)) { - Expression_Obj e = SASS_MEMORY_CAST(Expression, env->get_global(var)); + Expression_Obj e = Cast(env->get_global(var)); if (!e || e->concrete_type() == Expression::NULL_VAL) { env->set_global(var, a->value()->perform(&eval)); } @@ -288,7 +287,7 @@ namespace Sass { while (cur && cur->is_lexical()) { if (cur->has_local(var)) { if (AST_Node_Obj node = cur->get_local(var)) { - Expression_Obj e = SASS_MEMORY_CAST(Expression, node); + Expression_Obj e = Cast(node); if (!e || e->concrete_type() == Expression::NULL_VAL) { cur->set_local(var, a->value()->perform(&eval)); } @@ -304,7 +303,7 @@ namespace Sass { } else if (env->has_global(var)) { if (AST_Node_Obj node = env->get_global(var)) { - Expression_Obj e = SASS_MEMORY_CAST(Expression, node); + Expression_Obj e = Cast(node); if (!e || e->concrete_type() == Expression::NULL_VAL) { env->set_global(var, a->value()->perform(&eval)); } @@ -328,7 +327,7 @@ namespace Sass { Import_Obj result = SASS_MEMORY_NEW(Import, imp->pstate()); if (imp->import_queries() && imp->import_queries()->size()) { Expression_Obj ex = imp->import_queries()->perform(&eval); - result->import_queries(SASS_MEMORY_CAST(List, ex)); + result->import_queries(Cast(ex)); } for ( size_t i = 0, S = imp->urls().size(); i < S; ++i) { result->urls().push_back(imp->urls()[i]->perform(&eval)); @@ -342,7 +341,7 @@ namespace Sass { { // get parent node from call stack AST_Node_Obj parent = call_stack.back(); - if (SASS_MEMORY_CAST(Block, parent) == NULL) { + if (Cast(parent) == NULL) { error("Import directives may not be used within control directives or mixins.", i->pstate()); } // we don't seem to need that actually afterall @@ -353,7 +352,7 @@ namespace Sass { ); ctx.import_stack.push_back(import); const std::string& abs_path(i->resource().abs_path); - append_block(&ctx.sheets.at(abs_path).root); + append_block(ctx.sheets.at(abs_path).root); sass_delete_import(ctx.import_stack.back()); ctx.import_stack.pop_back(); return 0; @@ -383,7 +382,7 @@ namespace Sass { Statement_Ptr Expand::operator()(Comment_Ptr c) { eval.is_in_comment = true; - Comment_Ptr rv = SASS_MEMORY_NEW(Comment, c->pstate(), SASS_MEMORY_CAST_PTR(String, c->text()->perform(&eval)), c->is_important()); + Comment_Ptr rv = SASS_MEMORY_NEW(Comment, c->pstate(), Cast(c->text()->perform(&eval)), c->is_important()); eval.is_in_comment = false; // TODO: eval the text, once we're parsing/storing it as a String_Schema return rv; @@ -396,10 +395,10 @@ namespace Sass { call_stack.push_back(i); Expression_Obj rv = i->predicate()->perform(&eval); if (*rv) { - append_block(&i->block()); + append_block(i->block()); } else { - Block_Ptr alt = &i->alternative(); + Block_Ptr alt = i->alternative(); if (alt) append_block(alt); } call_stack.pop_back(); @@ -420,8 +419,8 @@ namespace Sass { if (high->concrete_type() != Expression::NUMBER) { throw Exception::TypeMismatch(*high, "integer"); } - Number_Obj sass_start = SASS_MEMORY_CAST(Number, low); - Number_Obj sass_end = SASS_MEMORY_CAST(Number, high); + Number_Obj sass_start = Cast(low); + Number_Obj sass_end = Cast(high); // check if units are valid for sequence if (sass_start->unit() != sass_end->unit()) { std::stringstream msg; msg << "Incompatible units: '" @@ -436,8 +435,8 @@ namespace Sass { env_stack.push_back(&env); call_stack.push_back(f); Number_Obj it = SASS_MEMORY_NEW(Number, low->pstate(), start, sass_end->unit()); - env.set_local(variable, &it); - Block_Ptr body = &f->block(); + env.set_local(variable, it); + Block_Ptr body = f->block(); if (start < end) { if (f->is_inclusive()) ++end; for (double i = start; @@ -445,7 +444,7 @@ namespace Sass { ++i) { it = SASS_MEMORY_COPY(it); it->value(i); - env.set_local(variable, &it); + env.set_local(variable, it); append_block(body); } } else { @@ -455,7 +454,7 @@ namespace Sass { --i) { it = SASS_MEMORY_COPY(it); it->value(i); - env.set_local(variable, &it); + env.set_local(variable, it); append_block(body); } } @@ -473,25 +472,25 @@ namespace Sass { List_Obj list = 0; Map_Obj map; if (expr->concrete_type() == Expression::MAP) { - map = SASS_MEMORY_CAST(Map, expr); + map = Cast(expr); } - else if (Selector_List_Ptr ls = SASS_MEMORY_CAST(Selector_List, expr)) { + else if (Selector_List_Ptr ls = Cast(expr)) { Listize listize; Expression_Obj rv = ls->perform(&listize); - list = SASS_MEMORY_CAST(List, rv); + list = Cast(rv); } else if (expr->concrete_type() != Expression::LIST) { list = SASS_MEMORY_NEW(List, expr->pstate(), 1, SASS_COMMA); list->append(expr); } else { - list = SASS_MEMORY_CAST(List, expr); + list = Cast(expr); } // remember variables and then reset them Env env(environment(), true); env_stack.push_back(&env); call_stack.push_back(e); - Block_Ptr body = &e->block(); + Block_Ptr body = e->block(); if (map) { for (auto key : map->keys()) { @@ -502,43 +501,43 @@ namespace Sass { List_Obj variable = SASS_MEMORY_NEW(List, map->pstate(), 2, SASS_SPACE); variable->append(k); variable->append(v); - env.set_local(variables[0], &variable); + env.set_local(variables[0], variable); } else { - env.set_local(variables[0], &k); - env.set_local(variables[1], &v); + env.set_local(variables[0], k); + env.set_local(variables[1], v); } append_block(body); } } else { // bool arglist = list->is_arglist(); - if (list->length() == 1 && SASS_MEMORY_CAST(Selector_List, list)) { - list = SASS_MEMORY_CAST(List, list); + if (list->length() == 1 && Cast(list)) { + list = Cast(list); } for (size_t i = 0, L = list->length(); i < L; ++i) { Expression_Obj e = list->at(i); // unwrap value if the expression is an argument - if (Argument_Obj arg = SASS_MEMORY_CAST(Argument, e)) e = arg->value(); + if (Argument_Obj arg = Cast(e)) e = arg->value(); // check if we got passed a list of args (investigate) - if (List_Obj scalars = SASS_MEMORY_CAST(List, e)) { + if (List_Obj scalars = Cast(e)) { if (variables.size() == 1) { List_Obj var = scalars; // if (arglist) var = (*scalars)[0]; - env.set_local(variables[0], &var); + env.set_local(variables[0], var); } else { for (size_t j = 0, K = variables.size(); j < K; ++j) { Expression_Obj res = j >= scalars->length() ? SASS_MEMORY_NEW(Null, expr->pstate()) : (*scalars)[j]->perform(&eval); - env.set_local(variables[j], &res); + env.set_local(variables[j], res); } } } else { if (variables.size() > 0) { - env.set_local(variables.at(0), &e); + env.set_local(variables.at(0), e); for (size_t j = 1, K = variables.size(); j < K; ++j) { Expression_Obj res = SASS_MEMORY_NEW(Null, expr->pstate()); - env.set_local(variables[j], &res); + env.set_local(variables[j], res); } } } @@ -553,12 +552,12 @@ namespace Sass { Statement_Ptr Expand::operator()(While_Ptr w) { Expression_Obj pred = w->predicate(); - Block_Ptr body = &w->block(); + Block_Ptr body = w->block(); Env env(environment(), true); env_stack.push_back(&env); call_stack.push_back(w); Expression_Obj cond = pred->perform(&eval); - while (*&cond) { + while (!cond->is_false()) { append_block(body); cond = pred->perform(&eval); } @@ -576,12 +575,12 @@ namespace Sass { void Expand::expand_selector_list(Selector_Obj s, Selector_List_Obj extender) { - if (Selector_List_Obj sl = SASS_MEMORY_CAST(Selector_List, s)) { + if (Selector_List_Obj sl = Cast(s)) { for (Complex_Selector_Obj complex_selector : sl->elements()) { Complex_Selector_Obj tail = complex_selector; while (tail) { if (tail->head()) for (Simple_Selector_Obj header : tail->head()->elements()) { - if (SASS_MEMORY_CAST(Parent_Selector, header) == NULL) continue; // skip all others + if (Cast(header) == NULL) continue; // skip all others std::string sel_str(complex_selector->to_string(ctx.c_options)); error("Can't extend " + sel_str + ": can't extend parent selectors", header->pstate(), backtrace()); } @@ -591,7 +590,7 @@ namespace Sass { } - Selector_List_Obj contextualized = SASS_MEMORY_CAST_PTR(Selector_List, s->perform(&eval)); + Selector_List_Obj contextualized = Cast(s->perform(&eval)); if (contextualized == false) return; for (auto complex_sel : contextualized->elements()) { Complex_Selector_Obj c = complex_sel; @@ -604,7 +603,7 @@ namespace Sass { for (size_t i = 0, L = extender->length(); i < L; ++i) { Complex_Selector_Obj sel = (*extender)[i]; if (!(sel->head() && sel->head()->length() > 0 && - SASS_MEMORY_CAST(Parent_Selector, (*sel->head())[0]))) + Cast((*sel->head())[0]))) { Compound_Selector_Obj hh = SASS_MEMORY_NEW(Compound_Selector, (*extender)[i]->pstate()); hh->media_block((*extender)[i]->media_block()); @@ -613,7 +612,7 @@ namespace Sass { if (sel->has_line_feed()) ssel->has_line_feed(true); Parent_Selector_Obj ps = SASS_MEMORY_NEW(Parent_Selector, (*extender)[i]->pstate()); ps->media_block((*extender)[i]->media_block()); - hh->append(&ps); + hh->append(ps); ssel->tail(sel); ssel->head(hh); sel = ssel; @@ -627,31 +626,30 @@ namespace Sass { Statement* Expand::operator()(Extension_Ptr e) { - if (Selector_List_Obj extender = SASS_MEMORY_CAST(Selector_List, selector())) { - Selector_Obj s = e->selector(); - Selector_List_Obj sl = NULL; - // check if we already have a valid selector list - if ((sl = SASS_MEMORY_CAST(Selector_List, s))) {} - // convert selector schema to a selector list - else if (Selector_Schema_Obj schema = SASS_MEMORY_CAST(Selector_Schema, s)) { + if (Selector_List_Ptr extender = selector()) { + Selector_List_Ptr sl = e->selector(); + // abort on invalid selector + if (sl == NULL) return NULL; + if (Selector_Schema_Ptr schema = sl->schema()) { if (schema->has_real_parent_ref()) { - sl = eval(&schema); + // put root block on stack again (ignore parents) + // selector schema must not connect in eval! + block_stack.push_back(block_stack.at(1)); + sl = eval(sl->schema()); + block_stack.pop_back(); } else { selector_stack.push_back(0); - sl = eval(&schema); - sl->remove_parent_selectors(); + sl = eval(sl->schema()); selector_stack.pop_back(); } } - // abort on invalid selector - if (sl.isNull()) return NULL; for (Complex_Selector_Obj cs : sl->elements()) { if (!cs.isNull() && !cs->head().isNull()) { cs->head()->media_block(media_block_stack.back()); } } selector_stack.push_back(0); - expand_selector_list(&sl, extender); + expand_selector_list(sl, extender); selector_stack.pop_back(); } return 0; @@ -662,7 +660,7 @@ namespace Sass { Env* env = environment(); Definition_Obj dd = SASS_MEMORY_COPY(d); env->local_frame()[d->name() + - (d->type() == Definition::MIXIN ? "[m]" : "[f]")] = ⅆ + (d->type() == Definition::MIXIN ? "[m]" : "[f]")] = dd; if (d->type() == Definition::FUNCTION && ( Prelexer::calc_fn_call(d->name().c_str()) || @@ -696,7 +694,7 @@ namespace Sass { if (!env->has(full_name)) { error("no mixin named " + c->name(), c->pstate(), backtrace()); } - Definition_Obj def = SASS_MEMORY_CAST(Definition, (*env)[full_name]); + Definition_Obj def = Cast((*env)[full_name]); Block_Obj body = def->block(); Parameters_Obj params = def->parameters(); @@ -704,9 +702,18 @@ namespace Sass { error("Mixin \"" + c->name() + "\" does not accept a content block.", c->pstate(), backtrace()); } Expression_Obj rv = c->arguments()->perform(&eval); - Arguments_Obj args = SASS_MEMORY_CAST(Arguments, rv); + Arguments_Obj args = Cast(rv); Backtrace new_bt(backtrace(), c->pstate(), ", in mixin `" + c->name() + "`"); backtrace_stack.push_back(&new_bt); + ctx.callee_stack.push_back({ + c->name().c_str(), + c->pstate().path, + c->pstate().line + 1, + c->pstate().column + 1, + SASS_CALLEE_MIXIN, + { env } + }); + Env new_env(def->environment()); env_stack.push_back(&new_env); if (c->block()) { @@ -718,7 +725,7 @@ namespace Sass { c->block(), Definition::MIXIN); thunk->environment(env); - new_env.local_frame()["@content[m]"] = &thunk; + new_env.local_frame()["@content[m]"] = thunk; } bind(std::string("Mixin"), c->name(), params, args, &ctx, &new_env, &eval); @@ -727,7 +734,7 @@ namespace Sass { Trace_Obj trace = SASS_MEMORY_NEW(Trace, c->pstate(), c->name(), trace_block); - block_stack.push_back(&trace_block); + block_stack.push_back(trace_block); for (auto bb : body->elements()) { Statement_Obj ith = bb->perform(this); if (ith) trace->block()->append(ith); @@ -736,6 +743,7 @@ namespace Sass { env_stack.pop_back(); backtrace_stack.pop_back(); + ctx.callee_stack.pop_back(); recursions --; return trace.detach(); @@ -756,7 +764,7 @@ namespace Sass { "@content", SASS_MEMORY_NEW(Arguments, c->pstate())); - Trace_Obj trace = SASS_MEMORY_CAST_PTR(Trace, call->perform(this)); + Trace_Obj trace = Cast(call->perform(this)); if (block_stack.back()->is_root()) { selector_stack.pop_back(); @@ -771,7 +779,7 @@ namespace Sass { std::string err =std:: string("`Expand` doesn't handle ") + typeid(*n).name(); String_Quoted_Obj msg = SASS_MEMORY_NEW(String_Quoted, ParserState("[WARN]"), err); error("unknown internal error; please contact the LibSass maintainers", n->pstate(), backtrace()); - return SASS_MEMORY_NEW(Warning, ParserState("[WARN]"), &msg); + return SASS_MEMORY_NEW(Warning, ParserState("[WARN]"), msg); } // process and add to last block on stack @@ -779,7 +787,7 @@ namespace Sass { { if (b->is_root()) call_stack.push_back(b); for (size_t i = 0, L = b->length(); i < L; ++i) { - Statement_Ptr stm = &b->at(i); + Statement_Ptr stm = b->at(i); Statement_Obj ith = stm->perform(this); if (ith) block_stack.back()->append(ith); } diff --git a/src/libsass/src/expand.hpp b/src/libsass/src/expand.hpp index 1f93d2acb..2d0d5ecea 100755 --- a/src/libsass/src/expand.hpp +++ b/src/libsass/src/expand.hpp @@ -13,14 +13,12 @@ namespace Sass { class Listize; class Context; class Eval; - typedef Environment Env; struct Backtrace; class Expand : public Operation_CRTP { public: Env* environment(); - Context& context(); Selector_List_Obj selector(); Backtrace* backtrace(); diff --git a/src/libsass/src/extend.cpp b/src/libsass/src/extend.cpp index 8582de8a9..618d979db 100755 --- a/src/libsass/src/extend.cpp +++ b/src/libsass/src/extend.cpp @@ -61,8 +61,6 @@ namespace Sass { - typedef std::pair ExtensionPair; - typedef std::vector SubsetMapEntries; #ifdef DEBUG @@ -111,11 +109,6 @@ namespace Sass { } } - // Print a string representation of a Compound_Selector - typedef std::pair SelsNewSeqPair; - typedef std::vector SelsNewSeqPairCollection; - - // Print a string representation of a Compound_Selector static void printCompoundSelector(Compound_Selector_Ptr pCompoundSelector, const char* message=NULL, bool newline=true) { @@ -186,14 +179,14 @@ namespace Sass { } } - static void printSelsNewSeqPairCollection(SelsNewSeqPairCollection& collection, const char* message=NULL, bool newline=true) { + static void printSelsNewSeqPairCollection(SubSetMapLookups& collection, const char* message=NULL, bool newline=true) { if (message) { std::cerr << message; } bool first = true; std::cerr << "["; - for(SelsNewSeqPair& pair : collection) { + for(SubSetMapLookup& pair : collection) { if (first) { first = false; } else { @@ -212,8 +205,8 @@ namespace Sass { } } - // Print a string representation of a SourcesSet - static void printSourcesSet(SourcesSet& sources, Context& ctx, const char* message=NULL, bool newline=true) { + // Print a string representation of a ComplexSelectorSet + static void printSourcesSet(ComplexSelectorSet& sources, Context& ctx, const char* message=NULL, bool newline=true) { if (message) { std::cerr << message; @@ -223,7 +216,7 @@ namespace Sass { // the differences we see when debug printing. typedef std::deque SourceStrings; SourceStrings sourceStrings; - for (SourcesSet::iterator iterator = sources.begin(), iteratorEnd = sources.end(); iterator != iteratorEnd; ++iterator) { + for (ComplexSelectorSet::iterator iterator = sources.begin(), iteratorEnd = sources.end(); iterator != iteratorEnd; ++iterator) { Complex_Selector_Ptr pSource = *iterator; std::stringstream sstream; sstream << complexSelectorToNode(pSource, ctx); @@ -233,7 +226,7 @@ namespace Sass { // Sort to get consistent output std::sort(sourceStrings.begin(), sourceStrings.end()); - std::cerr << "SourcesSet["; + std::cerr << "ComplexSelectorSet["; for (SourceStrings::iterator iterator = sourceStrings.begin(), iteratorEnd = sourceStrings.end(); iterator != iteratorEnd; ++iterator) { std::string source = *iterator; if (iterator != sourceStrings.begin()) { @@ -249,10 +242,10 @@ namespace Sass { } - std::ostream& operator<<(std::ostream& os, SubsetMapEntries& entries) { + std::ostream& operator<<(std::ostream& os, SubSetMapPairs& entries) { os << "SUBSET_MAP_ENTRIES["; - for (SubsetMapEntries::iterator iterator = entries.begin(), endIterator = entries.end(); iterator != endIterator; ++iterator) { + for (SubSetMapPairs::iterator iterator = entries.begin(), endIterator = entries.end(); iterator != endIterator; ++iterator) { Complex_Selector_Obj pExtComplexSelector = iterator->first; // The selector up to where the @extend is (ie, the thing to merge) Compound_Selector_Obj pExtCompoundSelector = iterator->second; // The stuff after the @extend @@ -292,11 +285,11 @@ namespace Sass { Position noPosition(-1, -1, -1); Element_Selector_Obj fakeParent = SASS_MEMORY_NEW(Element_Selector, ParserState("[FAKE]"), "temp"); Compound_Selector_Obj fakeHead = SASS_MEMORY_NEW(Compound_Selector, ParserState("[FAKE]"), 1 /*size*/); - fakeHead->elements().push_back(&fakeParent); - Complex_Selector_Obj fakeParentContainer = SASS_MEMORY_NEW(Complex_Selector, ParserState("[FAKE]"), Complex_Selector::ANCESTOR_OF, &fakeHead /*head*/, NULL /*tail*/); + fakeHead->elements().push_back(fakeParent); + Complex_Selector_Obj fakeParentContainer = SASS_MEMORY_NEW(Complex_Selector, ParserState("[FAKE]"), Complex_Selector::ANCESTOR_OF, fakeHead /*head*/, NULL /*tail*/); - pOne->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF); - pTwo->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF); + pOne->set_innermost(fakeParentContainer, Complex_Selector::ANCESTOR_OF); + pTwo->set_innermost(fakeParentContainer, Complex_Selector::ANCESTOR_OF); bool isSuperselector = pOne->is_superselector_of(pTwo); @@ -318,7 +311,7 @@ namespace Sass { for (ComplexSelectorDeque::const_iterator iter = deque.begin(), iterEnd = deque.end(); iter != iterEnd; iter++) { Complex_Selector_Obj pChild = *iter; - result.collection()->push_back(complexSelectorToNode(&pChild, ctx)); + result.collection()->push_back(complexSelectorToNode(pChild, ctx)); } return result; @@ -341,7 +334,7 @@ namespace Sass { end */ - if (selectors_equal(*pOne, *pTwo, true /*simpleSelectorOrderDependent*/)) { + if (*pOne == *pTwo) { pOut = pOne; return true; } @@ -350,12 +343,12 @@ namespace Sass { return false; } - if (parentSuperselector(&pOne, &pTwo, mCtx)) { + if (parentSuperselector(pOne, pTwo, mCtx)) { pOut = pTwo; return true; } - if (parentSuperselector(&pTwo, &pOne, mCtx)) { + if (parentSuperselector(pTwo, pOne, mCtx)) { pOut = pOne; return true; } @@ -420,7 +413,7 @@ namespace Sass { for (size_t j = 1; j < y.size(); j++) { Complex_Selector_Obj pCompareOut; - if (comparator(&x[i], &y[j], pCompareOut)) { + if (comparator(x[i], y[j], pCompareOut)) { c[i][j] = c[i - 1][j - 1] + 1; } else { c[i][j] = std::max(c[i][j - 1], c[i - 1][j]); @@ -569,12 +562,12 @@ namespace Sass { // best guess at this point is that we're cloning an object somewhere and maintaining the sources when we shouldn't be. This is purely // a guess though. unsigned long maxSpecificity = isReplace ? pSeq1->specificity() : 0; - SourcesSet sources = pSeq1->sources(); + ComplexSelectorSet sources = pSeq1->sources(); DEBUG_PRINTLN(TRIM, "TRIM SEQ1: " << seq1) DEBUG_EXEC(TRIM, printSourcesSet(sources, ctx, "TRIM SOURCES: ")) - for (SourcesSet::iterator sourcesSetIterator = sources.begin(), sourcesSetIteratorEnd = sources.end(); sourcesSetIterator != sourcesSetIteratorEnd; ++sourcesSetIterator) { + for (ComplexSelectorSet::iterator sourcesSetIterator = sources.begin(), sourcesSetIteratorEnd = sources.end(); sourcesSetIterator != sourcesSetIteratorEnd; ++sourcesSetIterator) { const Complex_Selector_Obj& pCurrentSelector = *sourcesSetIterator; maxSpecificity = std::max(maxSpecificity, pCurrentSelector->specificity()); } @@ -655,13 +648,13 @@ namespace Sass { Position noPosition(-1, -1, -1); Element_Selector_Obj fakeParent = SASS_MEMORY_NEW(Element_Selector, ParserState("[FAKE]"), "temp"); Compound_Selector_Obj fakeHead = SASS_MEMORY_NEW(Compound_Selector, ParserState("[FAKE]"), 1 /*size*/); - fakeHead->elements().push_back(&fakeParent); - Complex_Selector_Obj fakeParentContainer = SASS_MEMORY_NEW(Complex_Selector, ParserState("[FAKE]"), Complex_Selector::ANCESTOR_OF, &fakeHead /*head*/, NULL /*tail*/); + fakeHead->elements().push_back(fakeParent); + Complex_Selector_Obj fakeParentContainer = SASS_MEMORY_NEW(Complex_Selector, ParserState("[FAKE]"), Complex_Selector::ANCESTOR_OF, fakeHead /*head*/, NULL /*tail*/); Complex_Selector_Obj pOneWithFakeParent = nodeToComplexSelector(one, ctx); - pOneWithFakeParent->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF); + pOneWithFakeParent->set_innermost(fakeParentContainer, Complex_Selector::ANCESTOR_OF); Complex_Selector_Obj pTwoWithFakeParent = nodeToComplexSelector(two, ctx); - pTwoWithFakeParent->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF); + pTwoWithFakeParent->set_innermost(fakeParentContainer, Complex_Selector::ANCESTOR_OF); return pOneWithFakeParent->is_superselector_of(pTwoWithFakeParent); } @@ -848,7 +841,7 @@ namespace Sass { DefaultLcsComparator lcsDefaultComparator; Node opsLcs = lcs(ops1, ops2, lcsDefaultComparator, ctx); - if (!(nodesEqual(opsLcs, ops1, true) || nodesEqual(opsLcs, ops2, true))) { + if (!(opsLcs == ops1 || opsLcs == ops2)) { return Node::createNil(); } @@ -945,7 +938,7 @@ namespace Sass { // If there are multiple operators, something hacky's going on. If one is a supersequence of the other, use that, otherwise give up. - if (!(nodesEqual(opsLcs, ops1, true) || nodesEqual(opsLcs, ops2, true))) { + if (!(opsLcs == ops1 || opsLcs == ops2)) { return Node::createNil(); } @@ -988,7 +981,7 @@ namespace Sass { Complex_Selector_Obj pMergedWrapper = SASS_MEMORY_CLONE(sel1.selector()); // Clone the Complex_Selector to get back to something we can transform to a node once we replace the head with the unification result // TODO: does subject matter? Ruby: return unless merged = sel1.unify(sel2.members, sel2.subject?) - Compound_Selector_Ptr pMerged = sel1.selector()->head()->unify_with(&sel2.selector()->head(), ctx); + Compound_Selector_Ptr pMerged = sel1.selector()->head()->unify_with(sel2.selector()->head(), ctx); pMergedWrapper->head(pMerged); DEBUG_EXEC(ALL, printCompoundSelector(pMerged, "MERGED: ")) @@ -1011,7 +1004,7 @@ namespace Sass { if (pMerged) { Node mergedPerm = Node::createCollection(); - mergedPerm.collection()->push_back(Node::createSelector(&pMergedWrapper, ctx)); + mergedPerm.collection()->push_back(Node::createSelector(pMergedWrapper, ctx)); mergedPerm.collection()->push_back(Node::createCombinator(Complex_Selector::PRECEDES)); newRes.collection()->push_back(mergedPerm); } @@ -1047,7 +1040,7 @@ namespace Sass { Complex_Selector_Obj pMergedWrapper = SASS_MEMORY_CLONE(plusSel.selector()); // Clone the Complex_Selector to get back to something we can transform to a node once we replace the head with the unification result // TODO: does subject matter? Ruby: merged = plus_sel.unify(tilde_sel.members, tilde_sel.subject?) - Compound_Selector_Ptr pMerged = plusSel.selector()->head()->unify_with(&tildeSel.selector()->head(), ctx); + Compound_Selector_Ptr pMerged = plusSel.selector()->head()->unify_with(tildeSel.selector()->head(), ctx); pMergedWrapper->head(pMerged); DEBUG_EXEC(ALL, printCompoundSelector(pMerged, "MERGED: ")) @@ -1063,7 +1056,7 @@ namespace Sass { if (pMerged) { Node mergedPerm = Node::createCollection(); - mergedPerm.collection()->push_back(Node::createSelector(&pMergedWrapper, ctx)); + mergedPerm.collection()->push_back(Node::createSelector(pMergedWrapper, ctx)); mergedPerm.collection()->push_back(Node::createCombinator(Complex_Selector::ADJACENT_TO)); newRes.collection()->push_back(mergedPerm); } @@ -1096,7 +1089,7 @@ namespace Sass { Complex_Selector_Obj pMergedWrapper = SASS_MEMORY_CLONE(sel1.selector()); // Clone the Complex_Selector to get back to something we can transform to a node once we replace the head with the unification result // TODO: does subject matter? Ruby: return unless merged = sel1.unify(sel2.members, sel2.subject?) - Compound_Selector_Ptr pMerged = sel1.selector()->head()->unify_with(&sel2.selector()->head(), ctx); + Compound_Selector_Ptr pMerged = sel1.selector()->head()->unify_with(sel2.selector()->head(), ctx); pMergedWrapper->head(pMerged); DEBUG_EXEC(ALL, printCompoundSelector(pMerged, "MERGED: ")) @@ -1106,7 +1099,7 @@ namespace Sass { } res.collection()->push_front(op1); - res.collection()->push_front(Node::createSelector(&pMergedWrapper, ctx)); + res.collection()->push_front(Node::createSelector(pMergedWrapper, ctx)); DEBUG_PRINTLN(ALL, "RESULT: " << res) @@ -1530,9 +1523,9 @@ namespace Sass { template class GroupByToAFunctor { public: - KeyType operator()(ExtensionPair& extPair) const { + KeyType operator()(SubSetMapPair& extPair) const { Complex_Selector_Obj pSelector = extPair.first; - return &pSelector; + return pSelector; } }; static Node extendCompoundSelector( @@ -1547,48 +1540,42 @@ namespace Sass { Node extendedSelectors = Node::createCollection(); // extendedSelectors.got_line_feed = true; - SubsetMapEntries entries = subset_map.get_v(pSelector); - - typedef std::vector > > GroupedByToAResult; + SubSetMapPairs entries = subset_map.get_v(pSelector); GroupByToAFunctor extPairKeyFunctor; - GroupedByToAResult arr; + SubSetMapResults arr; group_by_to_a(entries, extPairKeyFunctor, arr); - typedef std::pair SelsNewSeqPair; - typedef std::vector SelsNewSeqPairCollection; - - - SelsNewSeqPairCollection holder; + SubSetMapLookups holder; - for (GroupedByToAResult::iterator groupedIter = arr.begin(), groupedIterEnd = arr.end(); groupedIter != groupedIterEnd; groupedIter++) { - std::pair >& groupedPair = *groupedIter; + for (SubSetMapResults::iterator groupedIter = arr.begin(), groupedIterEnd = arr.end(); groupedIter != groupedIterEnd; groupedIter++) { + SubSetMapResult& groupedPair = *groupedIter; Complex_Selector_Obj seq = groupedPair.first; - std::vector& group = groupedPair.second; + SubSetMapPairs& group = groupedPair.second; - DEBUG_EXEC(EXTEND_COMPOUND, printComplexSelector(&seq, "SEQ: ")) + DEBUG_EXEC(EXTEND_COMPOUND, printComplexSelector(seq, "SEQ: ")) // changing this makes aua Compound_Selector_Obj pSels = SASS_MEMORY_NEW(Compound_Selector, pSelector->pstate()); - for (std::vector::iterator groupIter = group.begin(), groupIterEnd = group.end(); groupIter != groupIterEnd; groupIter++) { - ExtensionPair& pair = *groupIter; + for (SubSetMapPairs::iterator groupIter = group.begin(), groupIterEnd = group.end(); groupIter != groupIterEnd; groupIter++) { + SubSetMapPair& pair = *groupIter; Compound_Selector_Obj pCompound = pair.second; for (size_t index = 0; index < pCompound->length(); index++) { Simple_Selector_Obj pSimpleSelector = (*pCompound)[index]; - pSels->append(&pSimpleSelector); + pSels->append(pSimpleSelector); pCompound->extended(true); } } - DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(&pSels, "SELS: ")) + DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSels, "SELS: ")) - Complex_Selector_Ptr pExtComplexSelector = &seq; // The selector up to where the @extend is (ie, the thing to merge) + Complex_Selector_Ptr pExtComplexSelector = seq; // The selector up to where the @extend is (ie, the thing to merge) // TODO: This can return a Compound_Selector with no elements. Should that just be returning NULL? // RUBY: self_without_sel = Sass::Util.array_minus(members, sels) - Compound_Selector_Obj pSelectorWithoutExtendSelectors = pSelector->minus(&pSels, ctx); + Compound_Selector_Obj pSelectorWithoutExtendSelectors = pSelector->minus(pSels, ctx); DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelector, "MEMBERS: ")) DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelectorWithoutExtendSelectors, "SELF_WO_SEL: ")) @@ -1598,7 +1585,7 @@ namespace Sass { if (!pInnermostCompoundSelector) { pInnermostCompoundSelector = SASS_MEMORY_NEW(Compound_Selector, pSelector->pstate()); } - Compound_Selector_Obj pUnifiedSelector = pInnermostCompoundSelector->unify_with(&pSelectorWithoutExtendSelectors, ctx); + Compound_Selector_Obj pUnifiedSelector = pInnermostCompoundSelector->unify_with(pSelectorWithoutExtendSelectors, ctx); DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pInnermostCompoundSelector, "LHS: ")) DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelectorWithoutExtendSelectors, "RHS: ")) @@ -1621,10 +1608,10 @@ namespace Sass { Complex_Selector_Obj pNewInnerMost = SASS_MEMORY_NEW(Complex_Selector, pSelector->pstate(), Complex_Selector::ANCESTOR_OF, pUnifiedSelector, NULL); Complex_Selector::Combinator combinator = pNewSelector->clear_innermost(); - pNewSelector->set_innermost(&pNewInnerMost, combinator); + pNewSelector->set_innermost(pNewInnerMost, combinator); #ifdef DEBUG - SourcesSet debugSet; + ComplexSelectorSet debugSet; debugSet = pNewSelector->sources(); if (debugSet.size() > 0) { throw std::runtime_error("The new selector should start with no sources. Something needs to be cloned to fix this."); @@ -1640,9 +1627,10 @@ namespace Sass { // Set the sources on our new Complex_Selector to the sources of this simple sequence plus the thing we're extending. DEBUG_PRINTLN(EXTEND_COMPOUND, "SOURCES SETTING ON NEW SEQ: " << complexSelectorToNode(pNewSelector, ctx)) - DEBUG_EXEC(EXTEND_COMPOUND, SourcesSet oldSet = pNewSelector->sources(); printSourcesSet(oldSet, ctx, "SOURCES NEW SEQ BEGIN: ")) + DEBUG_EXEC(EXTEND_COMPOUND, ComplexSelectorSet oldSet = pNewSelector->sources(); printSourcesSet(oldSet, ctx, "SOURCES NEW SEQ BEGIN: ")) - SourcesSet newSourcesSet = pSelector->sources(); + // I actually want to create a copy here (performance!) + ComplexSelectorSet newSourcesSet = pSelector->sources(); // XXX DEBUG_EXEC(EXTEND_COMPOUND, printSourcesSet(newSourcesSet, ctx, "SOURCES THIS EXTEND: ")) newSourcesSet.insert(pExtComplexSelector); @@ -1651,7 +1639,7 @@ namespace Sass { // RUBY: new_seq.add_sources!(sources + [seq]) pNewSelector->addSources(newSourcesSet, ctx); - DEBUG_EXEC(EXTEND_COMPOUND, SourcesSet newSet = pNewSelector->sources(); printSourcesSet(newSet, ctx, "SOURCES ON NEW SELECTOR AFTER ADD: ")) + DEBUG_EXEC(EXTEND_COMPOUND, ComplexSelectorSet newSet = pNewSelector->sources(); printSourcesSet(newSet, ctx, "SOURCES ON NEW SELECTOR AFTER ADD: ")) DEBUG_EXEC(EXTEND_COMPOUND, printSourcesSet(pSelector->sources(), ctx, "SOURCES THIS EXTEND WHICH SHOULD BE SAME STILL: ")) @@ -1661,8 +1649,8 @@ namespace Sass { } - for (SelsNewSeqPairCollection::iterator holderIter = holder.begin(), holderIterEnd = holder.end(); holderIter != holderIterEnd; holderIter++) { - SelsNewSeqPair& pair = *holderIter; + for (SubSetMapLookups::iterator holderIter = holder.begin(), holderIterEnd = holder.end(); holderIter != holderIterEnd; holderIter++) { + SubSetMapLookup& pair = *holderIter; Compound_Selector_Obj pSels = pair.first; Complex_Selector_Obj pNewSelector = pair.second; @@ -1679,7 +1667,7 @@ namespace Sass { DEBUG_PRINTLN(EXTEND_COMPOUND, "RECURSING DO EXTEND: " << complexSelectorToNode(pNewSelector, ctx)) - Node recurseExtendedSelectors = extendComplexSelector(&pNewSelector, ctx, subset_map, recurseSeen, isReplace, false); // !:isOriginal + Node recurseExtendedSelectors = extendComplexSelector(pNewSelector, ctx, subset_map, recurseSeen, isReplace, false); // !:isOriginal DEBUG_PRINTLN(EXTEND_COMPOUND, "RECURSING DO EXTEND RETURN: " << recurseExtendedSelectors) @@ -1717,8 +1705,8 @@ namespace Sass { Compound_Selector_Obj pHead = pIter->head(); if (pHead) { - SubsetMapEntries entries = subset_map.get_v(pHead); - for (ExtensionPair ext : entries) { + SubSetMapPairs entries = subset_map.get_v(pHead); + for (SubSetMapPair ext : entries) { // check if both selectors have the same media block parent // if (ext.first->media_block() == pComplexSelector->media_block()) continue; if (ext.second->media_block() == 0) continue; @@ -1799,7 +1787,7 @@ namespace Sass { Compound_Selector_Obj pCompoundSelector = sseqOrOp.selector()->head(); // RUBY: extended = sseq_or_op.do_extend(extends, parent_directives, replace, seen) - Node extended = extendCompoundSelector(&pCompoundSelector, ctx, subset_map, seen, isReplace); + Node extended = extendCompoundSelector(pCompoundSelector, ctx, subset_map, seen, isReplace); if (sseqOrOp.got_line_feed) extended.got_line_feed = true; DEBUG_PRINTLN(EXTEND_COMPLEX, "EXTENDED: " << extended) @@ -1810,7 +1798,7 @@ namespace Sass { // RUBY: extended.first.add_sources!([self]) if original && !has_placeholder? if (isOriginal && !pComplexSelector->has_placeholder()) { - SourcesSet srcset; + ComplexSelectorSet srcset; srcset.insert(pComplexSelector); pJustCurrentCompoundSelector->addSources(srcset, ctx); DEBUG_PRINTLN(EXTEND_COMPLEX, "ADD SOURCES: " << *pComplexSelector) @@ -1829,7 +1817,7 @@ namespace Sass { if (!isSuperselector) { if (sseqOrOp.got_line_feed) pJustCurrentCompoundSelector->has_line_feed(sseqOrOp.got_line_feed); - extended.collection()->push_front(complexSelectorToNode(&pJustCurrentCompoundSelector, ctx)); + extended.collection()->push_front(complexSelectorToNode(pJustCurrentCompoundSelector, ctx)); } DEBUG_PRINTLN(EXTEND_COMPLEX, "CHOICES UNSHIFTED: " << extended) @@ -1909,16 +1897,16 @@ namespace Sass { // run through the extend code (which does a data model transformation), check if there is anything to extend before doing // the extend. We might be able to optimize extendComplexSelector, but this approach keeps us closer to ruby sass (which helps // when debugging). - if (!complexSelectorHasExtension(&pSelector, ctx, subset_map, seen)) { - pNewSelectors->append(&pSelector); + if (!complexSelectorHasExtension(pSelector, ctx, subset_map, seen)) { + pNewSelectors->append(pSelector); continue; } extendedSomething = true; - Node extendedSelectors = extendComplexSelector(&pSelector, ctx, subset_map, seen, isReplace, true); + Node extendedSelectors = extendComplexSelector(pSelector, ctx, subset_map, seen, isReplace, true); if (!pSelector->has_placeholder()) { - if (!extendedSelectors.contains(complexSelectorToNode(&pSelector, ctx), true /*simpleSelectorOrderDependent*/)) { + if (!extendedSelectors.contains(complexSelectorToNode(pSelector, ctx), true /*simpleSelectorOrderDependent*/)) { pNewSelectors->append(pSelector); continue; } @@ -1933,10 +1921,10 @@ namespace Sass { } } - Remove_Placeholders remove_placeholders(ctx); + Remove_Placeholders remove_placeholders; // it seems that we have to remove the place holders early here // normally we do this as the very last step (compare to ruby sass) - pNewSelectors = remove_placeholders.remove_placeholders(&pNewSelectors); + pNewSelectors = remove_placeholders.remove_placeholders(pNewSelectors); // unwrap all wrapped selectors with inner lists for (Complex_Selector_Obj cur : pNewSelectors->elements()) { @@ -1949,9 +1937,9 @@ namespace Sass { // create a copy since we add multiple items if stuff get unwrapped Compound_Selector_Obj cpy_head = SASS_MEMORY_NEW(Compound_Selector, cur->pstate()); for (Simple_Selector_Obj hs : *cur->head()) { - if (Wrapped_Selector_Obj ws = SASS_MEMORY_CAST(Wrapped_Selector, hs)) { + if (Wrapped_Selector_Obj ws = Cast(hs)) { ws->selector(SASS_MEMORY_CLONE(ws->selector())); - if (Selector_List_Obj sl = SASS_MEMORY_CAST(Selector_List, ws->selector())) { + if (Selector_List_Obj sl = Cast(ws->selector())) { // special case for ruby ass if (sl->empty()) { // this seems inconsistent but it is how ruby sass seems to remove parentheses @@ -1964,34 +1952,34 @@ namespace Sass { for (size_t i = 0; i < ext_sl->length(); i += 1) { if (Complex_Selector_Obj ext_cs = ext_sl->at(i)) { // create clones for wrapped selector and the inner list - Wrapped_Selector_Obj cpy_ws = SASS_MEMORY_COPY(&ws); + Wrapped_Selector_Obj cpy_ws = SASS_MEMORY_COPY(ws); Selector_List_Obj cpy_ws_sl = SASS_MEMORY_NEW(Selector_List, sl->pstate()); // remove parent selectors from inner selector if (ext_cs->first() && ext_cs->first()->head()->length() > 0) { - Wrapped_Selector_Ptr ext_ws = SASS_MEMORY_CAST(Wrapped_Selector, ext_cs->first()->head()->first()); + Wrapped_Selector_Ptr ext_ws = Cast(ext_cs->first()->head()->first()); if (ext_ws/* && ext_cs->length() == 1*/) { - Selector_List_Obj ws_cs = SASS_MEMORY_CAST(Selector_List, ext_ws->selector()); + Selector_List_Obj ws_cs = Cast(ext_ws->selector()); Compound_Selector_Obj ws_ss = ws_cs->first()->head(); if (!( - SASS_MEMORY_CAST(Pseudo_Selector, ws_ss->first()) || - SASS_MEMORY_CAST(Element_Selector, ws_ss->first()) || - SASS_MEMORY_CAST(Placeholder_Selector, ws_ss->first()) + Cast(ws_ss->first()) || + Cast(ws_ss->first()) || + Cast(ws_ss->first()) )) continue; } cpy_ws_sl->append(ext_cs->first()); } // assign list to clone - cpy_ws->selector(&cpy_ws_sl); + cpy_ws->selector(cpy_ws_sl); // append the clone - cpy_head->append(&cpy_ws); + cpy_head->append(cpy_ws); } } } } else { - cpy_head->append(&hs); + cpy_head->append(hs); } } else { - cpy_head->append(&hs); + cpy_head->append(hs); } } // replace header @@ -2024,8 +2012,9 @@ namespace Sass { for (size_t i = 0, L = b->length(); i < L; ++i) { Statement_Obj stm = b->at(i); - if (dynamic_cast(&stm)) { - // Do nothing. This doesn't count as a statement that causes extension since we'll iterate over this rule set in a future visit and try to extend it. + if (Cast(stm)) { + // Do nothing. This doesn't count as a statement that causes extension since we'll + // iterate over this rule set in a future visit and try to extend it. } else { return true; @@ -2041,7 +2030,7 @@ namespace Sass { template static void extendObjectWithSelectorAndBlock(ObjectType* pObject, Context& ctx, Subset_Map& subset_map) { - DEBUG_PRINTLN(EXTEND_OBJECT, "FOUND SELECTOR: " << static_cast(pObject->selector())->to_string(ctx.c_options)) + DEBUG_PRINTLN(EXTEND_OBJECT, "FOUND SELECTOR: " << Cast(pObject->selector())->to_string(ctx.c_options)) // Ruby sass seems to filter nodes that don't have any content well before we get here. I'm not sure the repercussions // of doing so, so for now, let's just not extend things that won't be output later. @@ -2051,13 +2040,13 @@ namespace Sass { } bool extendedSomething = false; - Selector_List_Obj pNewSelectorList = Extend::extendSelectorList(SASS_MEMORY_CAST(Selector_List, pObject->selector()), ctx, subset_map, false, extendedSomething); + Selector_List_Obj pNewSelectorList = Extend::extendSelectorList(Cast(pObject->selector()), ctx, subset_map, false, extendedSomething); if (extendedSomething && pNewSelectorList) { - DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND ORIGINAL SELECTORS: " << static_cast(pObject->selector())->to_string(ctx.c_options)) + DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND ORIGINAL SELECTORS: " << Cast(pObject->selector())->to_string(ctx.c_options)) DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND SETTING NEW SELECTORS: " << pNewSelectorList->to_string(ctx.c_options)) pNewSelectorList->remove_parent_selectors(); - pObject->selector(&pNewSelectorList); + pObject->selector(pNewSelectorList); } else { DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND DID NOT TRY TO EXTEND ANYTHING") } @@ -2080,8 +2069,10 @@ namespace Sass { if (b->is_root()) { // debug_subset_map(subset_map); for(auto const &it : subset_map.values()) { - Complex_Selector_Ptr sel = it.first ? &it.first->first() : NULL; - Compound_Selector_Ptr ext = it.second ? &it.second : NULL; + Complex_Selector_Ptr sel = NULL; + Compound_Selector_Ptr ext = NULL; + if (it.first) sel = it.first->first(); + if (it.second) ext = it.second; if (ext && (ext->extended() || ext->is_optional())) continue; std::string str_sel(sel->to_string({ NESTED, 5 })); std::string str_ext(ext->to_string({ NESTED, 5 })); @@ -2114,7 +2105,7 @@ namespace Sass { void Extend::operator()(Directive_Ptr a) { - // Selector_List_Ptr ls = dynamic_cast(a->selector()); + // Selector_List_Ptr ls = Cast(a->selector()); // selector_stack.push_back(ls); if (a->block()) a->block()->perform(this); // exp.selector_stack.pop_back(); diff --git a/src/libsass/src/file.cpp b/src/libsass/src/file.cpp index 8b2d19498..cac5fb61d 100755 --- a/src/libsass/src/file.cpp +++ b/src/libsass/src/file.cpp @@ -20,6 +20,7 @@ #include "context.hpp" #include "prelexer.hpp" #include "utf8_string.hpp" +#include "sass_functions.hpp" #include "sass2scss.h" #ifdef _WIN32 @@ -301,13 +302,9 @@ namespace Sass { // (2) underscore + given // (3) underscore + given + extension // (4) given + extension - std::vector resolve_includes(const std::string& root, const std::string& file) + std::vector resolve_includes(const std::string& root, const std::string& file, const std::vector& exts) { std::string filename = join_paths(root, file); - // supported extensions - const std::vector exts = { - ".scss", ".sass", ".css" - }; // split the filename std::string base(dir_name(file)); std::string name(base_name(file)); @@ -336,8 +333,41 @@ namespace Sass { return includes; } - // helper function to resolve a filename + std::vector find_files(const std::string& file, const std::vector paths) + { + std::vector includes; + for (std::string path : paths) { + std::string abs_path(join_paths(path, file)); + if (file_exists(abs_path)) includes.push_back(abs_path); + } + return includes; + } + + std::vector find_files(const std::string& file, struct Sass_Compiler* compiler) + { + // get the last import entry to get current base directory + // struct Sass_Options* options = sass_compiler_get_options(compiler); + Sass_Import_Entry import = sass_compiler_get_last_import(compiler); + const std::vector& incs = compiler->cpp_ctx->include_paths; + // create the vector with paths to lookup + std::vector paths(1 + incs.size()); + paths.push_back(dir_name(import->abs_path)); + paths.insert(paths.end(), incs.begin(), incs.end()); + // dispatch to find files in paths + return find_files(file, paths); + } + + // helper function to search one file in all include paths + // this is normally not used internally by libsass (C-API sugar) std::string find_file(const std::string& file, const std::vector paths) + { + if (file.empty()) return file; + auto res = find_files(file, paths); + return res.empty() ? "" : res.front(); + } + + // helper function to resolve a filename + std::string find_include(const std::string& file, const std::vector paths) { // search in every include path for a match for (size_t i = 0, S = paths.size(); i < S; ++i) @@ -349,20 +379,6 @@ namespace Sass { return std::string(""); } - // inc paths can be directly passed from C code - std::string find_file(const std::string& file, const char* paths[]) - { - if (paths == 0) return std::string(""); - std::vector includes(0); - // includes.push_back("."); - const char** it = paths; - while (it && *it) { - includes.push_back(*it); - ++it; - } - return find_file(file, includes); - } - // try to load the given filename // returned memory must be freed // will auto convert .sass files @@ -414,5 +430,25 @@ namespace Sass { } } + // split a path string delimited by semicolons or colons (OS dependent) + std::vector split_path_list(const char* str) + { + std::vector paths; + if (str == NULL) return paths; + // find delimiter via prelexer (return zero at end) + const char* end = Prelexer::find_first(str); + // search until null delimiter + while (end) { + // add path from current position to delimiter + paths.push_back(std::string(str, end - str)); + str = end + 1; // skip delimiter + end = Prelexer::find_first(str); + } + // add path from current position to end + paths.push_back(std::string(str)); + // return back + return paths; + } + } } diff --git a/src/libsass/src/file.hpp b/src/libsass/src/file.hpp index 8e5a0b041..279b9e9f6 100755 --- a/src/libsass/src/file.hpp +++ b/src/libsass/src/file.hpp @@ -4,6 +4,7 @@ #include #include +#include "sass/context.h" #include "ast_fwd_decl.hpp" namespace Sass { @@ -47,9 +48,16 @@ namespace Sass { std::string abs2rel(const std::string& path, const std::string& base = ".", const std::string& cwd = get_cwd()); // helper function to resolve a filename + // searching without variations in all paths + std::string find_file(const std::string& file, struct Sass_Compiler* options); std::string find_file(const std::string& file, const std::vector paths); - // inc paths can be directly passed from C code - std::string find_file(const std::string& file, const char** paths); + + // helper function to resolve a include filename + // this has the original resolve logic for sass include + std::string find_include(const std::string& file, const std::vector paths); + + // split a path string delimited by semicolons or colons (OS dependent) + std::vector split_path_list(const char* paths); // try to load the given filename // returned memory must be freed @@ -113,7 +121,10 @@ namespace Sass { namespace File { - std::vector resolve_includes(const std::string& root, const std::string& file); + static std::vector defaultExtensions = { ".scss", ".sass", ".css" }; + + std::vector resolve_includes(const std::string& root, const std::string& file, + const std::vector& exts = defaultExtensions); } diff --git a/src/libsass/src/functions.cpp b/src/libsass/src/functions.cpp index fcbd6cc59..d1c648207 100755 --- a/src/libsass/src/functions.cpp +++ b/src/libsass/src/functions.cpp @@ -108,7 +108,7 @@ namespace Sass { T* get_arg(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtrace* backtrace) { // Minimal error handling -- the expectation is that built-ins will be written correctly! - T* val = dynamic_cast(&env[argname]); + T* val = Cast(env[argname]); if (!val) { std::string msg("argument `"); msg += argname; @@ -124,10 +124,10 @@ namespace Sass { Map_Ptr get_arg_m(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtrace* backtrace, Context& ctx) { // Minimal error handling -- the expectation is that built-ins will be written correctly! - Map_Ptr val = SASS_MEMORY_CAST(Map, env[argname]); + Map_Ptr val = Cast(env[argname]); if (val) return val; - List_Ptr lval = SASS_MEMORY_CAST(List, env[argname]); + List_Ptr lval = Cast(env[argname]); if (lval && lval->length() == 0) return SASS_MEMORY_NEW(Map, pstate, 0); // fallback on get_arg for error handling @@ -163,10 +163,10 @@ namespace Sass { msg << "a list of strings, or a list of lists of strings for `" << function_name(sig) << "'"; error(msg.str(), pstate); } - if (String_Constant_Ptr str = SASS_MEMORY_CAST(String_Constant, exp)) { + if (String_Constant_Ptr str = Cast(exp)) { str->quote_mark(0); } - std::string exp_src = exp->to_string(ctx.c_options) + "{"; + std::string exp_src = exp->to_string(ctx.c_options); return Parser::parse_selector(exp_src.c_str(), ctx); } @@ -178,12 +178,13 @@ namespace Sass { msg << argname << ": null is not a string for `" << function_name(sig) << "'"; error(msg.str(), pstate); } - if (String_Constant_Ptr str = SASS_MEMORY_CAST(String_Constant, exp)) { + if (String_Constant_Ptr str = Cast(exp)) { str->quote_mark(0); } - std::string exp_src = exp->to_string(ctx.c_options) + "{"; + std::string exp_src = exp->to_string(ctx.c_options); Selector_List_Obj sel_list = Parser::parse_selector(exp_src.c_str(), ctx); - return (sel_list->length() > 0) ? &sel_list->first()->tail()->head() : 0; + if (sel_list->length() == 0) return NULL; + return sel_list->first()->tail()->head(); } #ifdef __MINGW32__ @@ -285,13 +286,7 @@ namespace Sass { BUILT_IN(blue) { return SASS_MEMORY_NEW(Number, pstate, ARG("$color", Color)->b()); } - Signature mix_sig = "mix($color-1, $color-2, $weight: 50%)"; - BUILT_IN(mix) - { - Color_Ptr color1 = ARG("$color-1", Color); - Color_Ptr color2 = ARG("$color-2", Color); - Number_Ptr weight = ARGR("$weight", Number, 0, 100); - + Color* colormix(Context& ctx, ParserState& pstate, Color* color1, Color* color2, Number* weight) { double p = weight->value()/100; double w = 2*p - 1; double a = color1->a() - color2->a(); @@ -307,6 +302,16 @@ namespace Sass { color1->a()*p + color2->a()*(1-p)); } + Signature mix_sig = "mix($color-1, $color-2, $weight: 50%)"; + BUILT_IN(mix) + { + Color_Obj color1 = ARG("$color-1", Color); + Color_Obj color2 = ARG("$color-2", Color); + Number_Obj weight = ARGR("$weight", Number, 0, 100); + return colormix(ctx, pstate, color1, color2, weight); + + } + //////////////// // HSL FUNCTIONS //////////////// @@ -504,7 +509,7 @@ namespace Sass { BUILT_IN(saturate) { // CSS3 filter function overload: pass literal through directly - Number_Ptr amount = SASS_MEMORY_CAST(Number, env["$amount"]); + Number_Ptr amount = Cast(env["$amount"]); if (!amount) { return SASS_MEMORY_NEW(String_Quoted, pstate, "saturate(" + env["$color"]->to_string(ctx.c_options) + ")"); } @@ -564,7 +569,7 @@ namespace Sass { BUILT_IN(grayscale) { // CSS3 filter function overload: pass literal through directly - Number_Ptr amount = SASS_MEMORY_CAST(Number, env["$color"]); + Number_Ptr amount = Cast(env["$color"]); if (amount) { return SASS_MEMORY_NEW(String_Quoted, pstate, "grayscale(" + amount->to_string(ctx.c_options) + ")"); } @@ -596,22 +601,24 @@ namespace Sass { pstate); } - Signature invert_sig = "invert($color)"; + Signature invert_sig = "invert($color, $weight: 100%)"; BUILT_IN(invert) { // CSS3 filter function overload: pass literal through directly - Number_Ptr amount = SASS_MEMORY_CAST(Number, env["$color"]); + Number_Ptr amount = Cast(env["$color"]); if (amount) { return SASS_MEMORY_NEW(String_Quoted, pstate, "invert(" + amount->to_string(ctx.c_options) + ")"); } + Number_Obj weight = ARGR("$weight", Number, 0, 100); Color_Ptr rgb_color = ARG("$color", Color); - return SASS_MEMORY_NEW(Color, + Color_Obj inv = SASS_MEMORY_NEW(Color, pstate, 255 - rgb_color->r(), 255 - rgb_color->g(), 255 - rgb_color->b(), rgb_color->a()); + return colormix(ctx, pstate, inv, rgb_color, weight); } //////////////////// @@ -621,13 +628,13 @@ namespace Sass { Signature opacity_sig = "opacity($color)"; BUILT_IN(alpha) { - String_Constant_Ptr ie_kwd = SASS_MEMORY_CAST(String_Constant, env["$color"]); + String_Constant_Ptr ie_kwd = Cast(env["$color"]); if (ie_kwd) { return SASS_MEMORY_NEW(String_Quoted, pstate, "alpha(" + ie_kwd->value() + ")"); } // CSS3 filter function overload: pass literal through directly - Number_Ptr amount = SASS_MEMORY_CAST(Number, env["$color"]); + Number_Ptr amount = Cast(env["$color"]); if (amount) { return SASS_MEMORY_NEW(String_Quoted, pstate, "opacity(" + amount->to_string(ctx.c_options) + ")"); } @@ -673,13 +680,13 @@ namespace Sass { BUILT_IN(adjust_color) { Color_Ptr color = ARG("$color", Color); - Number_Ptr r = SASS_MEMORY_CAST(Number, env["$red"]); - Number_Ptr g = SASS_MEMORY_CAST(Number, env["$green"]); - Number_Ptr b = SASS_MEMORY_CAST(Number, env["$blue"]); - Number_Ptr h = SASS_MEMORY_CAST(Number, env["$hue"]); - Number_Ptr s = SASS_MEMORY_CAST(Number, env["$saturation"]); - Number_Ptr l = SASS_MEMORY_CAST(Number, env["$lightness"]); - Number_Ptr a = SASS_MEMORY_CAST(Number, env["$alpha"]); + Number_Ptr r = Cast(env["$red"]); + Number_Ptr g = Cast(env["$green"]); + Number_Ptr b = Cast(env["$blue"]); + Number_Ptr h = Cast(env["$hue"]); + Number_Ptr s = Cast(env["$saturation"]); + Number_Ptr l = Cast(env["$lightness"]); + Number_Ptr a = Cast(env["$alpha"]); bool rgb = r || g || b; bool hsl = h || s || l; @@ -728,13 +735,13 @@ namespace Sass { BUILT_IN(scale_color) { Color_Ptr color = ARG("$color", Color); - Number_Ptr r = SASS_MEMORY_CAST(Number, env["$red"]); - Number_Ptr g = SASS_MEMORY_CAST(Number, env["$green"]); - Number_Ptr b = SASS_MEMORY_CAST(Number, env["$blue"]); - Number_Ptr h = SASS_MEMORY_CAST(Number, env["$hue"]); - Number_Ptr s = SASS_MEMORY_CAST(Number, env["$saturation"]); - Number_Ptr l = SASS_MEMORY_CAST(Number, env["$lightness"]); - Number_Ptr a = SASS_MEMORY_CAST(Number, env["$alpha"]); + Number_Ptr r = Cast(env["$red"]); + Number_Ptr g = Cast(env["$green"]); + Number_Ptr b = Cast(env["$blue"]); + Number_Ptr h = Cast(env["$hue"]); + Number_Ptr s = Cast(env["$saturation"]); + Number_Ptr l = Cast(env["$lightness"]); + Number_Ptr a = Cast(env["$alpha"]); bool rgb = r || g || b; bool hsl = h || s || l; @@ -784,13 +791,13 @@ namespace Sass { BUILT_IN(change_color) { Color_Ptr color = ARG("$color", Color); - Number_Ptr r = SASS_MEMORY_CAST(Number, env["$red"]); - Number_Ptr g = SASS_MEMORY_CAST(Number, env["$green"]); - Number_Ptr b = SASS_MEMORY_CAST(Number, env["$blue"]); - Number_Ptr h = SASS_MEMORY_CAST(Number, env["$hue"]); - Number_Ptr s = SASS_MEMORY_CAST(Number, env["$saturation"]); - Number_Ptr l = SASS_MEMORY_CAST(Number, env["$lightness"]); - Number_Ptr a = SASS_MEMORY_CAST(Number, env["$alpha"]); + Number_Ptr r = Cast(env["$red"]); + Number_Ptr g = Cast(env["$green"]); + Number_Ptr b = Cast(env["$blue"]); + Number_Ptr h = Cast(env["$hue"]); + Number_Ptr s = Cast(env["$saturation"]); + Number_Ptr l = Cast(env["$lightness"]); + Number_Ptr a = Cast(env["$alpha"]); bool rgb = r || g || b; bool hsl = h || s || l; @@ -866,25 +873,26 @@ namespace Sass { BUILT_IN(sass_unquote) { AST_Node_Obj arg = env["$string"]; - if (String_Quoted_Ptr string_quoted = SASS_MEMORY_CAST(String_Quoted, arg)) { + if (String_Quoted_Ptr string_quoted = Cast(arg)) { String_Constant_Ptr result = SASS_MEMORY_NEW(String_Constant, pstate, string_quoted->value()); // remember if the string was quoted (color tokens) result->is_delayed(true); // delay colors return result; } - else if (SASS_MEMORY_CAST(String_Constant, arg)) { - return (Expression_Ptr) &arg; + else if (String_Constant_Ptr str = Cast(arg)) { + return str; } - else { + else if (Expression_Ptr ex = Cast(arg)) { Sass_Output_Style oldstyle = ctx.c_options.output_style; ctx.c_options.output_style = SASS_STYLE_NESTED; std::string val(arg->to_string(ctx.c_options)); - val = SASS_MEMORY_CAST(Null, arg) ? "null" : val; + val = Cast(arg) ? "null" : val; ctx.c_options.output_style = oldstyle; deprecated_function("Passing " + val + ", a non-string value, to unquote()", pstate); - return (Expression_Ptr) &arg; + return ex; } + throw std::runtime_error("Invalid Data Type for unquote"); } Signature quote_sig = "quote($string)"; @@ -892,7 +900,7 @@ namespace Sass { { AST_Node_Obj arg = env["$string"]; // only set quote mark to true if already a string - if (String_Quoted_Ptr qstr = SASS_MEMORY_CAST(String_Quoted, arg)) { + if (String_Quoted_Ptr qstr = Cast(arg)) { qstr->quote_mark('*'); return qstr; } @@ -956,7 +964,7 @@ namespace Sass { str = ins + str; } - if (String_Quoted_Ptr ss = SASS_MEMORY_CAST_PTR(String_Quoted, s)) { + if (String_Quoted_Ptr ss = Cast(s)) { if (ss->quote_mark()) str = quote(str); } } @@ -999,13 +1007,13 @@ namespace Sass { String_Constant_Ptr s = ARG("$string", String_Constant); double start_at = ARG("$start-at", Number)->value(); double end_at = ARG("$end-at", Number)->value(); - String_Quoted_Ptr ss = SASS_MEMORY_CAST_PTR(String_Quoted, s); + String_Quoted_Ptr ss = Cast(s); std::string str = unquote(s->value()); size_t size = utf8::distance(str.begin(), str.end()); - if (!SASS_MEMORY_CAST(Number, env["$end-at"])) { + if (!Cast(env["$end-at"])) { end_at = -1; } @@ -1055,7 +1063,7 @@ namespace Sass { } } - if (String_Quoted_Ptr ss = SASS_MEMORY_CAST_PTR(String_Quoted, s)) { + if (String_Quoted_Ptr ss = Cast(s)) { String_Quoted_Ptr cpy = SASS_MEMORY_COPY(ss); cpy->value(str); return cpy; @@ -1076,7 +1084,7 @@ namespace Sass { } } - if (String_Quoted_Ptr ss = SASS_MEMORY_CAST_PTR(String_Quoted, s)) { + if (String_Quoted_Ptr ss = Cast(s)) { String_Quoted_Ptr cpy = SASS_MEMORY_COPY(ss); cpy->value(str); return cpy; @@ -1144,7 +1152,7 @@ namespace Sass { Number_Obj least = NULL; for (size_t i = 0, L = arglist->length(); i < L; ++i) { Expression_Obj val = arglist->value_at_index(i); - Number_Obj xi = SASS_MEMORY_CAST(Number, val); + Number_Obj xi = Cast(val); if (!xi) { error("\"" + val->to_string(ctx.c_options) + "\" is not a number for `min'", pstate); } @@ -1162,7 +1170,7 @@ namespace Sass { Number_Obj greatest = NULL; for (size_t i = 0, L = arglist->length(); i < L; ++i) { Expression_Obj val = arglist->value_at_index(i); - Number_Obj xi = SASS_MEMORY_CAST(Number, val); + Number_Obj xi = Cast(val); if (!xi) { error("\"" + val->to_string(ctx.c_options) + "\" is not a number for `max'", pstate); } @@ -1177,9 +1185,9 @@ namespace Sass { BUILT_IN(random) { AST_Node_Obj arg = env["$limit"]; - Value_Ptr v = SASS_MEMORY_CAST(Value, arg); - Number_Ptr l = SASS_MEMORY_CAST(Number, arg); - Boolean_Ptr b = SASS_MEMORY_CAST(Boolean, arg); + Value_Ptr v = Cast(arg); + Number_Ptr l = Cast(arg); + Boolean_Ptr b = Cast(arg); if (l) { double v = l->value(); if (v < 1) { @@ -1216,25 +1224,25 @@ namespace Sass { Signature length_sig = "length($list)"; BUILT_IN(length) { - if (Selector_List_Ptr sl = SASS_MEMORY_CAST(Selector_List, env["$list"])) { + if (Selector_List_Ptr sl = Cast(env["$list"])) { return SASS_MEMORY_NEW(Number, pstate, (double)sl->length()); } Expression_Ptr v = ARG("$list", Expression); if (v->concrete_type() == Expression::MAP) { - Map_Ptr map = SASS_MEMORY_CAST(Map, env["$list"]); + Map_Ptr map = Cast(env["$list"]); return SASS_MEMORY_NEW(Number, pstate, (double)(map ? map->length() : 1)); } if (v->concrete_type() == Expression::SELECTOR) { - if (Compound_Selector_Ptr h = dynamic_cast(v)) { + if (Compound_Selector_Ptr h = Cast(v)) { return SASS_MEMORY_NEW(Number, pstate, (double)h->length()); - } else if (Selector_List_Ptr ls = SASS_MEMORY_CAST_PTR(Selector_List, v)) { + } else if (Selector_List_Ptr ls = Cast(v)) { return SASS_MEMORY_NEW(Number, pstate, (double)ls->length()); } else { return SASS_MEMORY_NEW(Number, pstate, 1); } } - List_Ptr list = SASS_MEMORY_CAST(List, env["$list"]); + List_Ptr list = Cast(env["$list"]); return SASS_MEMORY_NEW(Number, pstate, (double)(list ? list->size() : 1)); @@ -1244,8 +1252,8 @@ namespace Sass { BUILT_IN(nth) { Number_Ptr n = ARG("$n", Number); - Map_Ptr m = SASS_MEMORY_CAST(Map, env["$list"]); - if (Selector_List_Ptr sl = SASS_MEMORY_CAST(Selector_List, env["$list"])) { + Map_Ptr m = Cast(env["$list"]); + if (Selector_List_Ptr sl = Cast(env["$list"])) { size_t len = m ? m->length() : sl->length(); bool empty = m ? m->empty() : sl->empty(); if (empty) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate); @@ -1255,7 +1263,7 @@ namespace Sass { Listize listize; return (*sl)[static_cast(index)]->perform(&listize); } - List_Obj l = SASS_MEMORY_CAST(List, env["$list"]); + List_Obj l = Cast(env["$list"]); if (n->value() == 0) error("argument `$n` of `" + std::string(sig) + "` must be non-zero", pstate); // if the argument isn't a list, then wrap it in a singleton list if (!m && !l) { @@ -1284,8 +1292,8 @@ namespace Sass { Signature set_nth_sig = "set-nth($list, $n, $value)"; BUILT_IN(set_nth) { - Map_Obj m = SASS_MEMORY_CAST(Map, env["$list"]); - List_Obj l = SASS_MEMORY_CAST(List, env["$list"]); + Map_Obj m = Cast(env["$list"]); + List_Obj l = Cast(env["$list"]); Number_Obj n = ARG("$n", Number); Expression_Obj v = ARG("$value", Expression); if (!l) { @@ -1298,7 +1306,7 @@ namespace Sass { if (l->empty()) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate); double index = std::floor(n->value() < 0 ? l->length() + n->value() : n->value() - 1); if (index < 0 || index > l->length() - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate); - List_Ptr result = SASS_MEMORY_NEW(List, pstate, l->length(), l->separator()); + List_Ptr result = SASS_MEMORY_NEW(List, pstate, l->length(), l->separator(), false, l->is_bracketed()); for (size_t i = 0, L = l->length(); i < L; ++i) { result->append(((i == index) ? v : (*l)[i])); } @@ -1308,8 +1316,8 @@ namespace Sass { Signature index_sig = "index($list, $value)"; BUILT_IN(index) { - Map_Obj m = SASS_MEMORY_CAST(Map, env["$list"]); - List_Obj l = SASS_MEMORY_CAST(List, env["$list"]); + Map_Obj m = Cast(env["$list"]); + List_Obj l = Cast(env["$list"]); Expression_Obj v = ARG("$value", Expression); if (!l) { l = SASS_MEMORY_NEW(List, pstate, 1); @@ -1324,19 +1332,22 @@ namespace Sass { return SASS_MEMORY_NEW(Null, pstate); } - Signature join_sig = "join($list1, $list2, $separator: auto)"; + Signature join_sig = "join($list1, $list2, $separator: auto, $bracketed: auto)"; BUILT_IN(join) { - Map_Obj m1 = SASS_MEMORY_CAST(Map, env["$list1"]); - Map_Obj m2 = SASS_MEMORY_CAST(Map, env["$list2"]); - List_Obj l1 = SASS_MEMORY_CAST(List, env["$list1"]); - List_Obj l2 = SASS_MEMORY_CAST(List, env["$list2"]); + Map_Obj m1 = Cast(env["$list1"]); + Map_Obj m2 = Cast(env["$list2"]); + List_Obj l1 = Cast(env["$list1"]); + List_Obj l2 = Cast(env["$list2"]); String_Constant_Obj sep = ARG("$separator", String_Constant); enum Sass_Separator sep_val = (l1 ? l1->separator() : SASS_SPACE); + Value* bracketed = ARG("$bracketed", Value); + bool is_bracketed = (l1 ? l1->is_bracketed() : false); if (!l1) { l1 = SASS_MEMORY_NEW(List, pstate, 1); l1->append(ARG("$list1", Expression)); sep_val = (l2 ? l2->separator() : SASS_SPACE); + is_bracketed = (l2 ? l2->is_bracketed() : false); } if (!l2) { l2 = SASS_MEMORY_NEW(List, pstate, 1); @@ -1354,21 +1365,26 @@ namespace Sass { if (sep_str == "space") sep_val = SASS_SPACE; else if (sep_str == "comma") sep_val = SASS_COMMA; else if (sep_str != "auto") error("argument `$separator` of `" + std::string(sig) + "` must be `space`, `comma`, or `auto`", pstate); - List_Obj result = SASS_MEMORY_NEW(List, pstate, len, sep_val); - result->concat(&l1); - result->concat(&l2); + String_Constant_Obj bracketed_as_str = Cast(bracketed); + bool bracketed_is_auto = bracketed_as_str && unquote(bracketed_as_str->value()) == "auto"; + if (!bracketed_is_auto) { + is_bracketed = !bracketed->is_false(); + } + List_Obj result = SASS_MEMORY_NEW(List, pstate, len, sep_val, false, is_bracketed); + result->concat(l1); + result->concat(l2); return result.detach(); } Signature append_sig = "append($list, $val, $separator: auto)"; BUILT_IN(append) { - Map_Obj m = SASS_MEMORY_CAST(Map, env["$list"]); - List_Obj l = SASS_MEMORY_CAST(List, env["$list"]); + Map_Obj m = Cast(env["$list"]); + List_Obj l = Cast(env["$list"]); Expression_Obj v = ARG("$val", Expression); - if (Selector_List_Ptr sl = SASS_MEMORY_CAST(Selector_List, env["$list"])) { + if (Selector_List_Ptr sl = Cast(env["$list"])) { Listize listize; - l = SASS_MEMORY_CAST_PTR(List, sl->perform(&listize)); + l = Cast(sl->perform(&listize)); } String_Constant_Obj sep = ARG("$separator", String_Constant); if (!l) { @@ -1405,8 +1421,8 @@ namespace Sass { List_Obj arglist = SASS_MEMORY_COPY(ARG("$lists", List)); size_t shortest = 0; for (size_t i = 0, L = arglist->length(); i < L; ++i) { - List_Obj ith = SASS_MEMORY_CAST(List, arglist->value_at_index(i)); - Map_Obj mith = SASS_MEMORY_CAST(Map, arglist->value_at_index(i)); + List_Obj ith = Cast(arglist->value_at_index(i)); + Map_Obj mith = Cast(arglist->value_at_index(i)); if (!ith) { if (mith) { ith = mith->to_list(ctx, pstate); @@ -1415,10 +1431,10 @@ namespace Sass { ith->append(arglist->value_at_index(i)); } if (arglist->is_arglist()) { - Argument_Obj arg = (Argument_Ptr)(&arglist->at(i)); - arg->value(&ith); + Argument_Obj arg = (Argument_Ptr)(arglist->at(i).ptr()); // XXX + arg->value(ith); } else { - (*arglist)[i] = &ith; + (*arglist)[i] = ith; } } shortest = (i ? std::min(shortest, ith->length()) : ith->length()); @@ -1428,7 +1444,7 @@ namespace Sass { for (size_t i = 0; i < shortest; ++i) { List_Ptr zipper = SASS_MEMORY_NEW(List, pstate, L); for (size_t j = 0; j < L; ++j) { - zipper->append(SASS_MEMORY_CAST(List, arglist->value_at_index(j))->at(i)); + zipper->append(Cast(arglist->value_at_index(j))->at(i)); } zippers->append(zipper); } @@ -1438,7 +1454,7 @@ namespace Sass { Signature list_separator_sig = "list_separator($list)"; BUILT_IN(list_separator) { - List_Obj l = SASS_MEMORY_CAST(List, env["$list"]); + List_Obj l = Cast(env["$list"]); if (!l) { l = SASS_MEMORY_NEW(List, pstate, 1); l->append(ARG("$list", Expression)); @@ -1460,7 +1476,7 @@ namespace Sass { Map_Obj m = ARGM("$map", Map, ctx); Expression_Obj v = ARG("$key", Expression); try { - Expression_Obj val = m->at(v); // XXX + Expression_Obj val = m->at(v); return val ? val.detach() : SASS_MEMORY_NEW(Null, pstate); } catch (const std::out_of_range&) { return SASS_MEMORY_NEW(Null, pstate); @@ -1507,8 +1523,8 @@ namespace Sass { size_t len = m1->length() + m2->length(); Map_Ptr result = SASS_MEMORY_NEW(Map, pstate, len); // concat not implemented for maps - *result += &m1; - *result += &m2; + *result += m1; + *result += m2; return result; } @@ -1536,7 +1552,7 @@ namespace Sass { Map_Obj result = SASS_MEMORY_NEW(Map, pstate, 1); for (size_t i = arglist->size(), L = arglist->length(); i < L; ++i) { Expression_Obj obj = arglist->at(i); - Argument_Obj arg = (Argument_Ptr)&obj; + Argument_Obj arg = (Argument_Ptr) obj.ptr(); // XXX std::string name = std::string(arg->name()); name = name.erase(0, 1); // sanitize name (remove dollar sign) *result << std::make_pair(SASS_MEMORY_NEW(String_Quoted, @@ -1651,19 +1667,19 @@ namespace Sass { Arguments_Obj args = SASS_MEMORY_NEW(Arguments, pstate); // std::string full_name(name + "[f]"); - // Definition_Ptr def = d_env.has(full_name) ? static_cast((d_env)[full_name]) : 0; + // Definition_Ptr def = d_env.has(full_name) ? Cast((d_env)[full_name]) : 0; // Parameters_Ptr params = def ? def->parameters() : 0; // size_t param_size = params ? params->length() : 0; for (size_t i = 0, L = arglist->length(); i < L; ++i) { Expression_Obj expr = arglist->value_at_index(i); // if (params && params->has_rest_parameter()) { // Parameter_Obj p = param_size > i ? (*params)[i] : 0; - // List_Ptr list = SASS_MEMORY_CAST(List, expr); + // List_Ptr list = Cast(expr); // if (list && p && !p->is_rest_parameter()) expr = (*list)[0]; // } if (arglist->is_arglist()) { Expression_Obj obj = arglist->at(i); - Argument_Obj arg = (Argument_Ptr)&obj; + Argument_Obj arg = (Argument_Ptr) obj.ptr(); // XXX args->append(SASS_MEMORY_NEW(Argument, pstate, expr, @@ -1674,7 +1690,7 @@ namespace Sass { args->append(SASS_MEMORY_NEW(Argument, pstate, expr)); } } - Function_Call_Obj func = SASS_MEMORY_NEW(Function_Call, pstate, name, &args); + Function_Call_Obj func = SASS_MEMORY_NEW(Function_Call, pstate, name, args); Expand expand(ctx, &d_env, backtrace, &selector_stack); func->via_call(true); // calc invoke is allowed return func->perform(&expand.eval); @@ -1705,17 +1721,6 @@ namespace Sass { return res; } - //////////////// - // URL FUNCTIONS - //////////////// - - Signature image_url_sig = "image-url($path, $only-path: false, $cache-buster: false)"; - BUILT_IN(image_url) - { - error("`image_url` has been removed from libsass because it's not part of the Sass spec", pstate); - return 0; // suppress warning, error will exit anyway - } - ////////////////////////// // MISCELLANEOUS FUNCTIONS ////////////////////////// @@ -1759,19 +1764,19 @@ namespace Sass { // Parse args into vector of selectors std::vector parsedSelectors; for (size_t i = 0, L = arglist->length(); i < L; ++i) { - Expression_Obj exp = SASS_MEMORY_CAST(Expression, arglist->value_at_index(i)); + Expression_Obj exp = Cast(arglist->value_at_index(i)); if (exp->concrete_type() == Expression::NULL_VAL) { std::stringstream msg; msg << "$selectors: null is not a valid selector: it must be a string,\n"; msg << "a list of strings, or a list of lists of strings for 'selector-nest'"; error(msg.str(), pstate); } - if (String_Constant_Obj str = SASS_MEMORY_CAST(String_Constant, exp)) { + if (String_Constant_Obj str = Cast(exp)) { str->quote_mark(0); } - std::string exp_src = exp->to_string(ctx.c_options) + "{"; + std::string exp_src = exp->to_string(ctx.c_options); Selector_List_Obj sel = Parser::parse_selector(exp_src.c_str(), ctx); - parsedSelectors.push_back(&sel); + parsedSelectors.push_back(sel); } // Nothing to do @@ -1787,7 +1792,7 @@ namespace Sass { for(;itr != parsedSelectors.end(); ++itr) { Selector_List_Obj child = *itr; std::vector exploded; - selector_stack.push_back(&result); + selector_stack.push_back(result); Selector_List_Obj rv = child->resolve_parent_refs(ctx, selector_stack); selector_stack.pop_back(); for (size_t m = 0, mLen = rv->length(); m < mLen; ++m) { @@ -1812,19 +1817,19 @@ namespace Sass { // Parse args into vector of selectors std::vector parsedSelectors; for (size_t i = 0, L = arglist->length(); i < L; ++i) { - Expression_Obj exp = SASS_MEMORY_CAST(Expression, arglist->value_at_index(i)); + Expression_Obj exp = Cast(arglist->value_at_index(i)); if (exp->concrete_type() == Expression::NULL_VAL) { std::stringstream msg; msg << "$selectors: null is not a valid selector: it must be a string,\n"; msg << "a list of strings, or a list of lists of strings for 'selector-append'"; error(msg.str(), pstate); } - if (String_Constant_Ptr str = SASS_MEMORY_CAST(String_Constant, exp)) { + if (String_Constant_Ptr str = Cast(exp)) { str->quote_mark(0); } - std::string exp_src = exp->to_string() + "{"; + std::string exp_src = exp->to_string(); Selector_List_Obj sel = Parser::parse_selector(exp_src.c_str(), ctx); - parsedSelectors.push_back(&sel); + parsedSelectors.push_back(sel); } // Nothing to do @@ -1865,7 +1870,7 @@ namespace Sass { } // Cannot be a Universal selector - Element_Selector_Obj pType = SASS_MEMORY_CAST(Element_Selector, childSeq->head()->first()); + Element_Selector_Obj pType = Cast(childSeq->head()->first()); if(pType && pType->name() == "*") { std::string msg("Can't append \""); msg += childSeq->to_string(); @@ -1878,12 +1883,12 @@ namespace Sass { // TODO: Add check for namespace stuff // append any selectors in childSeq's head - parentSeqClone->innermost()->head()->concat(&base->head()); + parentSeqClone->innermost()->head()->concat(base->head()); // Set parentSeqClone new tail parentSeqClone->innermost()->tail( base->tail() ); - newElements.push_back(&parentSeqClone); + newElements.push_back(parentSeqClone); } } @@ -1900,7 +1905,7 @@ namespace Sass { Selector_List_Obj selector1 = ARGSEL("$selector1", Selector_List_Obj, p_contextualize); Selector_List_Obj selector2 = ARGSEL("$selector2", Selector_List_Obj, p_contextualize); - Selector_List_Obj result = selector1->unify_with(&selector2, ctx); + Selector_List_Obj result = selector1->unify_with(selector2, ctx); Listize listize; return result->perform(&listize); } @@ -1981,5 +1986,12 @@ namespace Sass { return SASS_MEMORY_NEW(String_Quoted, pstate, ss.str()); } + Signature is_bracketed_sig = "is-bracketed($list)"; + BUILT_IN(is_bracketed) + { + Value_Obj value = ARG("$list", Value); + List_Obj list = Cast(value); + return SASS_MEMORY_NEW(Boolean, pstate, list && list->is_bracketed()); + } } } diff --git a/src/libsass/src/functions.hpp b/src/libsass/src/functions.hpp index ef4f60ef4..f2cc0af50 100755 --- a/src/libsass/src/functions.hpp +++ b/src/libsass/src/functions.hpp @@ -12,7 +12,6 @@ name(Env& env, Env& d_env, Context& ctx, Signature sig, ParserState pstate, Back namespace Sass { struct Backtrace; - typedef Environment Env; typedef const char* Signature; typedef Expression_Ptr (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtrace*, std::vector); @@ -89,7 +88,6 @@ namespace Sass { extern Signature call_sig; extern Signature not_sig; extern Signature if_sig; - extern Signature image_url_sig; extern Signature map_get_sig; extern Signature map_merge_sig; extern Signature map_remove_sig; @@ -107,6 +105,7 @@ namespace Sass { extern Signature is_superselector_sig; extern Signature simple_selectors_sig; extern Signature selector_parse_sig; + extern Signature is_bracketed_sig; BUILT_IN(rgb); BUILT_IN(rgba_4); @@ -171,7 +170,6 @@ namespace Sass { BUILT_IN(call); BUILT_IN(sass_not); BUILT_IN(sass_if); - BUILT_IN(image_url); BUILT_IN(map_get); BUILT_IN(map_merge); BUILT_IN(map_remove); @@ -189,6 +187,7 @@ namespace Sass { BUILT_IN(is_superselector); BUILT_IN(simple_selectors); BUILT_IN(selector_parse); + BUILT_IN(is_bracketed); } } diff --git a/src/libsass/src/inspect.cpp b/src/libsass/src/inspect.cpp index 3b68900d5..4ace72484 100755 --- a/src/libsass/src/inspect.cpp +++ b/src/libsass/src/inspect.cpp @@ -166,7 +166,7 @@ namespace Sass { import->urls().front()->perform(this); if (import->urls().size() == 1) { - if (&import->import_queries()) { + if (import->import_queries()) { append_mandatory_space(); import->import_queries()->perform(this); } @@ -179,7 +179,7 @@ namespace Sass { import->urls()[i]->perform(this); if (import->urls().size() - 1 == i) { - if (&import->import_queries()) { + if (import->import_queries()) { append_mandatory_space(); import->import_queries()->perform(this); } @@ -360,10 +360,19 @@ namespace Sass { append_string(")"); } + std::string Inspect::lbracket(List_Ptr list) { + return list->is_bracketed() ? "[" : "("; + } + + std::string Inspect::rbracket(List_Ptr list) { + return list->is_bracketed() ? "]" : ")"; + } + void Inspect::operator()(List_Ptr list) { - if (output_style() == TO_SASS && list->empty()) { - append_string("()"); + if (list->empty() && (output_style() == TO_SASS || list->is_bracketed())) { + append_string(lbracket(list)); + append_string(rbracket(list)); return; } std::string sep(list->separator() == SASS_SPACE ? " " : ","); @@ -374,19 +383,24 @@ namespace Sass { bool was_space_array = in_space_array; bool was_comma_array = in_comma_array; + // if the list is bracketed, always include the left bracket + if (list->is_bracketed()) { + append_string(lbracket(list)); + } // probably ruby sass eqivalent of element_needs_parens - if (output_style() == TO_SASS && + else if (output_style() == TO_SASS && list->length() == 1 && !list->from_selector() && - !SASS_MEMORY_CAST(List, list->at(0)) && - !SASS_MEMORY_CAST(Selector_List, list->at(0))) { - append_string("("); + !Cast(list->at(0)) && + !Cast(list->at(0)) + ) { + append_string(lbracket(list)); } else if (!in_declaration && (list->separator() == SASS_HASH || (list->separator() == SASS_SPACE && in_space_array) || (list->separator() == SASS_COMMA && in_comma_array) )) { - append_string("("); + append_string(lbracket(list)); } if (list->separator() == SASS_SPACE) in_space_array = true; @@ -399,7 +413,7 @@ namespace Sass { if (output_style() != TO_SASS) { if (list_item->is_invisible()) { // this fixes an issue with "" in a list - if (!SASS_MEMORY_CAST(String_Constant, list_item)) { + if (!Cast(list_item)) { continue; } } @@ -415,19 +429,29 @@ namespace Sass { in_comma_array = was_comma_array; in_space_array = was_space_array; + + // if the list is bracketed, always include the right bracket + if (list->is_bracketed()) { + if (list->separator() == SASS_COMMA && list->size() == 1) { + append_string(","); + } + append_string(rbracket(list)); + } // probably ruby sass eqivalent of element_needs_parens - if (output_style() == TO_SASS && + else if (output_style() == TO_SASS && list->length() == 1 && !list->from_selector() && - !SASS_MEMORY_CAST(List, list->at(0)) && - !SASS_MEMORY_CAST(Selector_List, list->at(0))) { - append_string(",)"); + !Cast(list->at(0)) && + !Cast(list->at(0)) + ) { + append_string(","); + append_string(rbracket(list)); } else if (!in_declaration && (list->separator() == SASS_HASH || (list->separator() == SASS_SPACE && in_space_array) || (list->separator() == SASS_COMMA && in_comma_array) )) { - append_string(")"); + append_string(rbracket(list)); } } @@ -443,7 +467,7 @@ namespace Sass { expr->is_right_interpolant()) )) append_string(" "); - switch (expr->type()) { + switch (expr->optype()) { case Sass_OP::AND: append_string("&&"); break; case Sass_OP::OR: append_string("||"); break; case Sass_OP::EQ: append_string("=="); break; @@ -471,8 +495,8 @@ namespace Sass { void Inspect::operator()(Unary_Expression_Ptr expr) { - if (expr->type() == Unary_Expression::PLUS) append_string("+"); - else append_string("-"); + if (expr->optype() == Unary_Expression::PLUS) append_string("+"); + else append_string("-"); expr->operand()->perform(this); } @@ -744,9 +768,9 @@ namespace Sass { { append_token("not", sn); append_mandatory_space(); - if (sn->needs_parens(&sn->condition())) append_string("("); + if (sn->needs_parens(sn->condition())) append_string("("); sn->condition()->perform(this); - if (sn->needs_parens(&sn->condition())) append_string(")"); + if (sn->needs_parens(sn->condition())) append_string(")"); } void Inspect::operator()(Supports_Declaration_Ptr sd) @@ -766,7 +790,7 @@ namespace Sass { void Inspect::operator()(Media_Query_Ptr mq) { size_t i = 0; - if (&mq->media_type()) { + if (mq->media_type()) { if (mq->is_negated()) append_string("not "); else if (mq->is_restricted()) append_string("only "); mq->media_type()->perform(this); @@ -851,7 +875,7 @@ namespace Sass { return; } if (a->value()->concrete_type() == Expression::STRING) { - String_Constant_Ptr s = SASS_MEMORY_CAST(String_Constant, a->value()); + String_Constant_Ptr s = Cast(a->value()); if (s) s->perform(this); } else { a->value()->perform(this); @@ -919,7 +943,7 @@ namespace Sass { append_token(s->ns_name(), s); if (!s->matcher().empty()) { append_string(s->matcher()); - if (&s->value() && *s->value()) { + if (s->value() && *s->value()) { s->value()->perform(this); } } @@ -1040,8 +1064,8 @@ namespace Sass { bool was_comma_array = in_comma_array; // probably ruby sass eqivalent of element_needs_parens if (output_style() == TO_SASS && g->length() == 1 && - (!SASS_MEMORY_CAST(List, (*g)[0]) && - !SASS_MEMORY_CAST(Selector_List, (*g)[0]))) { + (!Cast((*g)[0]) && + !Cast((*g)[0]))) { append_string("("); } else if (!in_declaration && in_comma_array) { @@ -1053,7 +1077,7 @@ namespace Sass { for (size_t i = 0, L = g->length(); i < L; ++i) { if (!in_wrapped && i == 0) append_indentation(); if ((*g)[i] == 0) continue; - schedule_mapping(&g->at(i)->last()); + schedule_mapping(g->at(i)->last()); // add_open_mapping((*g)[i]->last()); (*g)[i]->perform(this); // add_close_mapping((*g)[i]->last()); @@ -1066,8 +1090,8 @@ namespace Sass { in_comma_array = was_comma_array; // probably ruby sass eqivalent of element_needs_parens if (output_style() == TO_SASS && g->length() == 1 && - (!SASS_MEMORY_CAST(List, (*g)[0]) && - !SASS_MEMORY_CAST(Selector_List, (*g)[0]))) { + (!Cast((*g)[0]) && + !Cast((*g)[0]))) { append_string(",)"); } else if (!in_declaration && in_comma_array) { diff --git a/src/libsass/src/inspect.hpp b/src/libsass/src/inspect.hpp index a5fc20570..59805a156 100755 --- a/src/libsass/src/inspect.hpp +++ b/src/libsass/src/inspect.hpp @@ -92,6 +92,9 @@ namespace Sass { virtual void operator()(Complex_Selector_Ptr); virtual void operator()(Selector_List_Ptr); + virtual std::string lbracket(List_Ptr); + virtual std::string rbracket(List_Ptr); + // template // void fallback(U x) { fallback_impl(reinterpret_cast(x)); } }; diff --git a/src/libsass/src/lexer.cpp b/src/libsass/src/lexer.cpp index 464ca444a..781257e2e 100755 --- a/src/libsass/src/lexer.cpp +++ b/src/libsass/src/lexer.cpp @@ -1,6 +1,5 @@ #include "sass.hpp" #include -#include #include #include #include "lexer.hpp" diff --git a/src/libsass/src/listize.cpp b/src/libsass/src/listize.cpp index 7edb2359f..88329ba1b 100755 --- a/src/libsass/src/listize.cpp +++ b/src/libsass/src/listize.cpp @@ -70,7 +70,7 @@ namespace Sass { if (tail) { Expression_Obj tt = tail->perform(this); - if (List_Ptr ls = SASS_MEMORY_CAST(List, tt)) + if (List_Ptr ls = Cast(tt)) { l->concat(ls); } } if (l->length() == 0) return 0; @@ -79,7 +79,7 @@ namespace Sass { Expression_Ptr Listize::fallback_impl(AST_Node_Ptr n) { - return dynamic_cast(n); + return Cast(n); } } diff --git a/src/libsass/src/listize.hpp b/src/libsass/src/listize.hpp index 208f43826..9716ebefc 100755 --- a/src/libsass/src/listize.hpp +++ b/src/libsass/src/listize.hpp @@ -11,7 +11,6 @@ namespace Sass { - typedef Environment Env; struct Backtrace; class Listize : public Operation_CRTP { diff --git a/src/libsass/src/memory/SharedPtr.cpp b/src/libsass/src/memory/SharedPtr.cpp index 53f368131..e6d44dab1 100755 --- a/src/libsass/src/memory/SharedPtr.cpp +++ b/src/libsass/src/memory/SharedPtr.cpp @@ -18,7 +18,7 @@ namespace Sass { std::cerr << "# REPORTING MISSING DEALLOCATIONS #\n"; std::cerr << "###################################\n"; for (auto var : all) { - if (AST_Node_Ptr ast = SASS_MEMORY_CAST_PTR(AST_Node, var)) { + if (AST_Node_Ptr ast = Cast(var)) { debug_ast(ast); } else { std::cerr << "LEAKED " << var << "\n"; @@ -62,7 +62,7 @@ namespace Sass { #endif if (node->refcounter == 0) { #ifdef DEBUG_SHARED_PTR - AST_Node_Ptr ptr = SASS_MEMORY_CAST_PTR(AST_Node, node); + AST_Node_Ptr ptr = Cast(node); if (node->dbg) std::cerr << "DELETE NODE " << node << "\n"; #endif if (!node->detached) { diff --git a/src/libsass/src/memory/SharedPtr.hpp b/src/libsass/src/memory/SharedPtr.hpp index 3a85fb1a9..2df55bc24 100755 --- a/src/libsass/src/memory/SharedPtr.hpp +++ b/src/libsass/src/memory/SharedPtr.hpp @@ -17,7 +17,7 @@ namespace Sass { #ifdef DEBUG_SHARED_PTR #define SASS_MEMORY_NEW(Class, ...) \ - static_cast((new Class(__VA_ARGS__))->trace(__FILE__, __LINE__)) \ + ((new Class(__VA_ARGS__))->trace(__FILE__, __LINE__)) \ #define SASS_MEMORY_COPY(obj) \ ((obj)->copy(__FILE__, __LINE__)) \ @@ -38,12 +38,6 @@ namespace Sass { #endif - #define SASS_MEMORY_CAST(Class, obj) \ - (dynamic_cast(&obj)) \ - - #define SASS_MEMORY_CAST_PTR(Class, ptr) \ - (dynamic_cast(ptr)) \ - class SharedObj { protected: friend class SharedPtr; @@ -114,13 +108,10 @@ namespace Sass { // destructor ~SharedPtr(); public: - SharedObj* obj () { - return node; - }; SharedObj* obj () const { return node; }; - SharedObj* operator-> () { + SharedObj* operator-> () const { return node; }; bool isNull () { @@ -129,68 +120,58 @@ namespace Sass { bool isNull () const { return node == NULL; }; - SharedObj* detach() { - node->detached = true; - return node; - }; SharedObj* detach() const { if (node) { node->detached = true; } return node; }; - operator bool() { - return node != NULL; - }; operator bool() const { return node != NULL; }; }; - template < typename T > + template < class T > class SharedImpl : private SharedPtr { public: SharedImpl() : SharedPtr(NULL) {}; SharedImpl(T* node) : SharedPtr(node) {}; + template < class U > + SharedImpl(SharedImpl obj) + : SharedPtr(static_cast(obj.ptr())) {} SharedImpl(T&& node) : SharedPtr(node) {}; SharedImpl(const T& node) : SharedPtr(node) {}; ~SharedImpl() {}; public: - T* operator& () { + operator T*() const { return static_cast(this->obj()); - }; - T* operator& () const { - return static_cast(this->obj()); - }; - T& operator* () { + } + operator T&() const { return *static_cast(this->obj()); - }; + } T& operator* () const { return *static_cast(this->obj()); }; - T* operator-> () { - return static_cast(this->obj()); - }; T* operator-> () const { return static_cast(this->obj()); }; - T* ptr () { + T* ptr () const { return static_cast(this->obj()); }; - T* detach() { + T* detach() const { if (this->obj() == NULL) return NULL; return static_cast(SharedPtr::detach()); } - bool isNull() { + bool isNull() const { return this->obj() == NULL; } - operator bool() { - return this->obj() != NULL; + bool operator<(const T& rhs) const { + return *this->ptr() < rhs; }; operator bool() const { return this->obj() != NULL; diff --git a/src/libsass/src/node.cpp b/src/libsass/src/node.cpp index f408521a2..1cea923a8 100755 --- a/src/libsass/src/node.cpp +++ b/src/libsass/src/node.cpp @@ -66,12 +66,12 @@ namespace Sass { bool Node::contains(const Node& potentialChild, bool simpleSelectorOrderDependent) const { - bool found = false; + bool found = false; for (NodeDeque::iterator iter = mpCollection->begin(), iterEnd = mpCollection->end(); iter != iterEnd; iter++) { Node& toTest = *iter; - if (nodesEqual(toTest, potentialChild, simpleSelectorOrderDependent)) { + if (toTest == potentialChild) { found = true; break; } @@ -82,37 +82,32 @@ namespace Sass { bool Node::operator==(const Node& rhs) const { - return nodesEqual(*this, rhs, true /*simpleSelectorOrderDependent*/); - } - - - bool nodesEqual(const Node& lhs, const Node& rhs, bool simpleSelectorOrderDependent) { - if (lhs.type() != rhs.type()) { + if (this->type() != rhs.type()) { return false; } - if (lhs.isCombinator()) { + if (this->isCombinator()) { - return lhs.combinator() == rhs.combinator(); + return this->combinator() == rhs.combinator(); - } else if (lhs.isNil()) { + } else if (this->isNil()) { return true; // no state to check - } else if (lhs.isSelector()){ + } else if (this->isSelector()){ - return selectors_equal(*&lhs.selector(), *&rhs.selector(), simpleSelectorOrderDependent); + return *this->selector() == *rhs.selector(); - } else if (lhs.isCollection()) { + } else if (this->isCollection()) { - if (lhs.collection()->size() != rhs.collection()->size()) { + if (this->collection()->size() != rhs.collection()->size()) { return false; } - for (NodeDeque::iterator lhsIter = lhs.collection()->begin(), lhsIterEnd = lhs.collection()->end(), + for (NodeDeque::iterator lhsIter = this->collection()->begin(), lhsIterEnd = this->collection()->end(), rhsIter = rhs.collection()->begin(); lhsIter != lhsIterEnd; lhsIter++, rhsIter++) { - if (!nodesEqual(*lhsIter, *rhsIter, simpleSelectorOrderDependent)) { + if (*lhsIter != *rhsIter) { return false; } @@ -128,10 +123,10 @@ namespace Sass { void Node::plus(Node& rhs) { - if (!this->isCollection() || !rhs.isCollection()) { - throw "Both the current node and rhs must be collections."; + if (!this->isCollection() || !rhs.isCollection()) { + throw "Both the current node and rhs must be collections."; } - this->collection()->insert(this->collection()->end(), rhs.collection()->begin(), rhs.collection()->end()); + this->collection()->insert(this->collection()->end(), rhs.collection()->begin(), rhs.collection()->end()); } #ifdef DEBUG @@ -189,7 +184,7 @@ namespace Sass { if (pToConvert->head() && pToConvert->head()->has_parent_ref()) { Complex_Selector_Obj tail = pToConvert->tail(); if (tail) tail->has_line_feed(pToConvert->has_line_feed()); - pToConvert = &tail; + pToConvert = tail; } while (pToConvert) { @@ -216,7 +211,7 @@ namespace Sass { // pToConvert->tail()->has_line_feed(pToConvert->has_line_feed()); } - pToConvert = &pToConvert->tail(); + pToConvert = pToConvert->tail(); } return node; @@ -254,7 +249,7 @@ namespace Sass { // collections, and can result in an infinite loop during the call to parentSuperselector() pCurrent->tail(SASS_MEMORY_COPY(child.selector())); // if (child.got_line_feed) pCurrent->has_line_feed(child.got_line_feed); - pCurrent = &pCurrent->tail(); + pCurrent = pCurrent->tail(); } else if (child.isCombinator()) { pCurrent->combinator(child.combinator()); if (child.got_line_feed) pCurrent->has_line_feed(child.got_line_feed); @@ -265,7 +260,7 @@ namespace Sass { if (nextNode.isCombinator()) { pCurrent->tail(SASS_MEMORY_NEW(Complex_Selector, ParserState("[NODE]"), Complex_Selector::ANCESTOR_OF, NULL, NULL)); if (nextNode.got_line_feed) pCurrent->tail()->has_line_feed(nextNode.got_line_feed); - pCurrent = &pCurrent->tail(); + pCurrent = pCurrent->tail(); } } } else { diff --git a/src/libsass/src/node.hpp b/src/libsass/src/node.hpp index 21d10fb3a..969d5dfee 100755 --- a/src/libsass/src/node.hpp +++ b/src/libsass/src/node.hpp @@ -113,8 +113,6 @@ namespace Sass { Node complexSelectorToNode(Complex_Selector_Ptr pToConvert, Context& ctx); Complex_Selector_Ptr nodeToComplexSelector(const Node& toConvert, Context& ctx); - bool nodesEqual(const Node& one, const Node& two, bool simpleSelectorOrderDependent); - } #endif diff --git a/src/libsass/src/output.cpp b/src/libsass/src/output.cpp index 456020001..0ba43332e 100755 --- a/src/libsass/src/output.cpp +++ b/src/libsass/src/output.cpp @@ -116,8 +116,8 @@ namespace Sass { if (!Util::isPrintable(r, output_style())) { for (size_t i = 0, L = b->length(); i < L; ++i) { const Statement_Obj& stm = b->at(i); - if (dynamic_cast(&stm)) { - if (!dynamic_cast(&stm)) { + if (Cast(stm)) { + if (!Cast(stm)) { stm->perform(this); } } @@ -135,27 +135,27 @@ namespace Sass { append_optional_linefeed(); } if (s) s->perform(this); - append_scope_opener(&b); + append_scope_opener(b); for (size_t i = 0, L = b->length(); i < L; ++i) { Statement_Obj stm = b->at(i); bool bPrintExpression = true; // Check print conditions - if (Declaration_Ptr dec = SASS_MEMORY_CAST(Declaration, stm)) { - if (String_Constant_Ptr valConst = SASS_MEMORY_CAST(String_Constant, dec->value())) { + if (Declaration_Ptr dec = Cast(stm)) { + if (String_Constant_Ptr valConst = Cast(dec->value())) { std::string val(valConst->value()); - if (String_Quoted_Ptr qstr = SASS_MEMORY_CAST_PTR(String_Quoted, valConst)) { + if (String_Quoted_Ptr qstr = Cast(valConst)) { if (!qstr->quote_mark() && val.empty()) { bPrintExpression = false; } } } - else if (List_Ptr list = SASS_MEMORY_CAST(List, dec->value())) { + else if (List_Ptr list = Cast(dec->value())) { bool all_invisible = true; for (size_t list_i = 0, list_L = list->length(); list_i < list_L; ++list_i) { - Expression_Ptr item = &list->at(list_i); + Expression_Ptr item = list->at(list_i); if (!item->is_invisible()) all_invisible = false; } - if (all_invisible) bPrintExpression = false; + if (all_invisible && !list->is_bracketed()) bPrintExpression = false; } } // Print if OK @@ -164,7 +164,7 @@ namespace Sass { } } if (output_style() == NESTED) indentation -= r->tabs(); - append_scope_closer(&b); + append_scope_closer(b); } void Output::operator()(Keyframe_Rule_Ptr r) @@ -172,7 +172,7 @@ namespace Sass { Block_Obj b = r->block(); Selector_Obj v = r->name(); - if (&v) { + if (!v.isNull()) { v->perform(this); } @@ -201,7 +201,7 @@ namespace Sass { if (!Util::isPrintable(f, output_style())) { for (size_t i = 0, L = b->length(); i < L; ++i) { Statement_Obj stm = b->at(i); - if (dynamic_cast(&stm)) { + if (Cast(stm)) { stm->perform(this); } } @@ -237,7 +237,7 @@ namespace Sass { if (!Util::isPrintable(m, output_style())) { for (size_t i = 0, L = b->length(); i < L; ++i) { Statement_Obj stm = b->at(i); - if (dynamic_cast(&stm)) { + if (Cast(stm)) { stm->perform(this); } } @@ -282,7 +282,7 @@ namespace Sass { if (v) { append_mandatory_space(); // ruby sass bug? should use options? - append_token(v->to_string(/* opt */), &v); + append_token(v->to_string(/* opt */), v); } if (!b) { append_delimiter(); diff --git a/src/libsass/src/parser.cpp b/src/libsass/src/parser.cpp index 89cdb9fe5..d266484ce 100755 --- a/src/libsass/src/parser.cpp +++ b/src/libsass/src/parser.cpp @@ -1,7 +1,4 @@ #include "sass.hpp" -#include -#include -#include #include "parser.hpp" #include "file.hpp" #include "inspect.hpp" @@ -24,8 +21,10 @@ // Another case with delayed values are colors. In compressed mode // only processed values get compressed (other are left as written). +#include +#include +#include #include -#include namespace Sass { using namespace Constants; @@ -96,21 +95,25 @@ namespace Sass { /* main entry point to parse root block */ Block_Obj Parser::parse() { - bool is_root = false; - Block_Obj root = SASS_MEMORY_NEW(Block, pstate, 0, true); + + // consume unicode BOM read_bom(); - // custom headers + // create a block AST node to hold children + Block_Obj root = SASS_MEMORY_NEW(Block, pstate, 0, true); + + // check seems a bit esoteric but works if (ctx.resources.size() == 1) { - is_root = true; - ctx.apply_custom_headers(&root, path, pstate); + // apply headers only on very first include + ctx.apply_custom_headers(root, path, pstate); } + // parse children nodes block_stack.push_back(root); - /* bool rv = */ parse_block_nodes(is_root); + parse_block_nodes(true); block_stack.pop_back(); - // update for end position + // update final position root->update_pstate(pstate); if (position != end) { @@ -138,7 +141,7 @@ namespace Sass { Block_Obj block = SASS_MEMORY_NEW(Block, pstate, 0, is_root); block_stack.push_back(block); - if (!parse_block_nodes()) css_error("Invalid CSS", " after ", ": expected \"}\", was "); + if (!parse_block_nodes(is_root)) css_error("Invalid CSS", " after ", ": expected \"}\", was "); if (!lex_css < exactly<'}'> >()) { css_error("Invalid CSS", " after ", ": expected \"}\", was "); @@ -154,7 +157,7 @@ namespace Sass { block_stack.pop_back(); - return █ + return block; } // convenience function for block parsing @@ -162,7 +165,6 @@ namespace Sass { // also updates the `in_at_root` flag Block_Obj Parser::parse_block(bool is_root) { - LOCAL_FLAG(in_at_root, is_root); return parse_css_block(is_root); } @@ -214,15 +216,15 @@ namespace Sass { // also parse block comments // first parse everything that is allowed in functions - if (lex < variable >(true)) { block->append(&parse_assignment()); } - else if (lex < kwd_err >(true)) { block->append(&parse_error()); } - else if (lex < kwd_dbg >(true)) { block->append(&parse_debug()); } - else if (lex < kwd_warn >(true)) { block->append(&parse_warning()); } - else if (lex < kwd_if_directive >(true)) { block->append(&parse_if_directive()); } - else if (lex < kwd_for_directive >(true)) { block->append(&parse_for_directive()); } - else if (lex < kwd_each_directive >(true)) { block->append(&parse_each_directive()); } - else if (lex < kwd_while_directive >(true)) { block->append(&parse_while_directive()); } - else if (lex < kwd_return_directive >(true)) { block->append(&parse_return_directive()); } + if (lex < variable >(true)) { block->append(parse_assignment()); } + else if (lex < kwd_err >(true)) { block->append(parse_error()); } + else if (lex < kwd_dbg >(true)) { block->append(parse_debug()); } + else if (lex < kwd_warn >(true)) { block->append(parse_warning()); } + else if (lex < kwd_if_directive >(true)) { block->append(parse_if_directive()); } + else if (lex < kwd_for_directive >(true)) { block->append(parse_for_directive()); } + else if (lex < kwd_each_directive >(true)) { block->append(parse_each_directive()); } + else if (lex < kwd_while_directive >(true)) { block->append(parse_while_directive()); } + else if (lex < kwd_return_directive >(true)) { block->append(parse_return_directive()); } // parse imports to process later else if (lex < kwd_import >(true)) { @@ -232,9 +234,11 @@ namespace Sass { error("Import directives may not be used within control directives or mixins.", pstate); } } + // this puts the parsed doc into sheets + // import stub will fetch this in expand Import_Obj imp = parse_import(); // if it is a url, we only add the statement - if (!imp->urls().empty()) block->append(&imp); + if (!imp->urls().empty()) block->append(imp); // process all resources now (add Import_Stub nodes) for (size_t i = 0, S = imp->incs().size(); i < S; ++i) { block->append(SASS_MEMORY_NEW(Import_Stub, pstate, imp->incs()[i])); @@ -244,32 +248,38 @@ namespace Sass { else if (lex < kwd_extend >(true)) { Lookahead lookahead = lookahead_for_include(position); if (!lookahead.found) css_error("Invalid CSS", " after ", ": expected selector, was "); - Selector_Obj target; - if (lookahead.has_interpolants) target = &parse_selector_schema(lookahead.found); - else target = &parse_selector_list(true); - block->append(SASS_MEMORY_NEW(Extension, pstate, &target)); + Selector_List_Obj target; + if (!lookahead.has_interpolants) { + target = parse_selector_list(true); + } + else { + target = SASS_MEMORY_NEW(Selector_List, pstate); + target->schema(parse_selector_schema(lookahead.found, true)); + } + + block->append(SASS_MEMORY_NEW(Extension, pstate, target)); } // selector may contain interpolations which need delayed evaluation else if (!(lookahead_result = lookahead_for_selector(position)).error) - { block->append(&parse_ruleset(lookahead_result, is_root)); } + { block->append(parse_ruleset(lookahead_result)); } // parse multiple specific keyword directives - else if (lex < kwd_media >(true)) { block->append(&parse_media_block()); } - else if (lex < kwd_at_root >(true)) { block->append(&parse_at_root_block()); } - else if (lex < kwd_include_directive >(true)) { block->append(&parse_include_directive()); } - else if (lex < kwd_content_directive >(true)) { block->append(&parse_content_directive()); } - else if (lex < kwd_supports_directive >(true)) { block->append(&parse_supports_directive()); } - else if (lex < kwd_mixin >(true)) { block->append(&parse_definition(Definition::MIXIN)); } - else if (lex < kwd_function >(true)) { block->append(&parse_definition(Definition::FUNCTION)); } + else if (lex < kwd_media >(true)) { block->append(parse_media_block()); } + else if (lex < kwd_at_root >(true)) { block->append(parse_at_root_block()); } + else if (lex < kwd_include_directive >(true)) { block->append(parse_include_directive()); } + else if (lex < kwd_content_directive >(true)) { block->append(parse_content_directive()); } + else if (lex < kwd_supports_directive >(true)) { block->append(parse_supports_directive()); } + else if (lex < kwd_mixin >(true)) { block->append(parse_definition(Definition::MIXIN)); } + else if (lex < kwd_function >(true)) { block->append(parse_definition(Definition::FUNCTION)); } // ignore the @charset directive for now else if (lex< kwd_charset_directive >(true)) { parse_charset_directive(); } // generic at keyword (keep last) - else if (lex< re_special_directive >(true)) { block->append(&parse_special_directive()); } - else if (lex< re_prefixed_directive >(true)) { block->append(&parse_prefixed_directive()); } - else if (lex< at_keyword >(true)) { block->append(&parse_directive()); } + else if (lex< re_special_directive >(true)) { block->append(parse_special_directive()); } + else if (lex< re_prefixed_directive >(true)) { block->append(parse_prefixed_directive()); } + else if (lex< at_keyword >(true)) { block->append(parse_directive()); } else if (is_root /* && block->is_root() */) { lex< css_whitespace >(); @@ -283,7 +293,7 @@ namespace Sass { // maybe we are expected to parse something? Declaration_Obj decl = parse_declaration(); decl->tabs(indentation); - block->append(&decl); + block->append(decl); // maybe we have a "sub-block" if (peek< exactly<'{'> >()) { if (decl->is_indented()) ++ indentation; @@ -312,24 +322,24 @@ namespace Sass { } else if (lex< uri_prefix >()) { Arguments_Obj args = SASS_MEMORY_NEW(Arguments, pstate); - Function_Call_Obj result = SASS_MEMORY_NEW(Function_Call, pstate, "url", &args); + Function_Call_Obj result = SASS_MEMORY_NEW(Function_Call, pstate, "url", args); if (lex< quoted_string >()) { - Expression_Obj the_url = &parse_string(); - args->append(SASS_MEMORY_NEW(Argument, the_url->pstate(), &the_url)); + Expression_Obj the_url = parse_string(); + args->append(SASS_MEMORY_NEW(Argument, the_url->pstate(), the_url)); } else if (String_Obj the_url = parse_url_function_argument()) { - args->append(SASS_MEMORY_NEW(Argument, the_url->pstate(), &the_url)); + args->append(SASS_MEMORY_NEW(Argument, the_url->pstate(), the_url)); } else if (peek < skip_over_scopes < exactly < '(' >, exactly < ')' > > >(position)) { Expression_Obj the_url = parse_list(); // parse_interpolated_chunk(lexed); - args->append(SASS_MEMORY_NEW(Argument, the_url->pstate(), &the_url)); + args->append(SASS_MEMORY_NEW(Argument, the_url->pstate(), the_url)); } else { error("malformed URL", pstate); } if (!lex< exactly<')'> >()) error("URI is missing ')'", pstate); - to_import.push_back(std::pair("", &result)); + to_import.push_back(std::pair("", result)); } else { if (first) error("@import directive requires a url or quoted path", pstate); @@ -345,9 +355,12 @@ namespace Sass { for(auto location : to_import) { if (location.second) { - imp->urls().push_back(&location.second); - } else if (!ctx.call_importers(unquote(location.first), path, pstate, &imp)) { - ctx.import_url(&imp, location.first, path); + imp->urls().push_back(location.second); + } + // check if custom importers want to take over the handling + else if (!ctx.call_importers(unquote(location.first), path, pstate, imp)) { + // nobody wants it, so we do our import + ctx.import_url(imp, location.first, path); } } @@ -367,7 +380,7 @@ namespace Sass { else stack.push_back(Scope::Function); Block_Obj body = parse_block(); stack.pop_back(); - return SASS_MEMORY_NEW(Definition, source_position_of_def, name, ¶ms, &body, which_type); + return SASS_MEMORY_NEW(Definition, source_position_of_def, name, params, body, which_type); } Parameters_Obj Parser::parse_parameters() @@ -378,7 +391,7 @@ namespace Sass { if (lex_css< exactly<'('> >()) { // if there's anything there at all if (!peek_css< exactly<')'> >()) { - do params->append(&parse_parameter()); + do params->append(parse_parameter()); while (lex_css< exactly<','> >()); } if (!lex_css< exactly<')'> >()) error("expected a variable name (e.g. $x) or ')' for the parameter list for " + name, position); @@ -402,7 +415,7 @@ namespace Sass { else if (lex< exactly< ellipsis > >()) { is_rest = true; } - return SASS_MEMORY_NEW(Parameter, pos, name, &val, is_rest); + return SASS_MEMORY_NEW(Parameter, pos, name, val, is_rest); } Arguments_Obj Parser::parse_arguments() @@ -413,7 +426,7 @@ namespace Sass { if (lex_css< exactly<'('> >()) { // if there's anything there at all if (!peek_css< exactly<')'> >()) { - do args->append(&parse_argument()); + do args->append(parse_argument()); while (lex_css< exactly<','> >()); } if (!lex_css< exactly<')'> >()) error("expected a variable name (e.g. $x) or ')' for the parameter list for " + name, position); @@ -441,7 +454,7 @@ namespace Sass { bool is_arglist = false; bool is_keyword = false; Expression_Obj val = parse_space_list(); - List_Ptr l = SASS_MEMORY_CAST(List, val); + List_Ptr l = Cast(val); if (lex_css< exactly< ellipsis > >()) { if (val->concrete_type() == Expression::MAP || ( (l != NULL && l->separator() == SASS_HASH) @@ -464,7 +477,7 @@ namespace Sass { Expression_Obj val; Lookahead lookahead = lookahead_for_value(position); if (lookahead.has_interpolants && lookahead.found) { - val = &parse_value_schema(lookahead.found); + val = parse_value_schema(lookahead.found); } else { val = parse_list(); } @@ -478,15 +491,22 @@ namespace Sass { } // a ruleset connects a selector and a block - Ruleset_Obj Parser::parse_ruleset(Lookahead lookahead, bool is_root) + Ruleset_Obj Parser::parse_ruleset(Lookahead lookahead) { + // inherit is_root from parent block + Block_Obj parent = block_stack.back(); + bool is_root = parent && parent->is_root(); // make sure to move up the the last position lex < optional_css_whitespace >(false, true); // create the connector object (add parts later) Ruleset_Obj ruleset = SASS_MEMORY_NEW(Ruleset, pstate); // parse selector static or as schema to be evaluated later - if (lookahead.parsable) ruleset->selector(&parse_selector_list(is_root)); - else ruleset->selector(&parse_selector_schema(lookahead.found)); + if (lookahead.parsable) ruleset->selector(parse_selector_list(false)); + else { + Selector_List_Obj list = SASS_MEMORY_NEW(Selector_List, pstate); + list->schema(parse_selector_schema(lookahead.found, false)); + ruleset->selector(list); + } // then parse the inner block stack.push_back(Scope::Rules); ruleset->block(parse_block()); @@ -494,7 +514,6 @@ namespace Sass { // update for end position ruleset->update_pstate(pstate); ruleset->block()->update_pstate(pstate); - // inherit is_root from parent block // need this info for sanity checks ruleset->is_root(is_root); // return AST Node @@ -504,7 +523,7 @@ namespace Sass { // parse a selector schema that will be evaluated in the eval stage // uses a string schema internally to do the actual schema handling // in the eval stage we will be re-parse it into an actual selector - Selector_Schema_Obj Parser::parse_selector_schema(const char* end_of_selector) + Selector_Schema_Obj Parser::parse_selector_schema(const char* end_of_selector, bool chroot) { // move up to the start lex< optional_spaces >(); @@ -513,6 +532,7 @@ namespace Sass { String_Schema_Ptr schema = SASS_MEMORY_NEW(String_Schema, pstate); // the selector schema is pretty much just a wrapper for the string schema Selector_Schema_Ptr selector_schema = SASS_MEMORY_NEW(Selector_Schema, pstate, schema); + selector_schema->connect_parent(chroot == false); selector_schema->media_block(last_media_block); // process until end @@ -525,7 +545,7 @@ namespace Sass { String_Constant_Obj str = SASS_MEMORY_NEW(String_Constant, pstate, parsed); pstate += Offset(parsed); str->update_pstate(pstate); - schema->append(&str); + schema->append(str); } // check if the interpolation only contains white-space (error out) @@ -541,7 +561,7 @@ namespace Sass { interpolant->is_interpolant(true); // schema->has_interpolants(true); // add to the string schema - schema->append(&interpolant); + schema->append(interpolant); // advance parser state pstate.add(p+2, j); // advance position @@ -557,7 +577,7 @@ namespace Sass { pstate += Offset(parsed); str->update_pstate(pstate); i = end_of_selector; - schema->append(&str); + schema->append(str); } // exit loop } @@ -611,24 +631,28 @@ namespace Sass { // parse a list of complex selectors // this is the main entry point for most - Selector_List_Obj Parser::parse_selector_list(bool in_root) + Selector_List_Obj Parser::parse_selector_list(bool chroot) { bool reloop = true; bool had_linefeed = false; Complex_Selector_Obj sel; Selector_List_Obj group = SASS_MEMORY_NEW(Selector_List, pstate); group->media_block(last_media_block); + + if (peek_css< alternatives < end_of_file, exactly <'{'> > >()) { + css_error("Invalid CSS", " after ", ": expected selector, was "); + } + do { reloop = false; had_linefeed = had_linefeed || peek_newline(); - if (peek_css< class_char < selector_list_delims > >()) + if (peek_css< alternatives < class_char < selector_list_delims > > >()) break; // in case there are superfluous commas at the end - // now parse the complex selector - sel = parse_complex_selector(in_root); + sel = parse_complex_selector(chroot); if (!sel) return group.detach(); @@ -662,7 +686,7 @@ namespace Sass { // complex selector, with one of four combinator operations. // the compound selector (head) is optional, since the combinator // can come first in the whole selector sequence (like `> DIV'). - Complex_Selector_Obj Parser::parse_complex_selector(bool in_root) + Complex_Selector_Obj Parser::parse_complex_selector(bool chroot) { String_Ptr reference = 0; @@ -670,6 +694,8 @@ namespace Sass { advanceToNextToken(); Complex_Selector_Obj sel = SASS_MEMORY_NEW(Complex_Selector, pstate); + if (peek < end_of_file >()) return 0; + // parse the left hand side Compound_Selector_Obj lhs; // special case if it starts with combinator ([+~>]) @@ -678,11 +704,9 @@ namespace Sass { lhs = parse_compound_selector(); } - // check for end of file condition - if (peek < end_of_file >()) return 0; // parse combinator between lhs and rhs - Complex_Selector::Combinator combinator; + Complex_Selector::Combinator combinator = Complex_Selector::ANCESTOR_OF; if (lex< exactly<'+'> >()) combinator = Complex_Selector::ADJACENT_TO; else if (lex< exactly<'~'> >()) combinator = Complex_Selector::PRECEDES; else if (lex< exactly<'>'> >()) combinator = Complex_Selector::PARENT_OF; @@ -693,7 +717,6 @@ namespace Sass { reference = SASS_MEMORY_NEW(String_Constant, pstate, lexed); if (!lex < exactly < '/' > >()) return 0; // ToDo: error msg? } - else /* if (lex< zero >()) */ combinator = Complex_Selector::ANCESTOR_OF; if (!lhs && combinator == Complex_Selector::ANCESTOR_OF) return 0; @@ -715,7 +738,7 @@ namespace Sass { // add a parent selector if we are not in a root // also skip adding parent ref if we only have refs - if (!sel->has_parent_ref() && !in_at_root && !in_root) { + if (!sel->has_parent_ref() && !chroot) { // create the objects to wrap parent selector reference Compound_Selector_Obj head = SASS_MEMORY_NEW(Compound_Selector, pstate); Parent_Selector_Ptr parent = SASS_MEMORY_NEW(Parent_Selector, pstate, false); @@ -760,7 +783,7 @@ namespace Sass { // parse functional if (match < re_pseudo_selector >()) { - seq->append(&parse_simple_selector()); + seq->append(parse_simple_selector()); } // parse parent selector else if (lex< exactly<'&'> >(false)) @@ -795,11 +818,11 @@ namespace Sass { else { Simple_Selector_Obj sel = parse_simple_selector(); if (!sel) return 0; - seq->append(&sel); + seq->append(sel); } } - if (seq && !peek_css>()) { + if (seq && !peek_css>>()) { seq->has_line_break(peek_newline()); } @@ -825,16 +848,16 @@ namespace Sass { return SASS_MEMORY_NEW(Element_Selector, pstate, lexed); } else if (peek< pseudo_not >()) { - return &parse_negated_selector(); + return parse_negated_selector(); } else if (peek< re_pseudo_selector >()) { - return &parse_pseudo_selector(); + return parse_pseudo_selector(); } else if (peek< exactly<':'> >()) { - return &parse_pseudo_selector(); + return parse_pseudo_selector(); } else if (lex < exactly<'['> >()) { - return &parse_attribute_selector(); + return parse_attribute_selector(); } else if (lex< placeholder >()) { Placeholder_Selector_Ptr sel = SASS_MEMORY_NEW(Placeholder_Selector, pstate, lexed); @@ -855,7 +878,7 @@ namespace Sass { error("negated selector is missing ')'", pstate); } name.erase(name.size() - 1); - return SASS_MEMORY_NEW(Wrapped_Selector, nsource_position, name, &negated); + return SASS_MEMORY_NEW(Wrapped_Selector, nsource_position, name, negated); } // a pseudo selector often starts with one or two colons @@ -896,7 +919,7 @@ namespace Sass { } else if (Selector_List_Obj wrapped = parse_selector_list(true)) { if (wrapped && lex_css< exactly<')'> >()) { - return SASS_MEMORY_NEW(Wrapped_Selector, p, name, &wrapped); + return SASS_MEMORY_NEW(Wrapped_Selector, p, name, wrapped); } } @@ -933,7 +956,7 @@ namespace Sass { value = SASS_MEMORY_NEW(String_Constant, p, lexed); } else if (lex_css< quoted_string >()) { - value = &parse_interpolated_chunk(lexed, true); // needed! + value = parse_interpolated_chunk(lexed, true); // needed! } else { error("expected a string constant or identifier in attribute selector for " + name, pstate); @@ -974,22 +997,22 @@ namespace Sass { if (peek_css< exactly<';'> >()) error("style declaration must contain a value", pstate); if (peek_css< exactly<'{'> >()) is_indented = false; // don't indent if value is empty if (peek_css< static_value >()) { - return SASS_MEMORY_NEW(Declaration, prop->pstate(), prop, &parse_static_value()/*, lex()*/); + return SASS_MEMORY_NEW(Declaration, prop->pstate(), prop, parse_static_value()/*, lex()*/); } else { Expression_Obj value; Lookahead lookahead = lookahead_for_value(position); if (lookahead.found) { if (lookahead.has_interpolants) { - value = &parse_value_schema(lookahead.found); + value = parse_value_schema(lookahead.found); } else { - value = &parse_list(DELAYED); + value = parse_list(DELAYED); } } else { - value = &parse_list(DELAYED); - if (List_Ptr list = SASS_MEMORY_CAST(List, value)) { - if (list->length() == 0 && !peek< exactly <'{'> >()) { + value = parse_list(DELAYED); + if (List_Ptr list = Cast(value)) { + if (!list->is_bracketed() && list->length() == 0 && !peek< exactly <'{'> >()) { css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was "); } } @@ -1003,6 +1026,7 @@ namespace Sass { } // parse +/- and return false if negative + // this is never hit via spec tests bool Parser::parse_number_prefix() { bool positive = true; @@ -1053,7 +1077,50 @@ namespace Sass { ps.offset = pstate - ps + pstate.offset; map->pstate(ps); - return ↦ + return map; + } + + Expression_Obj Parser::parse_bracket_list() + { + // check if we have an empty list + // return the empty list as such + if (peek_css< list_terminator >(position)) + { + // return an empty list (nothing to delay) + return SASS_MEMORY_NEW(List, pstate, 0, SASS_SPACE, false, true); + } + + bool has_paren = peek_css< exactly<'('> >() != NULL; + + // now try to parse a space list + Expression_Obj list = parse_space_list(); + // if it's a singleton, return it (don't wrap it) + if (!peek_css< exactly<','> >(position)) { + List_Obj l = Cast(list); + if (!l || l->is_bracketed() || has_paren) { + List_Obj bracketed_list = SASS_MEMORY_NEW(List, pstate, 1, SASS_SPACE, false, true); + bracketed_list->append(list); + return bracketed_list; + } + l->is_bracketed(true); + return l; + } + + // if we got so far, we actually do have a comma list + List_Obj bracketed_list = SASS_MEMORY_NEW(List, pstate, 2, SASS_COMMA, false, true); + // wrap the first expression + bracketed_list->append(list); + + while (lex_css< exactly<','> >()) + { + // check for abort condition + if (peek_css< list_terminator >(position) + ) { break; } + // otherwise add another expression + bracketed_list->append(parse_space_list()); + } + // return the list + return bracketed_list; } // parse list returns either a space separated list, @@ -1069,18 +1136,7 @@ namespace Sass { { // check if we have an empty list // return the empty list as such - if (peek_css< alternatives < - // exactly<'!'>, - exactly<';'>, - exactly<'}'>, - exactly<'{'>, - exactly<')'>, - exactly<':'>, - end_of_file, - exactly, - default_flag, - global_flag - > >(position)) + if (peek_css< list_terminator >(position)) { // return an empty list (nothing to delay) return SASS_MEMORY_NEW(List, pstate, 0); @@ -1104,23 +1160,13 @@ namespace Sass { while (lex_css< exactly<','> >()) { // check for abort condition - if (peek_css< alternatives < - exactly<';'>, - exactly<'}'>, - exactly<'{'>, - exactly<')'>, - exactly<':'>, - end_of_file, - exactly, - default_flag, - global_flag - > >(position) + if (peek_css< list_terminator >(position) ) { break; } // otherwise add another expression comma_list->append(parse_space_list()); } // return the list - return &comma_list; + return comma_list; } // EO parse_comma_list @@ -1129,43 +1175,22 @@ namespace Sass { { Expression_Obj disj1 = parse_disjunction(); // if it's a singleton, return it (don't wrap it) - if (peek_css< alternatives < - // exactly<'!'>, - exactly<';'>, - exactly<'}'>, - exactly<'{'>, - exactly<')'>, - exactly<','>, - exactly<':'>, - end_of_file, - exactly, - default_flag, - global_flag - > >(position) - ) { return disj1; } + if (peek_css< space_list_terminator >(position) + ) { + return disj1; } List_Obj space_list = SASS_MEMORY_NEW(List, pstate, 2, SASS_SPACE); space_list->append(disj1); - while (!(peek_css< alternatives < - // exactly<'!'>, - exactly<';'>, - exactly<'}'>, - exactly<'{'>, - exactly<')'>, - exactly<','>, - exactly<':'>, - end_of_file, - exactly, - default_flag, - global_flag - > >(position)) && peek_css< optional_css_whitespace >() != end + while ( + !(peek_css< space_list_terminator >(position)) && + peek_css< optional_css_whitespace >() != end ) { // the space is parsed implicitly? space_list->append(parse_disjunction()); } // return the list - return &space_list; + return space_list; } // EO parse_space_list @@ -1200,7 +1225,7 @@ namespace Sass { // parse multiple right hand sides std::vector operands; while (lex_css< kwd_and >()) { - operands.push_back(&parse_relation()); + operands.push_back(parse_relation()); } // if it's a singleton, return it directly if (operands.size() == 0) return rel; @@ -1246,7 +1271,7 @@ namespace Sass { // is directly adjacent to expression? bool right_ws = peek < css_comments >() != NULL; operators.push_back({ op, left_ws, right_ws }); - operands.push_back(&parse_expression()); + operands.push_back(parse_expression()); left_ws = peek < css_comments >() != NULL; } // we are called recursively for list, so we first @@ -1297,7 +1322,7 @@ namespace Sass { bool right_ws = peek < css_comments >() != NULL; operators.push_back({ lexed.to_string() == "+" ? Sass_OP::ADD : Sass_OP::SUB, left_ws, right_ws }); - operands.push_back(&parse_operators()); + operands.push_back(parse_operators()); left_ws = peek < css_comments >() != NULL; } @@ -1350,58 +1375,66 @@ namespace Sass { // lex the expected closing parenthesis if (!lex_css< exactly<')'> >()) error("unclosed parenthesis", pstate); // expression can be evaluated - return &value; + return value; + } + else if (lex_css< exactly<'['> >()) { + // explicit bracketed + Expression_Obj value = parse_bracket_list(); + // lex the expected closing square bracket + if (!lex_css< exactly<']'> >()) error("unclosed squared bracket", pstate); + return value; } // string may be interpolated // if (lex< quoted_string >()) { // return &parse_string(); // } else if (peek< ie_property >()) { - return &parse_ie_property(); + return parse_ie_property(); } else if (peek< ie_keyword_arg >()) { - return &parse_ie_keyword_arg(); + return parse_ie_keyword_arg(); } else if (peek< sequence < calc_fn_call, exactly <'('> > >()) { - return &parse_calc_function(); + return parse_calc_function(); } else if (lex < functional_schema >()) { - return &parse_function_call_schema(); + return parse_function_call_schema(); } else if (lex< identifier_schema >()) { String_Obj string = parse_identifier_schema(); - if (String_Schema_Ptr schema = SASS_MEMORY_CAST(String_Schema, string)) { + if (String_Schema_Ptr schema = Cast(string)) { if (lex < exactly < '(' > >()) { - schema->append(&parse_list()); + schema->append(parse_list()); lex < exactly < ')' > >(); } } - return &string; + return string; } else if (peek< sequence< uri_prefix, W, real_uri_value > >()) { - return &parse_url_function_string(); + return parse_url_function_string(); } else if (peek< re_functional >()) { - return &parse_function_call(); + return parse_function_call(); } else if (lex< exactly<'+'> >()) { - Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::PLUS, &parse_factor()); + Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::PLUS, parse_factor()); if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed()); return ex; } else if (lex< exactly<'-'> >()) { - Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::MINUS, &parse_factor()); + Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::MINUS, parse_factor()); if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed()); return ex; } else if (lex< sequence< kwd_not > >()) { - Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::NOT, &parse_factor()); + Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::NOT, parse_factor()); if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed()); return ex; } + // this whole branch is never hit via spec tests else if (peek < sequence < one_plus < alternatives < css_whitespace, exactly<'-'>, exactly<'+'> > >, number > >()) { - if (parse_number_prefix()) return &parse_value(); // prefix is positive - Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::MINUS, &parse_value()); + if (parse_number_prefix()) return parse_value(); // prefix is positive + Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::MINUS, parse_value()); if (ex->operand()) ex->is_delayed(ex->operand()->is_delayed()); return ex; } @@ -1430,14 +1463,14 @@ namespace Sass { // string may be interpolated if (lex< sequence < quoted_string, lookahead < exactly <'-'> > > >()) - { return &parse_string(); } + { return parse_string(); } if (const char* stop = peek< value_schema >()) - { return &parse_value_schema(stop); } + { return parse_value_schema(stop); } // string may be interpolated if (lex< quoted_string >()) - { return &parse_string(); } + { return parse_string(); } if (lex< kwd_true >()) { return SASS_MEMORY_NEW(Boolean, pstate, true); } @@ -1521,7 +1554,7 @@ namespace Sass { // parse the interpolant and accumulate it Expression_Obj interp_node = Parser::from_token(Token(p+2, j), ctx, pstate, source).parse_list(); interp_node->is_interpolant(true); - schema->append(&interp_node); + schema->append(interp_node); i = j; } else { @@ -1585,7 +1618,7 @@ namespace Sass { // parse the interpolant and accumulate it Expression_Obj interp_node = Parser::from_token(Token(p+2, j), ctx, pstate, source).parse_list(); interp_node->is_interpolant(true); - schema->append(&interp_node); + schema->append(interp_node); i = j; } else { @@ -1614,9 +1647,9 @@ namespace Sass { } lex< exactly<'='> >(); kwd_arg->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed)); - if (peek< variable >()) kwd_arg->append(&parse_list()); + if (peek< variable >()) kwd_arg->append(parse_list()); else if (lex< number >()) kwd_arg->append(SASS_MEMORY_NEW(Textual, pstate, Textual::NUMBER, Util::normalize_decimals(lexed))); - else if (peek < ie_keyword_arg_value >()) { kwd_arg->append(&parse_list()); } + else if (peek < ie_keyword_arg_value >()) { kwd_arg->append(parse_list()); } return kwd_arg; } @@ -1644,7 +1677,7 @@ namespace Sass { // schema->append(SASS_MEMORY_NEW(String_Constant, pstate, " ")); } if ((e = peek< re_functional >()) && e < stop) { - schema->append(&parse_function_call()); + schema->append(parse_function_call()); } // lex an interpolant /#{...}/ else if (lex< exactly < hash_lbrace > >()) { @@ -1674,7 +1707,7 @@ namespace Sass { // need_space = true; // if (schema->length()) schema->append(SASS_MEMORY_NEW(String_Constant, pstate, " ")); // else need_space = true; - schema->append(&parse_string()); + schema->append(parse_string()); if ((*position == '"' || *position == '\'') || peek < alternatives < alpha > >()) { // need_space = true; } @@ -1712,7 +1745,7 @@ namespace Sass { } // lex a value in parentheses else if (peek< parenthese_scope >()) { - schema->append(&parse_factor()); + schema->append(parse_factor()); } else { break; @@ -1746,7 +1779,7 @@ namespace Sass { if (i < p) { // accumulate the preceding segment if it's nonempty const char* o = position; position = i; - schema->append(&parse_value_schema(p)); + schema->append(parse_value_schema(p)); position = o; } // we need to skip anything inside strings @@ -1771,7 +1804,7 @@ namespace Sass { else { // no interpolants left; add the last segment if nonempty if (i < end) { const char* o = position; position = i; - schema->append(&parse_value_schema(id.end)); + schema->append(parse_value_schema(id.end)); position = o; } break; @@ -1796,9 +1829,9 @@ namespace Sass { exactly < ')' > > >(); - Argument_Obj arg = SASS_MEMORY_NEW(Argument, arg_pos, &parse_interpolated_chunk(Token(arg_beg, arg_end))); + Argument_Obj arg = SASS_MEMORY_NEW(Argument, arg_pos, parse_interpolated_chunk(Token(arg_beg, arg_end))); Arguments_Obj args = SASS_MEMORY_NEW(Arguments, arg_pos); - args->append(&arg); + args->append(arg); return SASS_MEMORY_NEW(Function_Call, call_pos, name, args); } @@ -1818,16 +1851,16 @@ namespace Sass { } std::string uri(""); - if (&url_string) { + if (url_string) { uri = url_string->to_string({ NESTED, 5 }); } - if (String_Schema_Ptr schema = dynamic_cast(&url_string)) { + if (String_Schema_Ptr schema = Cast(url_string)) { String_Schema_Obj res = SASS_MEMORY_NEW(String_Schema, pstate); res->append(SASS_MEMORY_NEW(String_Constant, pstate, prefix)); res->append(schema); res->append(SASS_MEMORY_NEW(String_Constant, pstate, suffix)); - return &res; + return res; } else { std::string res = prefix + uri + suffix; return SASS_MEMORY_NEW(String_Constant, pstate, res); @@ -1850,7 +1883,7 @@ namespace Sass { pp = sequence< interpolant, real_uri_value >(pp); } position = pp; - return &parse_interpolated_chunk(Token(p, position)); + return parse_interpolated_chunk(Token(p, position)); } else if (uri != "") { std::string res = Util::rtrim(uri); @@ -1897,10 +1930,10 @@ namespace Sass { // we want all other comments to be parsed if (lex_css< elseif_directive >()) { alternative = SASS_MEMORY_NEW(Block, pstate); - alternative->append(&parse_if_directive(true)); + alternative->append(parse_if_directive(true)); } else if (lex_css< kwd_else_directive >()) { - alternative = &parse_block(root); + alternative = parse_block(root); } stack.pop_back(); return SASS_MEMORY_NEW(If, if_source_position, predicate, block, alternative); @@ -1997,9 +2030,9 @@ namespace Sass { media_block->media_queries(parse_media_queries()); Media_Block_Obj prev_media_block = last_media_block; - last_media_block = &media_block; + last_media_block = media_block; media_block->block(parse_css_block()); - last_media_block = &prev_media_block; + last_media_block = prev_media_block; stack.pop_back(); return media_block.detach(); } @@ -2008,8 +2041,8 @@ namespace Sass { { advanceToNextToken(); List_Obj queries = SASS_MEMORY_NEW(List, pstate, 0, SASS_COMMA); - if (!peek_css < exactly <'{'> >()) queries->append(&parse_media_query()); - while (lex_css < exactly <','> >()) queries->append(&parse_media_query()); + if (!peek_css < exactly <'{'> >()) queries->append(parse_media_query()); + while (lex_css < exactly <','> >()) queries->append(parse_media_query()); queries->update_pstate(pstate); return queries.detach(); } @@ -2022,19 +2055,19 @@ namespace Sass { if (lex < kwd_not >()) { media_query->is_negated(true); lex < css_comments >(false); } else if (lex < kwd_only >()) { media_query->is_restricted(true); lex < css_comments >(false); } - if (lex < identifier_schema >()) media_query->media_type(&parse_identifier_schema()); - else if (lex < identifier >()) media_query->media_type(&parse_interpolated_chunk(lexed)); - else media_query->append(&parse_media_expression()); + if (lex < identifier_schema >()) media_query->media_type(parse_identifier_schema()); + else if (lex < identifier >()) media_query->media_type(parse_interpolated_chunk(lexed)); + else media_query->append(parse_media_expression()); - while (lex_css < kwd_and >()) media_query->append(&parse_media_expression()); + while (lex_css < kwd_and >()) media_query->append(parse_media_expression()); if (lex < identifier_schema >()) { String_Schema_Ptr schema = SASS_MEMORY_NEW(String_Schema, pstate); - schema->append(&media_query->media_type()); + schema->append(media_query->media_type()); schema->append(SASS_MEMORY_NEW(String_Constant, pstate, " ")); - schema->append(&parse_identifier_schema()); + schema->append(parse_identifier_schema()); media_query->media_type(schema); } - while (lex_css < kwd_and >()) media_query->append(&parse_media_expression()); + while (lex_css < kwd_and >()) media_query->append(parse_media_expression()); media_query->update_pstate(pstate); @@ -2045,7 +2078,7 @@ namespace Sass { { if (lex < identifier_schema >()) { String_Obj ss = parse_identifier_schema(); - return SASS_MEMORY_NEW(Media_Query_Expression, pstate, &ss, 0, true); + return SASS_MEMORY_NEW(Media_Query_Expression, pstate, ss, 0, true); } if (!lex_css< exactly<'('> >()) { error("media query expression must begin with '('", pstate); @@ -2054,10 +2087,10 @@ namespace Sass { if (peek_css< exactly<')'> >()) { error("media feature required in media query expression", pstate); } - feature = &parse_expression(); + feature = parse_expression(); Expression_Obj expression = 0; if (lex_css< exactly<':'> >()) { - expression = &parse_list(DELAYED); + expression = parse_list(DELAYED); } if (!lex_css< exactly<')'> >()) { error("unclosed parenthesis in media query expression", pstate); @@ -2095,13 +2128,13 @@ namespace Sass { { if (!lex < kwd_not >()) return 0; Supports_Condition_Obj cond = parse_supports_condition_in_parens(); - return SASS_MEMORY_NEW(Supports_Negation, pstate, &cond); + return SASS_MEMORY_NEW(Supports_Negation, pstate, cond); } Supports_Condition_Obj Parser::parse_supports_operator() { Supports_Condition_Obj cond = parse_supports_condition_in_parens(); - if (!&cond) return 0; + if (cond.isNull()) return 0; while (true) { Supports_Operator::Operand op = Supports_Operator::OR; @@ -2112,7 +2145,7 @@ namespace Sass { Supports_Condition_Obj right = parse_supports_condition_in_parens(); // Supports_Condition_Ptr cc = SASS_MEMORY_NEW(Supports_Condition, *static_cast(cond)); - cond = SASS_MEMORY_NEW(Supports_Operator, pstate, &cond, &right, op); + cond = SASS_MEMORY_NEW(Supports_Operator, pstate, cond, right, op); } return cond; } @@ -2124,7 +2157,7 @@ namespace Sass { String_Obj interp = parse_interpolated_chunk(lexed); if (!interp) return 0; - return SASS_MEMORY_NEW(Supports_Interpolation, pstate, &interp); + return SASS_MEMORY_NEW(Supports_Interpolation, pstate, interp); } // TODO: This needs some major work. Although feature conditions @@ -2137,7 +2170,7 @@ namespace Sass { if (!declaration) error("@supports condition expected declaration", pstate); cond = SASS_MEMORY_NEW(Supports_Declaration, declaration->pstate(), - &declaration->property(), + declaration->property(), declaration->value()); // ToDo: maybe we need an additional error condition? return cond; @@ -2146,13 +2179,13 @@ namespace Sass { Supports_Condition_Obj Parser::parse_supports_condition_in_parens() { Supports_Condition_Obj interp = parse_supports_interpolation(); - if (&interp != 0) return interp; + if (interp != 0) return interp; if (!lex < exactly <'('> >()) return 0; lex < css_whitespace >(); Supports_Condition_Obj cond = parse_supports_condition(); - if (&cond != 0) { + if (cond != 0) { if (!lex < exactly <')'> >()) error("unclosed parenthesis in @supports declaration", pstate); } else { cond = parse_supports_declaration(); @@ -2168,21 +2201,20 @@ namespace Sass { Block_Obj body = 0; At_Root_Query_Obj expr; Lookahead lookahead_result; - LOCAL_FLAG(in_at_root, true); if (lex_css< exactly<'('> >()) { expr = parse_at_root_query(); } if (peek_css < exactly<'{'> >()) { lex (); - body = &parse_block(true); + body = parse_block(true); } else if ((lookahead_result = lookahead_for_selector(position)).found) { - Ruleset_Obj r = parse_ruleset(lookahead_result, false); + Ruleset_Obj r = parse_ruleset(lookahead_result); body = SASS_MEMORY_NEW(Block, r->pstate(), 1, true); - body->append(&r); + body->append(r); } At_Root_Block_Obj at_root = SASS_MEMORY_NEW(At_Root_Block, at_source_position, body); - if (&expr) at_root->expression(&expr); + if (!expr.isNull()) at_root->expression(expr); return at_root; } @@ -2200,14 +2232,14 @@ namespace Sass { List_Obj value = SASS_MEMORY_NEW(List, feature->pstate(), 1); if (expression->concrete_type() == Expression::LIST) { - value = SASS_MEMORY_CAST(List, expression); + value = Cast(expression); } else value->append(expression); At_Root_Query_Obj cond = SASS_MEMORY_NEW(At_Root_Query, value->pstate(), feature, - &value); + value); if (!lex_css< exactly<')'> >()) error("unclosed parenthesis in @at-root expression", pstate); return cond; } @@ -2218,16 +2250,18 @@ namespace Sass { if (lexed == "@else") error("Invalid CSS: @else must come after @if", pstate); + // this whole branch is never hit via spec tests + Directive_Ptr at_rule = SASS_MEMORY_NEW(Directive, pstate, kwd); Lookahead lookahead = lookahead_for_include(position); if (lookahead.found && !lookahead.has_interpolants) { - at_rule->selector(&parse_selector_list(true)); + at_rule->selector(parse_selector_list(false)); } lex < css_comments >(false); if (lex < static_property >()) { - at_rule->value(&parse_interpolated_chunk(Token(lexed))); + at_rule->value(parse_interpolated_chunk(Token(lexed))); } else if (!(peek < alternatives < exactly<'{'>, exactly<'}'>, exactly<';'> > >())) { at_rule->value(parse_list()); } @@ -2241,6 +2275,7 @@ namespace Sass { return at_rule; } + // this whole branch is never hit via spec tests Directive_Obj Parser::parse_prefixed_directive() { std::string kwd(lexed); @@ -2250,15 +2285,15 @@ namespace Sass { Directive_Obj at_rule = SASS_MEMORY_NEW(Directive, pstate, kwd); Lookahead lookahead = lookahead_for_include(position); if (lookahead.found && !lookahead.has_interpolants) { - at_rule->selector(&parse_selector_list(true)); + at_rule->selector(parse_selector_list(false)); } lex < css_comments >(false); if (lex < static_property >()) { - at_rule->value(&parse_interpolated_chunk(Token(lexed))); + at_rule->value(parse_interpolated_chunk(Token(lexed))); } else if (!(peek < alternatives < exactly<'{'>, exactly<'}'>, exactly<';'> > >())) { - at_rule->value(&parse_list()); + at_rule->value(parse_list()); } lex < css_comments >(false); @@ -2276,7 +2311,7 @@ namespace Sass { Directive_Obj directive = SASS_MEMORY_NEW(Directive, pstate, lexed); String_Schema_Obj val = parse_almost_any_value(); // strip left and right if they are of type string - directive->value(&val); + directive->value(val); if (peek< exactly<'{'> >()) { directive->block(parse_block()); } @@ -2286,7 +2321,7 @@ namespace Sass { Expression_Obj Parser::lex_interpolation() { if (lex < interpolant >(true) != NULL) { - return &parse_interpolated_chunk(lexed, true); + return parse_interpolated_chunk(lexed, true); } return 0; } @@ -2361,12 +2396,12 @@ namespace Sass { { Expression_Obj rv = 0; if (*position == 0) return 0; - if ((rv = &lex_almost_any_value_chars())) return rv; + if ((rv = lex_almost_any_value_chars())) return rv; // if ((rv = lex_block_comment())) return rv; // if ((rv = lex_single_line_comment())) return rv; - if ((rv = &lex_interp_string())) return rv; - if ((rv = &lex_interp_uri())) return rv; - if ((rv = &lex_interpolation())) return rv; + if ((rv = lex_interp_string())) return rv; + if ((rv = lex_interp_uri())) return rv; + if ((rv = lex_interpolation())) return rv; return rv; } @@ -2384,7 +2419,7 @@ namespace Sass { return schema.detach(); } - while ((token = &lex_almost_any_value_token())) { + while ((token = lex_almost_any_value_token())) { schema->append(token); } @@ -2436,7 +2471,7 @@ namespace Sass { // check that we do not have an empty list (ToDo: check if we got all cases) if (peek_css < alternatives < exactly < ';' >, exactly < '}' >, end_of_file > >()) { css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was "); } - return SASS_MEMORY_NEW(Return, pstate, &parse_list()); + return SASS_MEMORY_NEW(Return, pstate, parse_list()); } Lookahead Parser::lookahead_for_selector(const char* start) @@ -2469,6 +2504,7 @@ namespace Sass { // check expected opening bracket // only after successfull matching if (peek < exactly<'{'> >(q)) rv.found = q; + // else if (peek < end_of_file >(q)) rv.found = q; else if (peek < exactly<'('> >(q)) rv.found = q; // else if (peek < exactly<';'> >(q)) rv.found = q; // else if (peek < exactly<'}'> >(q)) rv.found = q; @@ -2538,6 +2574,7 @@ namespace Sass { sequence < // optional_spaces, alternatives < + // end_of_file, exactly<'{'>, exactly<'}'>, exactly<';'> @@ -2641,14 +2678,14 @@ namespace Sass { Expression_Obj Parser::fold_operands(Expression_Obj base, std::vector& operands, Operand op) { for (size_t i = 0, S = operands.size(); i < S; ++i) { - base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), op, &base, operands[i]); + base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), op, base, operands[i]); } return base; } Expression_Obj Parser::fold_operands(Expression_Obj base, std::vector& operands, std::vector& ops, size_t i) { - if (String_Schema_Ptr schema = dynamic_cast(&base)) { + if (String_Schema_Ptr schema = Cast(base)) { // return schema; if (schema->has_interpolants()) { if (i + 1 < operands.size() && ( @@ -2663,7 +2700,7 @@ namespace Sass { || (ops[0].operand == Sass_OP::GTE) )) { Expression_Obj rhs = fold_operands(operands[i], operands, ops, i + 1); - rhs = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[0], schema, &rhs); + rhs = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[0], schema, rhs); return rhs; } // return schema; @@ -2671,31 +2708,32 @@ namespace Sass { } for (size_t S = operands.size(); i < S; ++i) { - if (String_Schema_Ptr schema = dynamic_cast(&operands[i])) { + if (String_Schema_Ptr schema = Cast(operands[i])) { if (schema->has_interpolants()) { if (i + 1 < S) { + // this whole branch is never hit via spec tests Expression_Obj rhs = fold_operands(operands[i+1], operands, ops, i + 2); - rhs = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], schema, &rhs); - base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], &base, &rhs); + rhs = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], schema, rhs); + base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], base, rhs); return base; } - base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], &base, operands[i]); + base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], base, operands[i]); return base; } else { - base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], &base, operands[i]); + base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], base, operands[i]); } } else { - base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], &base, operands[i]); + base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], base, operands[i]); } - Binary_Expression_Ptr b = static_cast(&base); + Binary_Expression_Ptr b = Cast(base.ptr()); if (b && ops[i].operand == Sass_OP::DIV && b->left()->is_delayed() && b->right()->is_delayed()) { base->is_delayed(true); } } // nested binary expression are never to be delayed - if (Binary_Expression_Ptr b = dynamic_cast(&base)) { - if (SASS_MEMORY_CAST(Binary_Expression, b->left())) base->set_delayed(false); - if (SASS_MEMORY_CAST(Binary_Expression, b->right())) base->set_delayed(false); + if (Binary_Expression_Ptr b = Cast(base)) { + if (Cast(b->left())) base->set_delayed(false); + if (Cast(b->right())) base->set_delayed(false); } return base; } @@ -2727,8 +2765,8 @@ namespace Sass { const char* pos_left(last_pos); const char* end_left(last_pos); - utf8::next(pos_left, end); - utf8::next(end_left, end); + if (*pos_left) utf8::next(pos_left, end); + if (*end_left) utf8::next(end_left, end); while (pos_left > source) { if (utf8::distance(pos_left, end_left) >= max_len) { utf8::prior(pos_left, source); diff --git a/src/libsass/src/parser.hpp b/src/libsass/src/parser.hpp index f4be97826..263b4e1e2 100755 --- a/src/libsass/src/parser.hpp +++ b/src/libsass/src/parser.hpp @@ -39,12 +39,11 @@ namespace Sass { Token lexed; - bool in_at_root; Parser(Context& ctx, const ParserState& pstate) : ParserState(pstate), ctx(ctx), block_stack(), stack(0), last_media_block(), source(0), position(0), end(0), before_token(pstate), after_token(pstate), pstate(pstate), indentation(0) - { in_at_root = false; stack.push_back(Scope::Root); } + { stack.push_back(Scope::Root); } // static Parser from_string(const std::string& src, Context& ctx, ParserState pstate = ParserState("[STRING]")); static Parser from_c_str(const char* src, Context& ctx, ParserState pstate = ParserState("[CSTRING]"), const char* source = 0); @@ -240,10 +239,10 @@ namespace Sass { Arguments_Obj parse_arguments(); Argument_Obj parse_argument(); Assignment_Obj parse_assignment(); - Ruleset_Obj parse_ruleset(Lookahead lookahead, bool is_root = false); - Selector_Schema_Obj parse_selector_schema(const char* end_of_selector); - Selector_List_Obj parse_selector_list(bool at_root = false); - Complex_Selector_Obj parse_complex_selector(bool in_root = true); + Ruleset_Obj parse_ruleset(Lookahead lookahead); + Selector_List_Obj parse_selector_list(bool chroot); + Complex_Selector_Obj parse_complex_selector(bool chroot); + Selector_Schema_Obj parse_selector_schema(const char* end_of_selector, bool chroot); Compound_Selector_Obj parse_compound_selector(); Simple_Selector_Obj parse_simple_selector(); Wrapped_Selector_Obj parse_negated_selector(); @@ -257,6 +256,7 @@ namespace Sass { bool parse_number_prefix(); Declaration_Obj parse_declaration(); Expression_Obj parse_map(); + Expression_Obj parse_bracket_list(); Expression_Obj parse_list(bool delayed = false); Expression_Obj parse_comma_list(bool delayed = false); Expression_Obj parse_space_list(); @@ -340,15 +340,15 @@ namespace Sass { schema->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed)); if (position[0] == '#' && position[1] == '{') { Expression_Obj itpl = lex_interpolation(); - if (&itpl) schema->append(&itpl); + if (!itpl.isNull()) schema->append(itpl); while (lex < close >(false)) { // std::cerr << "LEX [[" << std::string(lexed) << "]]\n"; schema->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed)); if (position[0] == '#' && position[1] == '{') { Expression_Obj itpl = lex_interpolation(); - if (&itpl) schema->append(&itpl); + if (!itpl.isNull()) schema->append(itpl); } else { - return &schema; + return schema; } } } else { diff --git a/src/libsass/src/plugins.cpp b/src/libsass/src/plugins.cpp index bdd61a905..eecba7880 100755 --- a/src/libsass/src/plugins.cpp +++ b/src/libsass/src/plugins.cpp @@ -1,3 +1,8 @@ +#include "sass.hpp" +#include +#include "output.hpp" +#include "plugins.hpp" + #ifdef _WIN32 #include #else @@ -7,15 +12,21 @@ #include #endif -#include "sass.hpp" -#include -#include "output.hpp" -#include "plugins.hpp" - namespace Sass { Plugins::Plugins(void) { } - Plugins::~Plugins(void) { } + Plugins::~Plugins(void) + { + for (auto function : functions) { + sass_delete_function(function); + } + for (auto importer : importers) { + sass_delete_importer(importer); + } + for (auto header : headers) { + sass_delete_importer(header); + } + } // check if plugin is compatible with this version // plugins may be linked static against libsass @@ -57,20 +68,23 @@ namespace Sass { // try to get import address for "libsass_load_functions" if (LOAD_LIB_FN(__plugin_load_fns__, plugin_load_functions, "libsass_load_functions")) { - Sass_Function_List fns = plugin_load_functions(); + Sass_Function_List fns = plugin_load_functions(), _p = fns; while (fns && *fns) { functions.push_back(*fns); ++ fns; } + sass_free_memory(_p); // only delete the container, items not yet } // try to get import address for "libsass_load_importers" if (LOAD_LIB_FN(__plugin_load_imps__, plugin_load_importers, "libsass_load_importers")) { - Sass_Importer_List imps = plugin_load_importers(); + Sass_Importer_List imps = plugin_load_importers(), _p = imps; while (imps && *imps) { importers.push_back(*imps); ++ imps; } + sass_free_memory(_p); // only delete the container, items not yet } // try to get import address for "libsass_load_headers" if (LOAD_LIB_FN(__plugin_load_imps__, plugin_load_headers, "libsass_load_headers")) { - Sass_Importer_List imps = plugin_load_headers(); + Sass_Importer_List imps = plugin_load_headers(), _p = imps; while (imps && *imps) { headers.push_back(*imps); ++ imps; } + sass_free_memory(_p); // only delete the container, items not yet } // success return true; @@ -153,7 +167,11 @@ namespace Sass { struct dirent *dirp; if((dp = opendir(path.c_str())) == NULL) return -1; while ((dirp = readdir(dp)) != NULL) { - if (!ends_with(dirp->d_name, ".so")) continue; + #if __APPLE__ + if (!ends_with(dirp->d_name, ".dylib")) continue; + #else + if (!ends_with(dirp->d_name, ".so")) continue; + #endif if (load_plugin(path + dirp->d_name)) ++ loaded; } closedir(dp); diff --git a/src/libsass/src/position.hpp b/src/libsass/src/position.hpp index e4306d5a8..1aeb5d15a 100755 --- a/src/libsass/src/position.hpp +++ b/src/libsass/src/position.hpp @@ -85,7 +85,7 @@ namespace Sass { size_t length() const { return end - begin; } std::string ws_before() const { return std::string(prefix, begin); } - std::string to_string() const { return std::string(begin, end); } + const std::string to_string() const { return std::string(begin, end); } std::string time_wspace() const { std::string str(to_string()); std::string whitespaces(" \t\f\v\n\r"); diff --git a/src/libsass/src/prelexer.cpp b/src/libsass/src/prelexer.cpp index cab812bba..f702513aa 100755 --- a/src/libsass/src/prelexer.cpp +++ b/src/libsass/src/prelexer.cpp @@ -1,6 +1,5 @@ #include "sass.hpp" #include -#include #include #include #include "util.hpp" @@ -1420,6 +1419,28 @@ namespace Sass { >(src); } + const char* list_terminator(const char* src) { + return alternatives < + exactly<';'>, + exactly<'}'>, + exactly<'{'>, + exactly<')'>, + exactly<']'>, + exactly<':'>, + end_of_file, + exactly, + default_flag, + global_flag + >(src); + }; + + const char* space_list_terminator(const char* src) { + return alternatives < + exactly<','>, + list_terminator + >(src); + }; + // const char* real_uri_prefix(const char* src) { // return alternatives< diff --git a/src/libsass/src/prelexer.hpp b/src/libsass/src/prelexer.hpp index 69c404323..7cac454a1 100755 --- a/src/libsass/src/prelexer.hpp +++ b/src/libsass/src/prelexer.hpp @@ -355,6 +355,10 @@ namespace Sass { const char* ie_keyword_arg_value(const char* src); const char* ie_keyword_arg_property(const char* src); + // characters that terminate parsing of a list + const char* list_terminator(const char* src); + const char* space_list_terminator(const char* src); + // match url() const char* H(const char* src); const char* W(const char* src); diff --git a/src/libsass/src/remove_placeholders.cpp b/src/libsass/src/remove_placeholders.cpp index 0fce4ed7e..7402a9251 100755 --- a/src/libsass/src/remove_placeholders.cpp +++ b/src/libsass/src/remove_placeholders.cpp @@ -6,13 +6,12 @@ namespace Sass { - Remove_Placeholders::Remove_Placeholders(Context& ctx) - : ctx(ctx) + Remove_Placeholders::Remove_Placeholders() { } void Remove_Placeholders::operator()(Block_Ptr b) { for (size_t i = 0, L = b->length(); i < L; ++i) { - Statement_Ptr st = &b->at(i); + Statement_Ptr st = b->at(i); st->perform(this); } } @@ -34,18 +33,18 @@ namespace Sass { void Remove_Placeholders::operator()(Ruleset_Ptr r) { // Create a new selector group without placeholders - Selector_List_Obj sl = SASS_MEMORY_CAST(Selector_List, r->selector()); + Selector_List_Obj sl = Cast(r->selector()); if (sl) { // Set the new placeholder selector list - r->selector(remove_placeholders(&sl)); + r->selector(remove_placeholders(sl)); // Remove placeholders in wrapped selectors for (Complex_Selector_Obj cs : sl->elements()) { while (cs) { if (cs->head()) { for (Simple_Selector_Obj& ss : cs->head()->elements()) { - if (Wrapped_Selector_Ptr ws = SASS_MEMORY_CAST(Wrapped_Selector, ss)) { - if (Selector_List_Ptr sl = SASS_MEMORY_CAST(Selector_List, ws->selector())) { + if (Wrapped_Selector_Ptr ws = Cast(ss)) { + if (Selector_List_Ptr sl = Cast(ws->selector())) { Selector_List_Ptr clean = remove_placeholders(sl); // also clean superflous parent selectors // probably not really the correct place @@ -72,10 +71,10 @@ namespace Sass { } void Remove_Placeholders::operator()(Media_Block_Ptr m) { - operator()(&m->block()); + operator()(m->block()); } void Remove_Placeholders::operator()(Supports_Block_Ptr m) { - operator()(&m->block()); + operator()(m->block()); } void Remove_Placeholders::operator()(Directive_Ptr a) { diff --git a/src/libsass/src/remove_placeholders.hpp b/src/libsass/src/remove_placeholders.hpp index a3f81dffc..c13b63134 100755 --- a/src/libsass/src/remove_placeholders.hpp +++ b/src/libsass/src/remove_placeholders.hpp @@ -9,19 +9,15 @@ namespace Sass { - class Context; - class Remove_Placeholders : public Operation_CRTP { - Context& ctx; - void fallback_impl(AST_Node_Ptr n) {} public: Selector_List_Ptr remove_placeholders(Selector_List_Ptr); public: - Remove_Placeholders(Context&); + Remove_Placeholders(); ~Remove_Placeholders() { } void operator()(Block_Ptr); diff --git a/src/libsass/src/sass.cpp b/src/libsass/src/sass.cpp index 3f6af2703..98e349f48 100755 --- a/src/libsass/src/sass.cpp +++ b/src/libsass/src/sass.cpp @@ -7,6 +7,23 @@ #include "sass.h" #include "file.hpp" #include "util.hpp" +#include "sass_context.hpp" +#include "sass_functions.hpp" + +namespace Sass { + + // helper to convert string list to vector + std::vector list2vec(struct string_list* cur) + { + std::vector list; + while (cur) { + list.push_back(cur->string); + cur = cur->next; + } + return list; + } + +} extern "C" { using namespace Sass; @@ -49,11 +66,50 @@ extern "C" { return sass_copy_c_string(unquoted.c_str()); } + char* ADDCALL sass_compiler_find_include (const char* file, struct Sass_Compiler* compiler) + { + // get the last import entry to get current base directory + Sass_Import_Entry import = sass_compiler_get_last_import(compiler); + const std::vector& incs = compiler->cpp_ctx->include_paths; + // create the vector with paths to lookup + std::vector paths(1 + incs.size()); + paths.push_back(File::dir_name(import->abs_path)); + paths.insert( paths.end(), incs.begin(), incs.end() ); + // now resolve the file path relative to lookup paths + std::string resolved(File::find_include(file, paths)); + return sass_copy_c_string(resolved.c_str()); + } + + char* ADDCALL sass_compiler_find_file (const char* file, struct Sass_Compiler* compiler) + { + // get the last import entry to get current base directory + Sass_Import_Entry import = sass_compiler_get_last_import(compiler); + const std::vector& incs = compiler->cpp_ctx->include_paths; + // create the vector with paths to lookup + std::vector paths(1 + incs.size()); + paths.push_back(File::dir_name(import->abs_path)); + paths.insert( paths.end(), incs.begin(), incs.end() ); + // now resolve the file path relative to lookup paths + std::string resolved(File::find_file(file, paths)); + return sass_copy_c_string(resolved.c_str()); + } + // Make sure to free the returned value! // Incs array has to be null terminated! - char* ADDCALL sass_resolve_file (const char* file, const char* paths[]) + // this has the original resolve logic for sass include + char* ADDCALL sass_find_include (const char* file, struct Sass_Options* opt) { - std::string resolved(File::find_file(file, paths)); + std::vector vec(list2vec(opt->include_paths)); + std::string resolved(File::find_include(file, vec)); + return sass_copy_c_string(resolved.c_str()); + } + + // Make sure to free the returned value! + // Incs array has to be null terminated! + char* ADDCALL sass_find_file (const char* file, struct Sass_Options* opt) + { + std::vector vec(list2vec(opt->include_paths)); + std::string resolved(File::find_file(file, vec)); return sass_copy_c_string(resolved.c_str()); } diff --git a/src/libsass/src/sass_context.cpp b/src/libsass/src/sass_context.cpp index 8cf7e2cf7..82dc2152f 100755 --- a/src/libsass/src/sass_context.cpp +++ b/src/libsass/src/sass_context.cpp @@ -272,10 +272,14 @@ extern "C" { #define IMPLEMENT_SASS_OPTION_ACCESSOR(type, option) \ type ADDCALL sass_option_get_##option (struct Sass_Options* options) { return options->option; } \ void ADDCALL sass_option_set_##option (struct Sass_Options* options, type option) { options->option = option; } - #define IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(type, option, def) \ - type ADDCALL sass_option_get_##option (struct Sass_Options* options) { return safe_str(options->option, def); } \ + #define IMPLEMENT_SASS_OPTION_STRING_GETTER(type, option, def) \ + type ADDCALL sass_option_get_##option (struct Sass_Options* options) { return safe_str(options->option, def); } + #define IMPLEMENT_SASS_OPTION_STRING_SETTER(type, option, def) \ void ADDCALL sass_option_set_##option (struct Sass_Options* options, type option) \ { free(options->option); options->option = option || def ? sass_copy_c_string(option ? option : def) : 0; } + #define IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(type, option, def) \ + IMPLEMENT_SASS_OPTION_STRING_GETTER(type, option, def) \ + IMPLEMENT_SASS_OPTION_STRING_SETTER(type, option, def) #define IMPLEMENT_SASS_CONTEXT_GETTER(type, option) \ type ADDCALL sass_context_get_##option (struct Sass_Context* ctx) { return ctx->option; } @@ -468,7 +472,7 @@ extern "C" { if (compiler->c_ctx->error_status) return compiler->c_ctx->error_status; // parse the context we have set up (file or data) - compiler->root = &sass_parse_block(compiler); + compiler->root = sass_parse_block(compiler); // success return 0; } @@ -674,6 +678,10 @@ extern "C" { size_t ADDCALL sass_compiler_get_import_stack_size(struct Sass_Compiler* compiler) { return compiler->cpp_ctx->import_stack.size(); } Sass_Import_Entry ADDCALL sass_compiler_get_last_import(struct Sass_Compiler* compiler) { return compiler->cpp_ctx->import_stack.back(); } Sass_Import_Entry ADDCALL sass_compiler_get_import_entry(struct Sass_Compiler* compiler, size_t idx) { return compiler->cpp_ctx->import_stack[idx]; } + // Getters for Sass_Compiler options (query function stack) + size_t ADDCALL sass_compiler_get_callee_stack_size(struct Sass_Compiler* compiler) { return compiler->cpp_ctx->callee_stack.size(); } + Sass_Callee_Entry ADDCALL sass_compiler_get_last_callee(struct Sass_Compiler* compiler) { return &compiler->cpp_ctx->callee_stack.back(); } + Sass_Callee_Entry ADDCALL sass_compiler_get_callee_entry(struct Sass_Compiler* compiler, size_t idx) { return &compiler->cpp_ctx->callee_stack[idx]; } // Calculate the size of the stored null terminated array size_t ADDCALL sass_context_get_included_files_size (struct Sass_Context* ctx) @@ -693,10 +701,10 @@ extern "C" { IMPLEMENT_SASS_OPTION_ACCESSOR(Sass_Importer_List, c_headers); IMPLEMENT_SASS_OPTION_ACCESSOR(const char*, indent); IMPLEMENT_SASS_OPTION_ACCESSOR(const char*, linefeed); + IMPLEMENT_SASS_OPTION_STRING_SETTER(const char*, plugin_path, 0); + IMPLEMENT_SASS_OPTION_STRING_SETTER(const char*, include_path, 0); IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, input_path, 0); IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, output_path, 0); - IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, plugin_path, 0); - IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, include_path, 0); IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, source_map_file, 0); IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, source_map_root, 0); @@ -740,6 +748,23 @@ extern "C" { } + // Push function for include paths (no manipulation support for now) + size_t ADDCALL sass_option_get_include_path_size(struct Sass_Options* options) + { + size_t len = 0; + struct string_list* cur = options->include_paths; + while (cur) { len ++; cur = cur->next; } + return len; + } + + // Push function for include paths (no manipulation support for now) + const char* ADDCALL sass_option_get_include_path(struct Sass_Options* options, size_t i) + { + struct string_list* cur = options->include_paths; + while (i) { i--; cur = cur->next; } + return cur->string; + } + // Push function for plugin paths (no manipulation support for now) void ADDCALL sass_option_push_plugin_path(struct Sass_Options* options, const char* path) { diff --git a/src/libsass/src/sass_context.hpp b/src/libsass/src/sass_context.hpp index 3a78d3ad8..8ae1fb12c 100755 --- a/src/libsass/src/sass_context.hpp +++ b/src/libsass/src/sass_context.hpp @@ -1,9 +1,8 @@ #ifndef SASS_SASS_CONTEXT_H #define SASS_SASS_CONTEXT_H -#include "sass.h" -#include "sass.hpp" -#include "context.hpp" +#include "sass/base.h" +#include "sass/context.h" #include "ast_fwd_decl.hpp" // sass config options structure @@ -33,7 +32,7 @@ struct Sass_Options : Sass_Output_Options { char* input_path; // The output path is used for source map - // generation. Libsass will not write to + // generation. LibSass will not write to // this file, it is just used to create // information in source-maps etc. char* output_path; diff --git a/src/libsass/src/sass_functions.cpp b/src/libsass/src/sass_functions.cpp index db153d603..f7beda35f 100755 --- a/src/libsass/src/sass_functions.cpp +++ b/src/libsass/src/sass_functions.cpp @@ -2,6 +2,7 @@ #include #include "util.hpp" #include "context.hpp" +#include "values.hpp" #include "sass/functions.h" #include "sass_functions.hpp" @@ -17,12 +18,30 @@ extern "C" { { Sass_Function_Entry cb = (Sass_Function_Entry) calloc(1, sizeof(Sass_Function)); if (cb == 0) return 0; - cb->signature = signature; + cb->signature = strdup(signature); cb->function = function; cb->cookie = cookie; return cb; } + void ADDCALL sass_delete_function(Sass_Function_Entry entry) + { + free(entry->signature); + free(entry); + } + + // Deallocator for the allocated memory + void ADDCALL sass_delete_function_list(Sass_Function_List list) + { + Sass_Function_List it = list; + if (list == 0) return; + while(*list) { + sass_delete_function(*list); + ++list; + } + free(it); + } + // Setters and getters for callbacks on function lists Sass_Function_Entry ADDCALL sass_function_get_list_entry(Sass_Function_List list, size_t pos) { return list[pos]; } void sass_function_set_list_entry(Sass_Function_List list, size_t pos, Sass_Function_Entry cb) { list[pos] = cb; } @@ -57,6 +76,18 @@ extern "C" { return (Sass_Importer_List) calloc(length + 1, sizeof(Sass_Importer_Entry)); } + // Deallocator for the allocated memory + void ADDCALL sass_delete_importer_list(Sass_Importer_List list) + { + Sass_Importer_List it = list; + if (list == 0) return; + while(*list) { + sass_delete_importer(*list); + ++list; + } + free(it); + } + Sass_Importer_Entry ADDCALL sass_importer_get_list_entry(Sass_Importer_List list, size_t idx) { return list[idx]; } void ADDCALL sass_importer_set_list_entry(Sass_Importer_List list, size_t idx, Sass_Importer_Entry cb) { list[idx] = cb; } @@ -126,6 +157,37 @@ extern "C" { free(import); } + // Getter for callee entry + const char* ADDCALL sass_callee_get_name(Sass_Callee_Entry entry) { return entry->name; } + const char* ADDCALL sass_callee_get_path(Sass_Callee_Entry entry) { return entry->path; } + size_t ADDCALL sass_callee_get_line(Sass_Callee_Entry entry) { return entry->line; } + size_t ADDCALL sass_callee_get_column(Sass_Callee_Entry entry) { return entry->column; } + enum Sass_Callee_Type ADDCALL sass_callee_get_type(Sass_Callee_Entry entry) { return entry->type; } + Sass_Env_Frame ADDCALL sass_callee_get_env (Sass_Callee_Entry entry) { return &entry->env; } + + // Getters and Setters for environments (lexical, local and global) + union Sass_Value* ADDCALL sass_env_get_lexical (Sass_Env_Frame env, const char* name) { + Expression_Ptr ex = Cast((*env->frame)[name]); + return ex != NULL ? ast_node_to_sass_value(ex) : NULL; + } + void ADDCALL sass_env_set_lexical (Sass_Env_Frame env, const char* name, union Sass_Value* val) { + (*env->frame)[name] = sass_value_to_ast_node(val); + } + union Sass_Value* ADDCALL sass_env_get_local (Sass_Env_Frame env, const char* name) { + Expression_Ptr ex = Cast(env->frame->get_local(name)); + return ex != NULL ? ast_node_to_sass_value(ex) : NULL; + } + void ADDCALL sass_env_set_local (Sass_Env_Frame env, const char* name, union Sass_Value* val) { + env->frame->set_local(name, sass_value_to_ast_node(val)); + } + union Sass_Value* ADDCALL sass_env_get_global (Sass_Env_Frame env, const char* name) { + Expression_Ptr ex = Cast(env->frame->get_global(name)); + return ex != NULL ? ast_node_to_sass_value(ex) : NULL; + } + void ADDCALL sass_env_set_global (Sass_Env_Frame env, const char* name, union Sass_Value* val) { + env->frame->set_global(name, sass_value_to_ast_node(val)); + } + // Getter for import entry const char* ADDCALL sass_import_get_imp_path(Sass_Import_Entry entry) { return entry->imp_path; } const char* ADDCALL sass_import_get_abs_path(Sass_Import_Entry entry) { return entry->abs_path; } diff --git a/src/libsass/src/sass_functions.hpp b/src/libsass/src/sass_functions.hpp index 5a7865d77..3b646d67e 100755 --- a/src/libsass/src/sass_functions.hpp +++ b/src/libsass/src/sass_functions.hpp @@ -2,10 +2,12 @@ #define SASS_SASS_FUNCTIONS_H #include "sass.h" +#include "environment.hpp" +#include "functions.hpp" // Struct to hold custom function callback struct Sass_Function { - const char* signature; + char* signature; Sass_Function_Fn function; void* cookie; }; @@ -22,6 +24,22 @@ struct Sass_Import { size_t column; }; +// External environments +struct Sass_Env { + // links to parent frames + Sass::Env* frame; +}; + +// External call entry +struct Sass_Callee { + const char* name; + const char* path; + size_t line; + size_t column; + enum Sass_Callee_Type type; + struct Sass_Env env; +}; + // Struct to hold importer callback struct Sass_Importer { Sass_Importer_Fn importer; diff --git a/src/libsass/src/sass_util.hpp b/src/libsass/src/sass_util.hpp index ca2819aaa..ef72dff27 100755 --- a/src/libsass/src/sass_util.hpp +++ b/src/libsass/src/sass_util.hpp @@ -40,7 +40,7 @@ namespace Sass { bool operator()(const Node& one, const Node& two, Node& out) const { // TODO: Is this the correct C++ interpretation? // block ||= proc {|a, b| a == b && a} - if (nodesEqual(one, two, true)) { + if (one == two) { out = one; return true; } diff --git a/src/libsass/src/sass_values.cpp b/src/libsass/src/sass_values.cpp index efdd8dd62..adf41d573 100755 --- a/src/libsass/src/sass_values.cpp +++ b/src/libsass/src/sass_values.cpp @@ -54,6 +54,8 @@ extern "C" { size_t ADDCALL sass_list_get_length(const union Sass_Value* v) { return v->list.length; } enum Sass_Separator ADDCALL sass_list_get_separator(const union Sass_Value* v) { return v->list.separator; } void ADDCALL sass_list_set_separator(union Sass_Value* v, enum Sass_Separator separator) { v->list.separator = separator; } + bool ADDCALL sass_list_get_is_bracketed(const union Sass_Value* v) { return v->list.is_bracketed; } + void ADDCALL sass_list_set_is_bracketed(union Sass_Value* v, bool is_bracketed) { v->list.is_bracketed = is_bracketed; } // Getters and setters for Sass_List values union Sass_Value* ADDCALL sass_list_get_value(const union Sass_Value* v, size_t i) { return v->list.values[i]; } void ADDCALL sass_list_set_value(union Sass_Value* v, size_t i, union Sass_Value* value) { v->list.values[i] = value; } @@ -130,13 +132,14 @@ extern "C" { return v; } - union Sass_Value* ADDCALL sass_make_list(size_t len, enum Sass_Separator sep) + union Sass_Value* ADDCALL sass_make_list(size_t len, enum Sass_Separator sep, bool is_bracketed) { union Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value)); if (v == 0) return 0; v->list.tag = SASS_LIST; v->list.length = len; v->list.separator = sep; + v->list.is_bracketed = is_bracketed; v->list.values = (union Sass_Value**) calloc(len, sizeof(union Sass_Value*)); if (v->list.values == 0) { free(v); return 0; } return v; @@ -247,7 +250,7 @@ extern "C" { 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); + union Sass_Value* list = sass_make_list(val->list.length, val->list.separator, val->list.is_bracketed); for (i = 0; i < list->list.length; i++) { list->list.values[i] = sass_clone_value(val->list.values[i]); } @@ -294,40 +297,40 @@ extern "C" { // see if it's a relational expression switch(op) { - case Sass_OP::EQ: return sass_make_boolean(Eval::eq(&lhs, &rhs)); - case Sass_OP::NEQ: return sass_make_boolean(!Eval::eq(&lhs, &rhs)); - case Sass_OP::GT: return sass_make_boolean(!Eval::lt(&lhs, &rhs, "gt") && !Eval::eq(&lhs, &rhs)); - case Sass_OP::GTE: return sass_make_boolean(!Eval::lt(&lhs, &rhs, "gte")); - case Sass_OP::LT: return sass_make_boolean(Eval::lt(&lhs, &rhs, "lt")); - case Sass_OP::LTE: return sass_make_boolean(Eval::lt(&lhs, &rhs, "lte") || Eval::eq(&lhs, &rhs)); - case Sass_OP::AND: return ast_node_to_sass_value(lhs->is_false() ? &lhs : &rhs); - case Sass_OP::OR: return ast_node_to_sass_value(lhs->is_false() ? &rhs : &lhs); + case Sass_OP::EQ: return sass_make_boolean(Eval::eq(lhs, rhs)); + case Sass_OP::NEQ: return sass_make_boolean(!Eval::eq(lhs, rhs)); + case Sass_OP::GT: return sass_make_boolean(!Eval::lt(lhs, rhs, "gt") && !Eval::eq(lhs, rhs)); + case Sass_OP::GTE: return sass_make_boolean(!Eval::lt(lhs, rhs, "gte")); + case Sass_OP::LT: return sass_make_boolean(Eval::lt(lhs, rhs, "lt")); + case Sass_OP::LTE: return sass_make_boolean(Eval::lt(lhs, rhs, "lte") || Eval::eq(lhs, rhs)); + case Sass_OP::AND: return ast_node_to_sass_value(lhs->is_false() ? lhs : rhs); + case Sass_OP::OR: return ast_node_to_sass_value(lhs->is_false() ? rhs : lhs); default: break; } if (sass_value_is_number(a) && sass_value_is_number(b)) { - Number_Ptr_Const l_n = SASS_MEMORY_CAST(Number, lhs); - Number_Ptr_Const r_n = SASS_MEMORY_CAST(Number, rhs); + Number_Ptr_Const l_n = Cast(lhs); + Number_Ptr_Const r_n = Cast(rhs); rv = Eval::op_numbers(op, *l_n, *r_n, options); } else if (sass_value_is_number(a) && sass_value_is_color(a)) { - Number_Ptr_Const l_n = SASS_MEMORY_CAST(Number, lhs); - Color_Ptr_Const r_c = SASS_MEMORY_CAST(Color, rhs); + Number_Ptr_Const l_n = Cast(lhs); + Color_Ptr_Const r_c = Cast(rhs); rv = Eval::op_number_color(op, *l_n, *r_c, options); } else if (sass_value_is_color(a) && sass_value_is_number(b)) { - Color_Ptr_Const l_c = SASS_MEMORY_CAST(Color, lhs); - Number_Ptr_Const r_n = SASS_MEMORY_CAST(Number, rhs); + Color_Ptr_Const l_c = Cast(lhs); + Number_Ptr_Const r_n = Cast(rhs); rv = Eval::op_color_number(op, *l_c, *r_n, options); } else if (sass_value_is_color(a) && sass_value_is_color(b)) { - Color_Ptr_Const l_c = SASS_MEMORY_CAST(Color, lhs); - Color_Ptr_Const r_c = SASS_MEMORY_CAST(Color, rhs); + Color_Ptr_Const l_c = Cast(lhs); + Color_Ptr_Const r_c = Cast(rhs); rv = Eval::op_colors(op, *l_c, *r_c, options); } else /* convert other stuff to string and apply operation */ { - Value_Ptr l_v = SASS_MEMORY_CAST(Value, lhs); - Value_Ptr r_v = SASS_MEMORY_CAST(Value, rhs); + Value_Ptr l_v = Cast(lhs); + Value_Ptr r_v = Cast(rhs); rv = Eval::op_strings(op, *l_v, *r_v, options); } diff --git a/src/libsass/src/sass_values.hpp b/src/libsass/src/sass_values.hpp index b9e9ebfcc..9aa5cdb33 100755 --- a/src/libsass/src/sass_values.hpp +++ b/src/libsass/src/sass_values.hpp @@ -35,6 +35,7 @@ struct Sass_String { struct Sass_List { enum Sass_Tag tag; enum Sass_Separator separator; + bool is_bracketed; size_t length; // null terminated "array" union Sass_Value** values; @@ -78,4 +79,4 @@ struct Sass_MapPair { union Sass_Value* value; }; -#endif \ No newline at end of file +#endif diff --git a/src/libsass/src/source_map.cpp b/src/libsass/src/source_map.cpp index 0f496f6fb..0e408b65d 100755 --- a/src/libsass/src/source_map.cpp +++ b/src/libsass/src/source_map.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #include "ast.hpp" diff --git a/src/libsass/src/subset_map.cpp b/src/libsass/src/subset_map.cpp index 766073df8..24513e498 100755 --- a/src/libsass/src/subset_map.cpp +++ b/src/libsass/src/subset_map.cpp @@ -4,22 +4,20 @@ namespace Sass { - void Subset_Map::put(const Compound_Selector_Obj& sel, const Subset_Map_Val& value) + void Subset_Map::put(const Compound_Selector_Obj& sel, const SubSetMapPair& value) { if (sel->empty()) throw std::runtime_error("internal error: subset map keys may not be empty"); size_t index = values_.size(); values_.push_back(value); for (size_t i = 0, S = sel->length(); i < S; ++i) { - hash_[(*sel)[i]].push_back(std::make_pair(&sel, index)); + hash_[(*sel)[i]].push_back(std::make_pair(sel, index)); } } - std::vector Subset_Map::get_kv(const Compound_Selector_Obj& sel) + std::vector Subset_Map::get_kv(const Compound_Selector_Obj& sel) { - // std::vector s = sel->to_str_vec(); - // std::set dict(s.begin(), s.end()); - std::unordered_set dict(sel->begin(), sel->end()); + SimpleSelectorDict dict(sel->begin(), sel->end()); // XXX Set std::vector indices; for (size_t i = 0, S = sel->length(); i < S; ++i) { if (!hash_.count((*sel)[i])) { @@ -42,14 +40,14 @@ namespace Sass { std::vector::iterator indices_end = unique(indices.begin(), indices.end()); indices.resize(distance(indices.begin(), indices_end)); - std::vector results; + std::vector results; for (size_t i = 0, S = indices.size(); i < S; ++i) { results.push_back(values_[indices[i]]); } return results; } - std::vector Subset_Map::get_v(const Compound_Selector_Obj& sel) + std::vector Subset_Map::get_v(const Compound_Selector_Obj& sel) { return get_kv(sel); } diff --git a/src/libsass/src/subset_map.hpp b/src/libsass/src/subset_map.hpp index 58916bccf..5c091e685 100755 --- a/src/libsass/src/subset_map.hpp +++ b/src/libsass/src/subset_map.hpp @@ -60,15 +60,15 @@ namespace Sass { class Subset_Map { private: - std::vector values_; - std::map > > hash_; + std::vector values_; + std::map >, OrderNodes > hash_; public: - void put(const Compound_Selector_Obj& sel, const Subset_Map_Val& value); - std::vector get_kv(const Compound_Selector_Obj& s); - std::vector get_v(const Compound_Selector_Obj& s); + void put(const Compound_Selector_Obj& sel, const SubSetMapPair& value); + std::vector get_kv(const Compound_Selector_Obj& s); + std::vector get_v(const Compound_Selector_Obj& s); bool empty() { return values_.empty(); } void clear() { values_.clear(); hash_.clear(); } - const std::vector values(void) { return values_; } + const std::vector values(void) { return values_; } }; } diff --git a/src/libsass/src/to_c.cpp b/src/libsass/src/to_c.cpp index a39e3e76a..8a6ea8d51 100755 --- a/src/libsass/src/to_c.cpp +++ b/src/libsass/src/to_c.cpp @@ -36,7 +36,7 @@ namespace Sass { union Sass_Value* To_C::operator()(List_Ptr l) { - union Sass_Value* v = sass_make_list(l->length(), l->separator()); + union Sass_Value* v = sass_make_list(l->length(), l->separator(), l->is_bracketed()); for (size_t i = 0, L = l->length(); i < L; ++i) { sass_list_set_value(v, i, (*l)[i]->perform(this)); } @@ -57,7 +57,7 @@ namespace Sass { union Sass_Value* To_C::operator()(Arguments_Ptr a) { - union Sass_Value* v = sass_make_list(a->length(), SASS_COMMA); + union Sass_Value* v = sass_make_list(a->length(), SASS_COMMA, false); for (size_t i = 0, L = a->length(); i < L; ++i) { sass_list_set_value(v, i, (*a)[i]->perform(this)); } diff --git a/src/libsass/src/util.cpp b/src/libsass/src/util.cpp index 5e598131e..4b1636e1c 100755 --- a/src/libsass/src/util.cpp +++ b/src/libsass/src/util.cpp @@ -445,7 +445,7 @@ namespace Sass { Block_Obj b = r->block(); - Selector_List_Ptr sl = SASS_MEMORY_CAST(Selector_List, r->selector()); + Selector_List_Ptr sl = Cast(r->selector()); bool hasSelectors = sl ? sl->length() > 0 : false; if (!hasSelectors) { @@ -456,16 +456,16 @@ namespace Sass { bool hasPrintableChildBlocks = false; for (size_t i = 0, L = b->length(); i < L; ++i) { Statement_Obj stm = b->at(i); - if (dynamic_cast(&stm)) { + if (Cast(stm)) { return true; - } else if (Declaration_Ptr d = dynamic_cast(&stm)) { + } else if (Declaration_Ptr d = Cast(stm)) { return isPrintable(d, style); - } else if (dynamic_cast(&stm)) { - Block_Obj pChildBlock = ((Has_Block_Ptr)&stm)->block(); - if (isPrintable(&pChildBlock, style)) { + } else if (Has_Block_Ptr p = Cast(stm)) { + Block_Obj pChildBlock = p->block(); + if (isPrintable(pChildBlock, style)) { hasPrintableChildBlocks = true; } - } else if (Comment_Ptr c = dynamic_cast(&stm)) { + } else if (Comment_Ptr c = Cast(stm)) { // keep for uncompressed if (style != COMPRESSED) { hasDeclarations = true; @@ -499,8 +499,8 @@ namespace Sass { bool isPrintable(Declaration_Ptr d, Sass_Output_Style style) { Expression_Obj val = d->value(); - if (String_Quoted_Obj sq = SASS_MEMORY_CAST(String_Quoted, val)) return isPrintable(&sq, style); - if (String_Constant_Obj sc = SASS_MEMORY_CAST(String_Constant, val)) return isPrintable(&sc, style); + if (String_Quoted_Obj sq = Cast(val)) return isPrintable(sq.ptr(), style); + if (String_Constant_Obj sc = Cast(val)) return isPrintable(sc.ptr(), style); return true; } @@ -511,18 +511,16 @@ namespace Sass { Block_Obj b = f->block(); -// bool hasSelectors = f->selector() && static_cast(f->selector())->length() > 0; - bool hasDeclarations = false; bool hasPrintableChildBlocks = false; for (size_t i = 0, L = b->length(); i < L; ++i) { Statement_Obj stm = b->at(i); - if (dynamic_cast(&stm) || dynamic_cast(&stm)) { + if (Cast(stm) || Cast(stm)) { hasDeclarations = true; } - else if (dynamic_cast(&stm)) { - Block_Obj pChildBlock = ((Has_Block_Ptr)&stm)->block(); - if (isPrintable(&pChildBlock, style)) { + else if (Has_Block_Ptr b = Cast(stm)) { + Block_Obj pChildBlock = b->block(); + if (isPrintable(pChildBlock, style)) { hasPrintableChildBlocks = true; } } @@ -542,34 +540,32 @@ namespace Sass { if (b == 0) return false; for (size_t i = 0, L = b->length(); i < L; ++i) { Statement_Obj stm = b->at(i); - if (dynamic_cast(&stm)) return true; - else if (dynamic_cast(&stm)) return true; - else if (dynamic_cast(&stm)) { - Comment_Ptr c = (Comment_Ptr) &stm; + if (Cast(stm)) return true; + else if (Cast(stm)) return true; + else if (Comment_Ptr c = Cast(stm)) { if (isPrintable(c, style)) { return true; } } - else if (dynamic_cast(&stm)) { - Ruleset_Ptr r = (Ruleset_Ptr) &stm; + else if (Ruleset_Ptr r = Cast(stm)) { if (isPrintable(r, style)) { return true; } } - else if (dynamic_cast(&stm)) { - Supports_Block_Ptr f = (Supports_Block_Ptr) &stm; + else if (Supports_Block_Ptr f = Cast(stm)) { if (isPrintable(f, style)) { return true; } } - else if (dynamic_cast(&stm)) { - Media_Block_Ptr m = (Media_Block_Ptr) &stm; + else if (Media_Block_Ptr m = Cast(stm)) { if (isPrintable(m, style)) { return true; } } - else if (dynamic_cast(&stm) && isPrintable(((Has_Block_Ptr)&stm)->block(), style)) { - return true; + else if (Has_Block_Ptr b = Cast(stm)) { + if (isPrintable(b->block(), style)) { + return true; + } } } return false; @@ -596,35 +592,33 @@ namespace Sass { for (size_t i = 0, L = b->length(); i < L; ++i) { Statement_Obj stm = b->at(i); - if (dynamic_cast(&stm) || dynamic_cast(&stm)) { + if (Cast(stm) || Cast(stm)) { return true; } - else if (dynamic_cast(&stm)) { - Comment_Ptr c = (Comment_Ptr) &stm; + else if (Comment_Ptr c = Cast(stm)) { if (isPrintable(c, style)) { return true; } } - else if (dynamic_cast(&stm)) { - Ruleset_Ptr r = (Ruleset_Ptr) &stm; + else if (Ruleset_Ptr r = Cast(stm)) { if (isPrintable(r, style)) { return true; } } - else if (dynamic_cast(&stm)) { - Supports_Block_Ptr f = (Supports_Block_Ptr) &stm; + else if (Supports_Block_Ptr f = Cast(stm)) { if (isPrintable(f, style)) { return true; } } - else if (dynamic_cast(&stm)) { - Media_Block_Ptr m = (Media_Block_Ptr) &stm; + else if (Media_Block_Ptr m = Cast(stm)) { if (isPrintable(m, style)) { return true; } } - else if (dynamic_cast(&stm) && isPrintable(((Has_Block_Ptr)&stm)->block(), style)) { - return true; + else if (Has_Block_Ptr b = Cast(stm)) { + if (isPrintable(b->block(), style)) { + return true; + } } } diff --git a/src/libsass/src/values.cpp b/src/libsass/src/values.cpp index 4d16b614f..a8b165f79 100755 --- a/src/libsass/src/values.cpp +++ b/src/libsass/src/values.cpp @@ -11,32 +11,32 @@ namespace Sass { { if (val->concrete_type() == Expression::NUMBER) { - Number_Ptr_Const res = dynamic_cast(val); + Number_Ptr_Const res = Cast(val); return sass_make_number(res->value(), res->unit().c_str()); } else if (val->concrete_type() == Expression::COLOR) { - Color_Ptr_Const col = dynamic_cast(val); + Color_Ptr_Const col = Cast(val); return sass_make_color(col->r(), col->g(), col->b(), col->a()); } else if (val->concrete_type() == Expression::LIST) { - List_Ptr_Const l = dynamic_cast(val); - union Sass_Value* list = sass_make_list(l->size(), l->separator()); + List_Ptr_Const l = Cast(val); + union Sass_Value* list = sass_make_list(l->size(), l->separator(), l->is_bracketed()); for (size_t i = 0, L = l->length(); i < L; ++i) { Expression_Obj obj = l->at(i); - auto val = ast_node_to_sass_value(&obj); + auto val = ast_node_to_sass_value(obj); sass_list_set_value(list, i, val); } return list; } else if (val->concrete_type() == Expression::MAP) { - Map_Ptr_Const m = dynamic_cast(val); + Map_Ptr_Const m = Cast(val); union Sass_Value* map = sass_make_map(m->length()); size_t i = 0; for (Expression_Obj key : m->keys()) { - sass_map_set_key(map, i, ast_node_to_sass_value(&key)); - sass_map_set_value(map, i, ast_node_to_sass_value(&m->at(key))); + sass_map_set_key(map, i, ast_node_to_sass_value(key)); + sass_map_set_value(map, i, ast_node_to_sass_value(m->at(key))); ++ i; } return map; @@ -47,16 +47,16 @@ namespace Sass { } else if (val->concrete_type() == Expression::BOOLEAN) { - Boolean_Ptr_Const res = dynamic_cast(val); + Boolean_Ptr_Const res = Cast(val); return sass_make_boolean(res->value()); } else if (val->concrete_type() == Expression::STRING) { - if (String_Quoted_Ptr_Const qstr = dynamic_cast(val)) + if (String_Quoted_Ptr_Const qstr = Cast(val)) { return sass_make_qstring(qstr->value().c_str()); } - else if (String_Constant_Ptr_Const cstr = dynamic_cast(val)) + else if (String_Constant_Ptr_Const cstr = Cast(val)) { return sass_make_string(cstr->value().c_str()); } @@ -106,6 +106,7 @@ namespace Sass { for (size_t i = 0, L = sass_list_get_length(val); i < L; ++i) { l->append(sass_value_to_ast_node(sass_list_get_value(val, i))); } + l->is_bracketed(sass_list_get_is_bracketed(val)); return l; } break; diff --git a/src/libsass/win/libsass.targets b/src/libsass/win/libsass.targets index 222c4381a..2f079b9d5 100755 --- a/src/libsass/win/libsass.targets +++ b/src/libsass/win/libsass.targets @@ -69,6 +69,7 @@ + diff --git a/src/libsass/win/libsass.vcxproj.filters b/src/libsass/win/libsass.vcxproj.filters index 47ea1c147..36d85b389 100755 --- a/src/libsass/win/libsass.vcxproj.filters +++ b/src/libsass/win/libsass.vcxproj.filters @@ -218,6 +218,9 @@ Sources + + Sources + Sources diff --git a/src/sass_types/list.cpp b/src/sass_types/list.cpp index c17dbd59e..cc94729a3 100644 --- a/src/sass_types/list.cpp +++ b/src/sass_types/list.cpp @@ -8,6 +8,7 @@ namespace SassTypes Sass_Value* List::construct(const std::vector> raw_val, Sass_Value **out) { size_t length = 0; bool comma = true; + bool is_bracketed = false; if (raw_val.size() >= 1) { if (!raw_val[0]->IsNumber()) { @@ -25,7 +26,7 @@ namespace SassTypes } } - return *out = sass_make_list(length, comma ? SASS_COMMA : SASS_SPACE); + return *out = sass_make_list(length, comma ? SASS_COMMA : SASS_SPACE, is_bracketed); } void List::initPrototype(v8::Local proto) {