diff --git a/.gitignore b/.gitignore
index ef3ca02205..5eb2d2b939 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,6 +53,10 @@ libsass/*
*.lo
*.so
*.dll
+*.h.gch
+*.h.pch
+*.hpp.gch
+*.hpp.pch
*.a
*.suo
*.sdf
diff --git a/.travis.yml b/.travis.yml
index d2a0ca0f45..32bd964b1b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -61,10 +61,6 @@ matrix:
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/GNUmakefile.am b/GNUmakefile.am
index 06a1d0c1e6..5a58c3eb4c 100644
--- a/GNUmakefile.am
+++ b/GNUmakefile.am
@@ -29,7 +29,7 @@ if ENABLE_TESTS
SASS_SASSC_PATH ?= $(top_srcdir)/sassc
SASS_SPEC_PATH ?= $(top_srcdir)/sass-spec
-LIBSASS_SPEC_PATH ?= $(top_srcdir)/libsass-spec
+SASS_SPEC_ROOT ?= $(top_srcdir)/sass-spec
noinst_PROGRAMS = tester
tester_LDADD = src/libsass.la
@@ -50,41 +50,25 @@ AM_RB_LOG_FLAGS = $(RUBY)
SASS_TEST_FLAGS = --impl libsass
SASS_TEST_FLAGS += -r $(SASS_SPEC_PATH)/spec
SASS_TEST_FLAGS += -c $(top_srcdir)/tester$(EXEEXT)
-LIBSASS_TEST_FLAGS = --impl libsass
-LIBSASS_TEST_FLAGS += -r $(LIBSASS_SPEC_PATH)/spec
-LIBSASS_TEST_FLAGS += -c $(top_srcdir)/tester$(EXEEXT)
-COMPRESSED_TEST_FLAGS = --impl libsass
-COMPRESSED_TEST_FLAGS += -r $(LIBSASS_SPEC_PATH)/styles/compressed
-COMPRESSED_TEST_FLAGS += -c $(top_srcdir)/tester$(EXEEXT)
-COMPRESSED_TEST_FLAGS += --cmd-args="-t compressed"
+SASS_TEST_FLAGS += --cmd-args "-I $(SASS_SPEC_ROOT)/spec"
AM_TESTS_ENVIRONMENT = TEST_FLAGS='$(SASS_TEST_FLAGS)'
SASS_TESTER = $(RUBY) $(SASS_SPEC_PATH)/sass-spec.rb
test:
$(SASS_TESTER) $(SASS_TEST_FLAGS)
- $(SASS_TESTER) $(LIBSASS_TEST_FLAGS)
- $(SASS_TESTER) $(COMPRESSED_TEST_FLAGS)
test_build:
$(SASS_TESTER) $(SASS_TEST_FLAGS)
- $(SASS_TESTER) $(LIBSASS_TEST_FLAGS)
- $(SASS_TESTER) $(COMPRESSED_TEST_FLAGS)
test_full:
$(SASS_TESTER) --run-todo $(SASS_TEST_FLAGS)
- $(SASS_TESTER) --run-todo $(LIBSASS_TEST_FLAGS)
- $(SASS_TESTER) --run-todo $(COMPRESSED_TEST_FLAGS)
test_probe:
$(SASS_TESTER) --probe-todo $(SASS_TEST_FLAGS)
- $(SASS_TESTER) --probe-todo $(LIBSASS_TEST_FLAGS)
- $(SASS_TESTER) --probe-todo $(COMPRESSED_TEST_FLAGS)
test_interactive:
$(SASS_TESTER) --interactive $(SASS_TEST_FLAGS)
- $(SASS_TESTER) --interactive $(LIBSASS_TEST_FLAGS)
- $(SASS_TESTER) --interactive $(COMPRESSED_TEST_FLAGS)
.PHONY: test test_build test_full test_probe
diff --git a/Makefile b/Makefile
index 30023bab0e..aba515e5fb 100644
--- a/Makefile
+++ b/Makefile
@@ -16,14 +16,24 @@ CFLAGS ?= -Wall
CXXFLAGS ?= -Wall
LDFLAGS ?= -Wall
ifndef COVERAGE
- CFLAGS += -O2
- CXXFLAGS += -O2
- LDFLAGS += -O2
+ CFLAGS += -O3 -pipe -DNDEBUG -fomit-frame-pointer
+ CXXFLAGS += -O3 -pipe -DNDEBUG -fomit-frame-pointer
+ LDFLAGS += -O3 -pipe -DNDEBUG -fomit-frame-pointer
else
CFLAGS += -O1 -fno-omit-frame-pointer
CXXFLAGS += -O1 -fno-omit-frame-pointer
LDFLAGS += -O1 -fno-omit-frame-pointer
endif
+ifeq "$(LIBSASS_GPO)" "generate"
+ CFLAGS += -fprofile-generate
+ CXXFLAGS += -fprofile-generate
+ LDFLAGS += -fprofile-generate -Wl,-fprofile-instr-generate
+endif
+ifeq "$(LIBSASS_GPO)" "use"
+ CFLAGS += -fprofile-use
+ CXXFLAGS += -fprofile-use
+ LDFLAGS += -fprofile-use -Wl,-fprofile-instr-use
+endif
CAT ?= $(if $(filter $(OS),Windows_NT),type,cat)
ifneq (,$(findstring /cygdrive/,$(PATH)))
@@ -84,6 +94,9 @@ else
CXXFLAGS += -I include
endif
+CFLAGS += -I $(SASS_LIBSASS_PATH)/src
+CXXFLAGS += -I $(SASS_LIBSASS_PATH)/src
+
CFLAGS += $(EXTRA_CFLAGS)
CXXFLAGS += $(EXTRA_CXXFLAGS)
LDFLAGS += $(EXTRA_LDFLAGS)
@@ -144,7 +157,7 @@ SASS_SASSC_PATH ?= sassc
SASS_SPEC_PATH ?= sass-spec
SASS_SPEC_SPEC_DIR ?= spec
LIBSASS_SPEC_PATH ?= libsass-spec
-LIBSASS_SPEC_SPEC_DIR ?= spec
+LIBSASS_SPEC_SPEC_DIR ?= suites
SASSC_BIN = $(SASS_SASSC_PATH)/bin/sassc
RUBY_BIN = ruby
@@ -177,6 +190,7 @@ endif
include Makefile.conf
OBJECTS = $(addprefix src/,$(SOURCES:.cpp=.o))
COBJECTS = $(addprefix src/,$(CSOURCES:.c=.o))
+HEADOBJS = $(addprefix src/,$(HPPFILES:.hpp=.hpp.gch))
RCOBJECTS = $(RESOURCES:.rc=.o)
DEBUG_LVL ?= NONE
@@ -185,6 +199,7 @@ CLEANUPS ?=
CLEANUPS += $(RCOBJECTS)
CLEANUPS += $(COBJECTS)
CLEANUPS += $(OBJECTS)
+CLEANUPS += $(HEADOBJS)
CLEANUPS += $(LIBSASS_LIB)
all: $(BUILD)
@@ -218,15 +233,18 @@ lib/libsass.dll: $(COBJECTS) $(OBJECTS) $(RCOBJECTS) | lib
$(CXX) -shared $(LDFLAGS) -o $@ $(COBJECTS) $(OBJECTS) $(RCOBJECTS) $(LDLIBS) \
-s -Wl,--subsystem,windows,--out-implib,lib/libsass.a
-%.o: %.c
- $(CC) $(CFLAGS) -c -o $@ $<
-
-%.o: %.rc
+$(RCOBJECTS): %.o: %.rc
$(WINDRES) -i $< -o $@
-%.o: %.cpp
+$(OBJECTS): %.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
+$(COBJECTS): %.o: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(HEADOBJS): %.hpp.gch: %.hpp
+ $(CXX) $(CXXFLAGS) -x c++-header -c -o $@ $<
+
%: %.o static
$(CXX) $(CXXFLAGS) -o $@ $+ $(LDFLAGS) $(LDLIBS)
@@ -252,7 +270,6 @@ $(DESTDIR)$(PREFIX)/include/%.h: include/%.h \
$(INSTALL) -v -m0644 "$<" "$@"
install-headers: $(DESTDIR)$(PREFIX)/include/sass.h \
- $(DESTDIR)$(PREFIX)/include/sass2scss.h \
$(DESTDIR)$(PREFIX)/include/sass/base.h \
$(DESTDIR)$(PREFIX)/include/sass/version.h \
$(DESTDIR)$(PREFIX)/include/sass/values.h \
@@ -302,13 +319,13 @@ test_build: $(SASSC_BIN) $(SASS_SPEC_PATH) $(LIBSASS_SPEC_PATH)
--cmd-args "-I $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)" \
$(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)
$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -c $(SASSC_BIN) --impl libsass \
- --cmd-args "-I $(LIBSASS_SPEC_PATH)/$(LIBSASS_SPEC_SPEC_DIR)" \
+ --cmd-args "-I . -I $(LIBSASS_SPEC_PATH)/$(LIBSASS_SPEC_SPEC_DIR)" \
$(LOG_FLAGS) $(LIBSASS_SPEC_PATH)/$(LIBSASS_SPEC_SPEC_DIR)
$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -c $(SASSC_BIN) --impl libsass \
- --cmd-args "-I $(LIBSASS_SPEC_PATH)/styles/compressed -t compressed" \
+ --cmd-args "-I . -I $(LIBSASS_SPEC_PATH)/styles/compressed -t compressed" \
$(LOG_FLAGS) $(LIBSASS_SPEC_PATH)/styles/compressed
$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -c $(SASSC_BIN) --impl libsass \
- --cmd-args "-I $(LIBSASS_SPEC_PATH)/styles/nested -t nested" \
+ --cmd-args "-I . -I $(LIBSASS_SPEC_PATH)/styles/nested -t nested" \
$(LOG_FLAGS) $(LIBSASS_SPEC_PATH)/styles/nested
test_full: $(SASSC_BIN) $(SASS_SPEC_PATH) $(LIBSASS_SPEC_PATH)
@@ -316,13 +333,13 @@ test_full: $(SASSC_BIN) $(SASS_SPEC_PATH) $(LIBSASS_SPEC_PATH)
--cmd-args "-I $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)" \
--run-todo $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)
$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -c $(SASSC_BIN) --impl libsass \
- --cmd-args "-I $(LIBSASS_SPEC_PATH)/$(LIBSASS_SPEC_SPEC_DIR)" \
+ --cmd-args "-I . -I $(LIBSASS_SPEC_PATH)/$(LIBSASS_SPEC_SPEC_DIR)" \
--run-todo $(LOG_FLAGS) $(LIBSASS_SPEC_PATH)/$(LIBSASS_SPEC_SPEC_DIR)
$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -c $(SASSC_BIN) --impl libsass \
- --cmd-args "-I $(LIBSASS_SPEC_PATH)/styles/compressed -t compressed" \
+ --cmd-args "-I . -I $(LIBSASS_SPEC_PATH)/styles/compressed -t compressed" \
--run-todo $(LOG_FLAGS) $(LIBSASS_SPEC_PATH)/styles/compressed
$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -c $(SASSC_BIN) --impl libsass \
- --cmd-args "-I $(LIBSASS_SPEC_PATH)/styles/nested -t nested" \
+ --cmd-args "-I . -I $(LIBSASS_SPEC_PATH)/styles/nested -t nested" \
--run-todo $(LOG_FLAGS) $(LIBSASS_SPEC_PATH)/styles/nested
test_probe: $(SASSC_BIN) $(SASS_SPEC_PATH) $(LIBSASS_SPEC_PATH)
@@ -330,13 +347,13 @@ test_probe: $(SASSC_BIN) $(SASS_SPEC_PATH) $(LIBSASS_SPEC_PATH)
--cmd-args "-I $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)" \
--probe-todo $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)
$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -c $(SASSC_BIN) --impl libsass \
- --cmd-args "-I $(LIBSASS_SPEC_PATH)/$(LIBSASS_SPEC_SPEC_DIR)" \
+ --cmd-args "-I . -I $(LIBSASS_SPEC_PATH)/$(LIBSASS_SPEC_SPEC_DIR)" \
--probe-todo $(LOG_FLAGS) $(LIBSASS_SPEC_PATH)/$(LIBSASS_SPEC_SPEC_DIR)
$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -c $(SASSC_BIN) --impl libsass \
- --cmd-args "-I $(LIBSASS_SPEC_PATH)/styles/compressed -t compressed" \
+ --cmd-args "-I . -I $(LIBSASS_SPEC_PATH)/styles/compressed -t compressed" \
--probe-todo $(LOG_FLAGS) $(LIBSASS_SPEC_PATH)/styles/compressed
$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -c $(SASSC_BIN) --impl libsass \
- --cmd-args "-I $(LIBSASS_SPEC_PATH)/styles/nested -t nested" \
+ --cmd-args "-I . -I $(LIBSASS_SPEC_PATH)/styles/nested -t nested" \
--probe-todo $(LOG_FLAGS) $(LIBSASS_SPEC_PATH)/styles/nested
test_interactive: $(SASSC_BIN) $(SASS_SPEC_PATH) $(LIBSASS_SPEC_PATH)
@@ -344,13 +361,13 @@ test_interactive: $(SASSC_BIN) $(SASS_SPEC_PATH) $(LIBSASS_SPEC_PATH)
--cmd-args "-I $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)" \
--interactive $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)
$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -c $(SASSC_BIN) --impl libsass \
- --cmd-args "-I $(LIBSASS_SPEC_PATH)/$(LIBSASS_SPEC_SPEC_DIR)" \
+ --cmd-args "-I . -I $(LIBSASS_SPEC_PATH)/$(LIBSASS_SPEC_SPEC_DIR)" \
--interactive $(LOG_FLAGS) $(LIBSASS_SPEC_PATH)/$(LIBSASS_SPEC_SPEC_DIR)
$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -c $(SASSC_BIN) --impl libsass \
- --cmd-args "-I $(LIBSASS_SPEC_PATH)/styles/compressed -t compressed" \
+ --cmd-args "-I . -I $(LIBSASS_SPEC_PATH)/styles/compressed -t compressed" \
--interactive $(LOG_FLAGS) $(LIBSASS_SPEC_PATH)/styles/compressed
$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -c $(SASSC_BIN) --impl libsass \
- --cmd-args "-I $(LIBSASS_SPEC_PATH)/styles/nested -t nested" \
+ --cmd-args "-I . -I $(LIBSASS_SPEC_PATH)/styles/nested -t nested" \
--interactive $(LOG_FLAGS) $(LIBSASS_SPEC_PATH)/styles/nested
clean-objects: | lib
diff --git a/Makefile.conf b/Makefile.conf
index 679e36ccfa..f088bec305 100644
--- a/Makefile.conf
+++ b/Makefile.conf
@@ -4,95 +4,125 @@
# in parallel. But we also want to mix them a little too avoid
# heavy RAM usage peaks. Other than that the order is arbitrary.
-
INCFILES = \
sass.h \
- sass2scss.h \
sass/base.h \
- sass/context.h \
- sass/functions.h \
+ sass/fwdecl.h \
+ sass/enums.h \
sass/values.h \
- sass/version.h
+ sass/version.h \
+ sass/context.h \
+ sass/function.h
HPPFILES = \
ast.hpp \
- ast2c.hpp \
+ ast_css.hpp \
+ ast_nodes.hpp \
ast_def_macros.hpp \
ast_fwd_decl.hpp \
ast_helpers.hpp \
ast_selectors.hpp \
+ ast_containers.hpp \
ast_supports.hpp \
+ ast_callables.hpp \
+ ast_statements.hpp \
+ ast_expressions.hpp \
ast_values.hpp \
backtrace.hpp \
base64vlq.hpp \
- bind.hpp \
- c2ast.hpp \
- check_nesting.hpp \
+ character.hpp \
+ charcode.hpp \
color_maps.hpp \
constants.hpp \
context.hpp \
cssize.hpp \
dart_helpers.hpp \
- debug.hpp \
debugger.hpp \
emitter.hpp \
environment.hpp \
- error_handling.hpp \
+ exceptions.hpp \
+ memory.hpp \
+ memory/config.hpp \
+ memory/allocator.hpp \
+ memory/shared_ptr.hpp \
+ memory/memory_pool.hpp \
+ MurmurHash2.hpp \
eval.hpp \
- expand.hpp \
extender.hpp \
extension.hpp \
file.hpp \
+ compiler.hpp \
fn_colors.hpp \
fn_lists.hpp \
fn_maps.hpp \
- fn_miscs.hpp \
+ fn_meta.hpp \
fn_numbers.hpp \
fn_selectors.hpp \
- fn_strings.hpp \
+ fn_texts.hpp \
fn_utils.hpp \
+ strings.hpp \
inspect.hpp \
+ terminal.hpp \
+ interpolation.hpp \
+ logger.hpp \
json.hpp \
kwd_arg_macros.hpp \
- lexer.hpp \
- listize.hpp \
+ randomize.hpp \
mapping.hpp \
- memory.hpp \
- MurmurHash2.hpp \
- operation.hpp \
- operators.hpp \
ordered_map.hpp \
+ source.hpp \
output.hpp \
parser.hpp \
+ parser_base.hpp \
+ parser_css.hpp \
+ parser_expression.hpp \
+ parser_media_query.hpp \
+ parser_at_root_query.hpp \
+ parser_keyframe_selector.hpp \
+ parser_sass.hpp \
+ parser_scss.hpp \
+ parser_selector.hpp \
+ parser_stylesheet.hpp \
permutate.hpp \
plugins.hpp \
- position.hpp \
- prelexer.hpp \
+ offset.hpp \
remove_placeholders.hpp \
- sass.hpp \
- sass_context.hpp \
- sass_functions.hpp \
- sass_values.hpp \
- settings.hpp \
- source.hpp \
- source_data.hpp \
+ capi_sass.hpp \
+ capi_base.hpp \
+ capi_list.hpp \
+ capi_error.hpp \
+ capi_context.hpp \
+ capi_compiler.hpp \
+ capi_functions.hpp \
+ capi_values.hpp \
+ scanner_string.hpp \
source_map.hpp \
+ source_state.hpp \
+ source_span.hpp \
stylesheet.hpp \
- to_value.hpp \
units.hpp \
- utf8_string.hpp \
- util.hpp \
+ unicode.hpp \
util_string.hpp \
- values.hpp \
- memory/allocator.hpp \
- memory/config.hpp \
- memory/memory_pool.hpp \
- memory/shared_ptr.hpp
+ visitor_css.hpp \
+ visitor_expression.hpp \
+ visitor_selector.hpp \
+ visitor_statement.hpp \
+ visitor_value.hpp \
+ string_utils.hpp \
+ callstack.hpp \
+ environment_cnt.hpp \
+ environment_key.hpp \
+ environment_stack.hpp
SOURCES = \
ast.cpp \
+ ast_css.cpp \
+ ast_nodes.cpp \
ast_values.cpp \
ast_supports.cpp \
+ ast_callables.cpp \
+ ast_statements.cpp \
+ ast_expressions.cpp \
ast_sel_cmp.cpp \
ast_sel_unify.cpp \
ast_sel_super.cpp \
@@ -100,60 +130,69 @@ SOURCES = \
ast_selectors.cpp \
context.cpp \
constants.cpp \
- fn_utils.cpp \
- fn_miscs.cpp \
+ compiler.cpp \
fn_maps.cpp \
fn_lists.cpp \
fn_colors.cpp \
fn_numbers.cpp \
- fn_strings.cpp \
+ fn_texts.cpp \
fn_selectors.cpp \
+ fn_meta.cpp \
color_maps.cpp \
environment.cpp \
ast_fwd_decl.cpp \
- bind.cpp \
file.cpp \
- util.cpp \
util_string.cpp \
+ string_utils.cpp \
+ logger.cpp \
+ strings.cpp \
json.cpp \
units.cpp \
- values.cpp \
plugins.cpp \
source.cpp \
- position.cpp \
- lexer.cpp \
- parser.cpp \
- parser_selectors.cpp \
- prelexer.cpp \
+ offset.cpp \
eval.cpp \
- eval_selectors.cpp \
- expand.cpp \
- listize.cpp \
+ randomize.cpp \
cssize.cpp \
extender.cpp \
extension.cpp \
stylesheet.cpp \
+ interpolation.cpp \
+ parser.cpp \
+ parser_css.cpp \
+ parser_base.cpp \
+ parser_scss.cpp \
+ parser_sass.cpp \
+ parser_selector.cpp \
+ parser_stylesheet.cpp \
+ parser_expression.cpp \
+ parser_media_query.cpp \
+ parser_at_root_query.cpp \
+ parser_keyframe_selector.cpp \
output.cpp \
inspect.cpp \
+ terminal.cpp \
emitter.cpp \
- check_nesting.cpp \
+ scanner_string.cpp \
remove_placeholders.cpp \
- sass.cpp \
- sass_values.cpp \
- sass_context.cpp \
- sass_functions.cpp \
- sass2scss.cpp \
- backtrace.cpp \
- operators.cpp \
- ast2c.cpp \
- c2ast.cpp \
- to_value.cpp \
+ capi_sass.cpp \
+ capi_base.cpp \
+ capi_lists.cpp \
+ capi_error.cpp \
+ capi_values.cpp \
+ capi_context.cpp \
+ capi_compiler.cpp \
+ capi_functions.cpp \
+ character.cpp \
+ environment_stack.cpp \
source_map.cpp \
- error_handling.cpp \
+ source_state.cpp \
+ source_span.cpp \
+ exceptions.cpp \
memory/allocator.cpp \
memory/shared_ptr.cpp \
- utf8_string.cpp \
- base64vlq.cpp
+ LUrlParser/LUrlParser.cpp \
+ unicode.cpp \
+ cencode.cpp
-CSOURCES = \
- cencode.c
+CSOURCES =
diff --git a/appveyor.yml b/appveyor.yml
index f462207844..ac38a87fb3 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,4 +1,4 @@
-os: Visual Studio 2013
+os: Visual Studio 2015
environment:
CTEST_OUTPUT_ON_FAILURE: 1
@@ -33,7 +33,7 @@ cache:
install:
- git clone https://github.com/sass/sassc.git
- - git clone https://github.com/sass/sass-spec.git
+ - git clone https://github.com/mgreter/sass-spec.git --branch feature/libsass-parser-backport
- set PATH=C:\Ruby%ruby_version%\bin;%PATH%
- ps: |
if(!(gem which minitest 2>$nul)) { gem install minitest --no-ri --no-rdoc }
@@ -66,17 +66,6 @@ build_script:
test_script:
- ps: |
$PRNR = $env:APPVEYOR_PULL_REQUEST_NUMBER
- if ($PRNR) {
- echo "Fetching info for PR $PRNR"
- wget https://api.github.com/repos/sass/libsass/pulls/$PRNR -OutFile pr.json
- $json = cat pr.json -Raw
- $SPEC_PR = [regex]::match($json,'sass\/sass-spec(#|\/pull\/)([0-9]+)').Groups[2].Value
- if ($SPEC_PR) {
- echo "Checkout sass spec PR $SPEC_PR"
- git -C sass-spec fetch -q -u origin pull/$SPEC_PR/head:ci-spec-pr-$SPEC_PR
- git -C sass-spec checkout -q --force ci-spec-pr-$SPEC_PR
- }
- }
$env:TargetPath = Join-Path $pwd.Path $env:TargetPath
If (Test-Path "$env:TargetPath") {
ruby sass-spec/sass-spec.rb --probe-todo --impl libsass -c $env:TargetPath -s sass-spec/spec
diff --git a/configure.ac b/configure.ac
index b5a943217a..78899d642e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -88,18 +88,23 @@ the --with-sass-spec-dir=
argument.
case $sass_spec_dir in
/*)
SASS_SPEC_PATH=`$RUBY -e "require 'pathname'; puts Pathname.new('$sass_spec_dir').relative_path_from(Pathname.new('$PWD')).to_s"`
+ SASS_SPEC_ROOT="$sass_spec_dir"
;;
*)
SASS_SPEC_PATH="$sass_spec_dir"
+ SASS_SPEC_ROOT="$sass_spec_dir"
;;
esac
AC_SUBST(SASS_SPEC_PATH)
+ AC_SUBST(SASS_SPEC_ROOT)
else
# we do not really need these paths for non test build
# but automake may error if we do not define them here
SASS_SPEC_PATH=sass-spec
+ SASS_SPEC_ROOT=sass-spec
SASS_SASSC_PATH=sassc
AC_SUBST(SASS_SPEC_PATH)
+ AC_SUBST(SASS_SPEC_ROOT)
AC_SUBST(SASS_SASSC_PATH)
fi
diff --git a/docs/build-shared-library.md b/docs/build-shared-library.md
index 3c143b46ae..409ab3cebb 100644
--- a/docs/build-shared-library.md
+++ b/docs/build-shared-library.md
@@ -28,7 +28,6 @@ This should install these files
/usr/lib/libsass.so.0.0.9
# $ ls -la /usr/include/sass*
/usr/include/sass.h
-/usr/include/sass2scss.h
/usr/include/sass/context.h
/usr/include/sass/functions.h
/usr/include/sass/values.h
diff --git a/include/sass.h b/include/sass.h
index 1dd8b06dca..41c90fa435 100644
--- a/include/sass.h
+++ b/include/sass.h
@@ -3,13 +3,28 @@
// #define DEBUG 1
+// Note: we can't forward declare with inheritance
+// https://stackoverflow.com/a/10145303/1550314
+
// include API headers
#include
+#include
#include
+#include
#include
+#include
+#include
+#include
#include
#include
-#include
+#include
-#endif
+typedef struct SassImport* Sass_Import_Entry;
+typedef struct SassImporter* Sass_Importer_Entry;
+typedef struct SassFunction* Sass_Function_Entry;
+typedef struct SassImportList* Sass_Import_List;
+typedef struct SassImporterList* Sass_Importer_List;
+typedef struct SassFunctionList* Sass_Function_List;
+
+#endif
diff --git a/include/sass/base.h b/include/sass/base.h
index 132da693ab..b73c4023dc 100644
--- a/include/sass/base.h
+++ b/include/sass/base.h
@@ -1,8 +1,5 @@
-#ifndef SASS_BASE_H
-#define SASS_BASE_H
-
-// #define DEBUG
-// #define DEBUG_SHARED_PTR
+#ifndef SASS_C_BASE_H
+#define SASS_C_BASE_H
#ifdef _MSC_VER
#pragma warning(disable : 4503)
@@ -23,9 +20,17 @@
#define noexcept throw( )
#endif
+// Load some POD types
#include
+#include
#include
+// Include forward declarations
+#include
+
+// Include enumerations
+#include
+
#ifdef __GNUC__
#define DEPRECATED(func) func __attribute__ ((deprecated))
#elif defined(_MSC_VER)
@@ -54,41 +59,50 @@
#endif
-/* Make sure functions are exported with C linkage under C++ compilers. */
#ifdef __cplusplus
extern "C" {
#endif
-
-// Different render styles
-enum Sass_Output_Style {
- SASS_STYLE_NESTED,
- SASS_STYLE_EXPANDED,
- SASS_STYLE_COMPACT,
- SASS_STYLE_COMPRESSED,
- // only used internaly
- SASS_STYLE_INSPECT,
- SASS_STYLE_TO_SASS,
- SASS_STYLE_TO_CSS
-};
-
-// to allocate buffer to be filled
-ADDAPI void* ADDCALL sass_alloc_memory(size_t size);
-// to allocate a buffer from existing string
-ADDAPI char* ADDCALL sass_copy_c_string(const char* str);
-// to free overtaken memory when done
-ADDAPI void ADDCALL sass_free_memory(void* ptr);
-
-// Some convenient string helper function
-ADDAPI char* ADDCALL sass_string_quote (const char* str, const char quote_mark);
-ADDAPI char* ADDCALL sass_string_unquote (const char* str);
-
-// Implemented sass language version
-// Hardcoded version 3.4 for time being
-ADDAPI const char* ADDCALL libsass_version(void);
-
-// Get compiled libsass language
-ADDAPI const char* ADDCALL libsass_language_version(void);
+ // Change the virtual current working directory
+ // You should probably not really use this function!
+ ADDAPI void ADDCALL sass_chdir(const char* path);
+
+ // Prints message to stderr with color for windows
+ ADDAPI void ADDCALL sass_print_stdout(const char* message);
+ ADDAPI void ADDCALL sass_print_stderr(const char* message);
+
+ // Allocate a memory block on the heap of (at least) [size].
+ // Make sure to release to acquired memory at some later point via
+ // `sass_free_memory`. You need to go through my utility function in
+ // case your code and my main program don't use the same memory manager.
+ ADDAPI void* ADDCALL sass_alloc_memory(size_t size);
+
+ // Allocate a memory block on the heap and copy [string] into it.
+ // Make sure to release to acquired memory at some later point via
+ // `sass_free_memory`. You need to go through my utility function in
+ // case your code and my main program don't use the same memory manager.
+ ADDAPI char* ADDCALL sass_copy_c_string(const char* str);
+
+ // Deallocate libsass heap memory
+ ADDAPI void ADDCALL sass_free_memory(void* ptr);
+ ADDAPI void ADDCALL sass_free_c_string(char* ptr);
+
+ // 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 SassOptionsCpp* opt);
+ // ADDAPI char* ADDCALL sass_find_include (const char* path, struct SassOptionsCpp* 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 SassCompiler* compiler);
+ // ADDAPI char* ADDCALL sass_compiler_find_include(const char* path, struct SassCompiler* compiler);
+
+ // Return implemented sass language version
+ ADDAPI const char* ADDCALL libsass_version(void);
+
+ // Return the compiled libsass language (hard-coded)
+ // This is hard-coded with the library on compilation!
+ ADDAPI const char* ADDCALL libsass_language_version(void);
#ifdef __cplusplus
} // __cplusplus defined.
diff --git a/include/sass/compiler.h b/include/sass/compiler.h
new file mode 100644
index 0000000000..8fc1642bda
--- /dev/null
+++ b/include/sass/compiler.h
@@ -0,0 +1,91 @@
+#ifndef SASS_C_COMPILER_H
+#define SASS_C_COMPILER_H
+
+#include
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ // Create a new compiler from the libsass context and the given entry point
+ ADDAPI struct SassCompiler* ADDCALL sass_make_compiler();
+
+ // Release all memory allocated with the structures
+ ADDAPI void ADDCALL sass_delete_compiler(struct SassCompiler* compiler);
+
+ // Parse the entry point and potentially all imports within
+ ADDAPI void ADDCALL sass_compiler_parse(struct SassCompiler* compiler);
+
+ // Evaluate the parsed entry point and store resulting ast-tree
+ ADDAPI void ADDCALL sass_compiler_compile(struct SassCompiler* compiler);
+
+ // Render the evaluated ast-tree to get the final output string
+ ADDAPI void ADDCALL sass_compiler_render(struct SassCompiler* compiler);
+
+ // Push function for paths (no manipulation support for now)
+ ADDAPI void ADDCALL sass_compiler_load_plugins(struct SassCompiler* compiler, const char* paths);
+ ADDAPI void ADDCALL sass_compiler_add_include_paths(struct SassCompiler* compiler, const char* paths);
+ ADDAPI void ADDCALL sass_compiler_add_custom_header(struct SassCompiler* compiler, struct SassImporter* header);
+ ADDAPI void ADDCALL sass_compiler_add_custom_importer(struct SassCompiler* compiler, struct SassImporter* importer);
+ ADDAPI void ADDCALL sass_compiler_add_custom_function(struct SassCompiler* compiler, struct SassFunction* function);
+
+ // Setters for output and console logging styles
+ ADDAPI void ADDCALL sass_compiler_set_output_style(struct SassCompiler* compiler, enum SassOutputStyle output_style);
+ ADDAPI void ADDCALL sass_compiler_set_logger_style(struct SassCompiler* compiler, enum SassLoggerStyle log_style);
+
+ // Getters for compiler option values
+ ADDAPI int ADDCALL sass_compiler_get_precision(struct SassCompiler* compiler);
+ ADDAPI const char* ADDCALL sass_compiler_get_output_path(struct SassCompiler* compiler);
+ ADDAPI struct SassImport* ADDCALL sass_compiler_get_entry_point(struct SassCompiler* compiler);
+
+ // Setters for compiler option values
+ ADDAPI void ADDCALL sass_compiler_set_precision(struct SassCompiler* compiler, int precision);
+ ADDAPI void ADDCALL sass_compiler_set_output_path(struct SassCompiler* compiler, const char* output_path);
+ ADDAPI void ADDCALL sass_compiler_set_entry_point(struct SassCompiler* compiler, struct SassImport* import);
+
+ // Getter for sass compiler results
+ ADDAPI const char* ADDCALL sass_compiler_get_warn_string(struct SassCompiler* compiler);
+ ADDAPI const char* ADDCALL sass_compiler_get_output_string(struct SassCompiler* compiler);
+ ADDAPI const char* ADDCALL sass_compiler_get_footer_string(struct SassCompiler* compiler);
+ ADDAPI const char* ADDCALL sass_compiler_get_srcmap_string(struct SassCompiler* compiler);
+
+ // Setters for source-map options
+ ADDAPI void ADDCALL sass_compiler_set_srcmap_path(struct SassCompiler* compiler, const char* path);
+ ADDAPI void ADDCALL sass_compiler_set_srcmap_root(struct SassCompiler* compiler, const char* root);
+ ADDAPI void ADDCALL sass_compiler_set_srcmap_mode(struct SassCompiler* compiler, enum SassSrcMapMode mode);
+ ADDAPI void ADDCALL sass_compiler_set_srcmap_file_urls(struct SassCompiler* compiler, bool enable);
+ ADDAPI void ADDCALL sass_compiler_set_srcmap_embed_contents(struct SassCompiler* compiler, bool enable);
+
+ ADDAPI size_t ADDCALL sass_compiler_get_included_files_count(struct SassCompiler* compiler);
+ ADDAPI const char* ADDCALL sass_compiler_get_included_file_path(struct SassCompiler* compiler, size_t n);
+
+ ADDAPI struct SassImport* ADDCALL sass_compiler_get_last_import(struct SassCompiler* compiler);
+
+#ifdef __cplusplus
+} // EO extern "C".
+#endif
+
+#ifdef __cplusplus
+namespace Sass {
+extern "C" {
+#endif
+
+ // Returns pointer to error object associated with compiler.
+ // Will be valid until the associated compiler is destroyed.
+ ADDAPI const struct SassError* ADDCALL sass_compiler_get_error(struct SassCompiler* compiler);
+ ADDAPI const char* ADDCALL sass_compiler_get_stderr(struct SassCompiler* compiler);
+
+
+
+
+ // ADDAPI void ADDCALL sass_compiler_set_input_path(struct SassCompiler* compiler, const char* input_path);
+ // ADDAPI void ADDCALL sass_compiler_set_source_map_file(struct SassCompiler* compiler, const char* source_map_file);
+ // ADDAPI void ADDCALL sass_compiler_set_source_map_root(struct SassCompiler* compiler, const char* source_map_root);
+
+
+
+#ifdef __cplusplus
+} // EO extern "C".
+} // EO namespace Sass
+#endif
+
+#endif
diff --git a/include/sass/context.h b/include/sass/context.h
index 7eb181e259..d3041fa703 100644
--- a/include/sass/context.h
+++ b/include/sass/context.h
@@ -1,171 +1,22 @@
#ifndef SASS_C_CONTEXT_H
#define SASS_C_CONTEXT_H
-#include
-#include
#include
-#include
-#include
#ifdef __cplusplus
extern "C" {
#endif
-// Forward declaration
-struct Sass_Compiler;
-
-// Forward declaration
-struct Sass_Options; // base struct
-struct Sass_Context; // : Sass_Options
-struct Sass_File_Context; // : Sass_Context
-struct Sass_Data_Context; // : Sass_Context
-
-// Compiler states
-enum Sass_Compiler_State {
- SASS_COMPILER_CREATED,
- SASS_COMPILER_PARSED,
- SASS_COMPILER_EXECUTED
-};
-
-// Create and initialize an option struct
-ADDAPI struct Sass_Options* ADDCALL sass_make_options (void);
-// Create and initialize a specific context
-ADDAPI struct Sass_File_Context* ADDCALL sass_make_file_context (const char* input_path);
-ADDAPI struct Sass_Data_Context* ADDCALL sass_make_data_context (char* source_string);
-
-// Call the compilation step for the specific context
-ADDAPI int ADDCALL sass_compile_file_context (struct Sass_File_Context* ctx);
-ADDAPI int ADDCALL sass_compile_data_context (struct Sass_Data_Context* ctx);
-
-// Create a sass compiler instance for more control
-ADDAPI struct Sass_Compiler* ADDCALL sass_make_file_compiler (struct Sass_File_Context* file_ctx);
-ADDAPI struct Sass_Compiler* ADDCALL sass_make_data_compiler (struct Sass_Data_Context* data_ctx);
-
-// Execute the different compilation steps individually
-// Useful if you only want to query the included files
-ADDAPI int ADDCALL sass_compiler_parse(struct Sass_Compiler* compiler);
-ADDAPI int ADDCALL sass_compiler_execute(struct Sass_Compiler* compiler);
-
-// Release all memory allocated with the compiler
-// This does _not_ include any contexts or options
-ADDAPI void ADDCALL sass_delete_compiler(struct Sass_Compiler* compiler);
-ADDAPI void ADDCALL sass_delete_options(struct Sass_Options* options);
-
-// Release all memory allocated and also ourself
-ADDAPI void ADDCALL sass_delete_file_context (struct Sass_File_Context* ctx);
-ADDAPI void ADDCALL sass_delete_data_context (struct Sass_Data_Context* ctx);
-
-// Getters for context from specific implementation
-ADDAPI struct Sass_Context* ADDCALL sass_file_context_get_context (struct Sass_File_Context* file_ctx);
-ADDAPI struct Sass_Context* ADDCALL sass_data_context_get_context (struct Sass_Data_Context* data_ctx);
-
-// Getters for Context_Options from Sass_Context
-ADDAPI struct Sass_Options* ADDCALL sass_context_get_options (struct Sass_Context* ctx);
-ADDAPI struct Sass_Options* ADDCALL sass_file_context_get_options (struct Sass_File_Context* file_ctx);
-ADDAPI struct Sass_Options* ADDCALL sass_data_context_get_options (struct Sass_Data_Context* data_ctx);
-ADDAPI void ADDCALL sass_file_context_set_options (struct Sass_File_Context* file_ctx, struct Sass_Options* opt);
-ADDAPI void ADDCALL sass_data_context_set_options (struct Sass_Data_Context* data_ctx, struct Sass_Options* opt);
-
-
-// Getters for Context_Option values
-ADDAPI int ADDCALL sass_option_get_precision (struct Sass_Options* options);
-ADDAPI enum Sass_Output_Style ADDCALL sass_option_get_output_style (struct Sass_Options* options);
-ADDAPI bool ADDCALL sass_option_get_source_comments (struct Sass_Options* options);
-ADDAPI bool ADDCALL sass_option_get_source_map_embed (struct Sass_Options* options);
-ADDAPI bool ADDCALL sass_option_get_source_map_contents (struct Sass_Options* options);
-ADDAPI bool ADDCALL sass_option_get_source_map_file_urls (struct Sass_Options* options);
-ADDAPI bool ADDCALL sass_option_get_omit_source_map_url (struct Sass_Options* options);
-ADDAPI bool ADDCALL sass_option_get_is_indented_syntax_src (struct Sass_Options* options);
-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_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);
-ADDAPI Sass_Importer_List ADDCALL sass_option_get_c_importers (struct Sass_Options* options);
-ADDAPI Sass_Function_List ADDCALL sass_option_get_c_functions (struct Sass_Options* options);
-
-// Setters for Context_Option values
-ADDAPI void ADDCALL sass_option_set_precision (struct Sass_Options* options, int precision);
-ADDAPI void ADDCALL sass_option_set_output_style (struct Sass_Options* options, enum Sass_Output_Style output_style);
-ADDAPI void ADDCALL sass_option_set_source_comments (struct Sass_Options* options, bool source_comments);
-ADDAPI void ADDCALL sass_option_set_source_map_embed (struct Sass_Options* options, bool source_map_embed);
-ADDAPI void ADDCALL sass_option_set_source_map_contents (struct Sass_Options* options, bool source_map_contents);
-ADDAPI void ADDCALL sass_option_set_source_map_file_urls (struct Sass_Options* options, bool source_map_file_urls);
-ADDAPI void ADDCALL sass_option_set_omit_source_map_url (struct Sass_Options* options, bool omit_source_map_url);
-ADDAPI void ADDCALL sass_option_set_is_indented_syntax_src (struct Sass_Options* options, bool is_indented_syntax_src);
-ADDAPI void ADDCALL sass_option_set_indent (struct Sass_Options* options, const char* indent);
-ADDAPI void ADDCALL sass_option_set_linefeed (struct Sass_Options* options, const char* linefeed);
-ADDAPI void ADDCALL sass_option_set_input_path (struct Sass_Options* options, const char* input_path);
-ADDAPI void ADDCALL sass_option_set_output_path (struct Sass_Options* options, const char* output_path);
-ADDAPI void ADDCALL sass_option_set_plugin_path (struct Sass_Options* options, const char* plugin_path);
-ADDAPI void ADDCALL sass_option_set_include_path (struct Sass_Options* options, const char* include_path);
-ADDAPI void ADDCALL sass_option_set_source_map_file (struct Sass_Options* options, const char* source_map_file);
-ADDAPI void ADDCALL sass_option_set_source_map_root (struct Sass_Options* options, const char* source_map_root);
-ADDAPI void ADDCALL sass_option_set_c_headers (struct Sass_Options* options, Sass_Importer_List c_headers);
-ADDAPI void ADDCALL sass_option_set_c_importers (struct Sass_Options* options, Sass_Importer_List c_importers);
-ADDAPI void ADDCALL sass_option_set_c_functions (struct Sass_Options* options, Sass_Function_List c_functions);
-
-
-// Getters for Sass_Context values
-ADDAPI const char* ADDCALL sass_context_get_output_string (struct Sass_Context* ctx);
-ADDAPI int ADDCALL sass_context_get_error_status (struct Sass_Context* ctx);
-ADDAPI const char* ADDCALL sass_context_get_error_json (struct Sass_Context* ctx);
-ADDAPI const char* ADDCALL sass_context_get_error_text (struct Sass_Context* ctx);
-ADDAPI const char* ADDCALL sass_context_get_error_message (struct Sass_Context* ctx);
-ADDAPI const char* ADDCALL sass_context_get_error_file (struct Sass_Context* ctx);
-ADDAPI const char* ADDCALL sass_context_get_error_src (struct Sass_Context* ctx);
-ADDAPI size_t ADDCALL sass_context_get_error_line (struct Sass_Context* ctx);
-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);
-// Plugin paths to load dynamic libraries work the same
-ADDAPI size_t ADDCALL sass_option_get_plugin_path_size(struct Sass_Options* options);
-ADDAPI const char* ADDCALL sass_option_get_plugin_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);
-
-// Take ownership of memory (value on context is set to 0)
-ADDAPI char* ADDCALL sass_context_take_error_json (struct Sass_Context* ctx);
-ADDAPI char* ADDCALL sass_context_take_error_text (struct Sass_Context* ctx);
-ADDAPI char* ADDCALL sass_context_take_error_message (struct Sass_Context* ctx);
-ADDAPI char* ADDCALL sass_context_take_error_file (struct Sass_Context* ctx);
-ADDAPI char* ADDCALL sass_context_take_error_src (struct Sass_Context* ctx);
-ADDAPI char* ADDCALL sass_context_take_output_string (struct Sass_Context* ctx);
-ADDAPI char* ADDCALL sass_context_take_source_map_string (struct Sass_Context* ctx);
-ADDAPI char** ADDCALL sass_context_take_included_files (struct Sass_Context* ctx);
-
-// Getters for Sass_Compiler options
-ADDAPI enum Sass_Compiler_State ADDCALL sass_compiler_get_state(struct Sass_Compiler* compiler);
-ADDAPI struct Sass_Context* ADDCALL sass_compiler_get_context(struct Sass_Compiler* compiler);
-ADDAPI struct Sass_Options* ADDCALL sass_compiler_get_options(struct Sass_Compiler* compiler);
-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);
+// ADDAPI char* ADDCALL sass_find_file (const char* path, struct SassOptionsCpp* opt);
+// ADDAPI char* ADDCALL sass_find_include (const char* path, struct SassOptionsCpp* 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);
+ADDAPI char* ADDCALL sass_compiler_find_file (const char* path, struct SassCompiler* compiler);
+ADDAPI char* ADDCALL sass_compiler_find_include (const char* path, struct SassCompiler* compiler);
#ifdef __cplusplus
} // __cplusplus defined.
diff --git a/include/sass/enums.h b/include/sass/enums.h
new file mode 100644
index 0000000000..1bcfc58b95
--- /dev/null
+++ b/include/sass/enums.h
@@ -0,0 +1,60 @@
+#ifndef SASS_C_ENUMS_H
+#define SASS_C_ENUMS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Different render styles
+enum SassOutputStyle {
+ SASS_STYLE_NESTED,
+ SASS_STYLE_EXPANDED,
+ SASS_STYLE_COMPACT,
+ SASS_STYLE_COMPRESSED,
+ // only used internally, but
+ // should be flag like inspect
+ SASS_STYLE_TO_CSS
+};
+
+// Type of parser to use
+enum SassImportFormat {
+ SASS_IMPORT_AUTO,
+ SASS_IMPORT_SCSS,
+ SASS_IMPORT_SASS,
+ SASS_IMPORT_CSS,
+};
+
+enum SassSrcMapMode {
+ SASS_SRCMAP_NONE,
+ SASS_SRCMAP_CREATE,
+ SASS_SRCMAP_EMBED_LINK,
+ SASS_SRCMAP_EMBED_JSON,
+};
+
+enum SassCompilerState {
+ SASS_COMPILER_CREATED,
+ SASS_COMPILER_PARSED,
+ SASS_COMPILER_COMPILED,
+ SASS_COMPILER_RENDERED,
+ SASS_COMPILER_DESTROYED
+};
+
+#define SASS_LOGGER_MONO 1
+#define SASS_LOGGER_COLOR 2
+#define SASS_LOGGER_ASCII 4
+#define SASS_LOGGER_UNICODE 8
+
+// Logging style
+enum SassLoggerStyle {
+ SASS_LOGGER_AUTO = 0,
+ SASS_LOGGER_ASCII_MONO = SASS_LOGGER_ASCII | SASS_LOGGER_MONO,
+ SASS_LOGGER_ASCII_COLOR = SASS_LOGGER_ASCII | SASS_LOGGER_COLOR,
+ SASS_LOGGER_UNICODE_MONO = SASS_LOGGER_UNICODE | SASS_LOGGER_MONO,
+ SASS_LOGGER_UNICODE_COLOR = SASS_LOGGER_UNICODE | SASS_LOGGER_COLOR,
+};
+
+#ifdef __cplusplus
+} // __cplusplus defined.
+#endif
+
+#endif
diff --git a/include/sass/error.h b/include/sass/error.h
new file mode 100644
index 0000000000..7ebb04cc94
--- /dev/null
+++ b/include/sass/error.h
@@ -0,0 +1,40 @@
+#ifndef SASS_C_ERROR_H
+#define SASS_C_ERROR_H
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ // Error related getters (use after compiler was rendered)
+ ADDAPI int ADDCALL sass_error_get_status(const struct SassError* error);
+ ADDAPI char* ADDCALL sass_error_get_json(const struct SassError* error);
+ ADDAPI const char* ADDCALL sass_error_get_what(const struct SassError* error);
+ // ADDAPI const char* ADDCALL sass_error_get_messages(struct SassError* error);
+ // ADDAPI const char* ADDCALL sass_error_get_warnings(struct SassError* error);
+ ADDAPI const char* ADDCALL sass_error_get_formatted(const struct SassError* error);
+
+ // These are here for convenience, could get them also indirectly
+ ADDAPI size_t ADDCALL sass_error_get_line(const struct SassError* error);
+ ADDAPI size_t ADDCALL sass_error_get_column(const struct SassError* error);
+ ADDAPI const char* ADDCALL sass_error_get_path(const struct SassError* error);
+ ADDAPI const char* ADDCALL sass_error_get_content(const struct SassError* error);
+
+ // ADDAPI size_t ADDCALL sass_traces_get_size(struct SassTraces* traces);
+ // ADDAPI struct SassTrace* ADDCALL sass_traces_get_last(struct SassTraces* traces);
+ // ADDAPI struct SassTrace* ADDCALL sass_traces_get_trace(struct SassTraces* traces, size_t i);
+
+ ADDAPI size_t ADDCALL sass_error_count_traces(const struct SassError* error);
+ ADDAPI const struct SassTrace* ADDCALL sass_error_last_trace(const struct SassError* error);
+ ADDAPI const struct SassTrace* ADDCALL sass_error_get_trace(const struct SassError* error, size_t i);
+
+ ADDAPI size_t ADDCALL sass_compiler_count_traces(struct SassCompiler* compiler);
+ ADDAPI const struct SassTrace* ADDCALL sass_compiler_last_trace(struct SassCompiler* compiler);
+ ADDAPI const struct SassTrace* ADDCALL sass_compiler_get_trace(struct SassCompiler* compiler, size_t i);
+
+#ifdef __cplusplus
+} // __cplusplus defined.
+#endif
+
+#endif
diff --git a/include/sass/functions.h b/include/sass/functions.h
index ac47e8ede1..82e9f89c0e 100644
--- a/include/sass/functions.h
+++ b/include/sass/functions.h
@@ -1,135 +1,83 @@
#ifndef SASS_C_FUNCTIONS_H
#define SASS_C_FUNCTIONS_H
-#include
-#include
#include
#ifdef __cplusplus
extern "C" {
#endif
-
-// 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);
-// Typedef helpers for custom importer lists
-typedef struct Sass_Importer (*Sass_Importer_Entry);
-typedef struct Sass_Importer* (*Sass_Importer_List);
-// Typedef defining importer signature and return type
-typedef Sass_Import_List (*Sass_Importer_Fn)
- (const char* url, Sass_Importer_Entry cb, struct Sass_Compiler* compiler);
-
-// Typedef helpers for custom functions lists
-typedef struct Sass_Function (*Sass_Function_Entry);
-typedef struct Sass_Function* (*Sass_Function_List);
-// Typedef defining function signature and return type
-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);
+// ADDAPI struct SassImportList* ADDCALL sass_make_import_list();
+// ADDAPI void ADDCALL sass_delete_import_list(struct SassImportList* list);
+// ADDAPI size_t ADDCALL sass_import_list_size(struct SassImportList* list);
+// ADDAPI struct SassImport* ADDCALL sass_import_list_shift(struct SassImportList* list);
+// ADDAPI void ADDCALL sass_import_list_push(struct SassImportList* list, struct SassImport*);
+// Creator for sass custom importer return argument list
+// ADDAPI struct SassImporterList* ADDCALL sass_make_importer_list ();
+// ADDAPI void ADDCALL sass_delete_importer_list(struct SassImporterList* list);
+// ADDAPI size_t ADDCALL sass_importer_list_size(struct SassImporterList* list);
+// ADDAPI struct SassImporter* ADDCALL sass_importer_list_shift(struct SassImporterList* list);
+// ADDAPI void ADDCALL sass_importer_list_push(struct SassImporterList* list, struct SassImporter*);
// Creators for custom importer callback (with some additional pointer)
// The pointer is mostly used to store the callback into the actual binding
-ADDAPI Sass_Importer_Entry ADDCALL sass_make_importer (Sass_Importer_Fn importer, double priority, void* cookie);
+ ADDAPI struct SassImporter* ADDCALL sass_make_importer(SassImporterLambda importer, double priority, void* cookie);
-// Getters for import function descriptors
-ADDAPI Sass_Importer_Fn ADDCALL sass_importer_get_function (Sass_Importer_Entry cb);
-ADDAPI double ADDCALL sass_importer_get_priority (Sass_Importer_Entry cb);
-ADDAPI void* ADDCALL sass_importer_get_cookie (Sass_Importer_Entry cb);
+ // Getters for import function descriptors
+ ADDAPI SassImporterLambda ADDCALL sass_importer_get_callback(struct SassImporter* cb);
+ ADDAPI double ADDCALL sass_importer_get_priority(struct SassImporter* cb);
+ ADDAPI void* ADDCALL sass_importer_get_cookie(struct SassImporter* cb);
-// Deallocator for associated memory
-ADDAPI void ADDCALL sass_delete_importer (Sass_Importer_Entry cb);
+ // Deallocator for associated memory
+ ADDAPI void ADDCALL sass_delete_importer(struct SassImporter* cb);
-// Creator for sass custom importer return argument list
-ADDAPI Sass_Import_List ADDCALL sass_make_import_list (size_t length);
-// Creator for a single import entry returned by the custom importer inside the list
-ADDAPI Sass_Import_Entry ADDCALL sass_make_import_entry (const char* path, char* source, char* srcmap);
-ADDAPI Sass_Import_Entry ADDCALL sass_make_import (const char* imp_path, const char* abs_base, char* source, char* srcmap);
-// set error message to abort import and to print out a message (path from existing object is used in output)
-ADDAPI Sass_Import_Entry ADDCALL 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
-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);
+ // Creator for a single import entry returned by the custom importer inside the list
+ ADDAPI struct SassImport* ADDCALL sass_make_import(const char* imp_path, const char* abs_base, char* source, char* srcmap, enum SassImportFormat format);
+ // ADDAPI struct SassImport* ADDCALL sass_make_import_error(const char* error);
+
+ // set error message to abort import and to print out a message (path from existing object is used in output)
+ ADDAPI void ADDCALL sass_import_set_error_msg(struct SassImport* import, const char* message, uint32_t line, uint32_t col);
+
+ // Getters for callee entry
+// ADDAPI const char* ADDCALL sass_callee_get_name (struct SassCallee*);
+// ADDAPI const char* ADDCALL sass_callee_get_path (struct SassCallee*);
+// ADDAPI uint32_t ADDCALL sass_callee_get_line (struct SassCallee*);
+// ADDAPI uint32_t ADDCALL sass_callee_get_column (struct SassCallee*);
+// ADDAPI enum Sass_Callee_Type ADDCALL sass_callee_get_type (struct SassCallee*);
// 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*);
+// ADDAPI struct SassValue* ADDCALL sass_env_get_lexical (struct SassCompiler*, const char*);
+ADDAPI void ADDCALL sass_env_set_lexical (struct SassCompiler*, const char*, struct SassValue*);
+// ADDAPI struct SassValue* ADDCALL sass_env_get_local (struct SassCompiler*, const char*);
+// ADDAPI void ADDCALL sass_env_set_local (struct SassCompiler*, const char*, struct SassValue*);
+// ADDAPI struct SassValue* ADDCALL sass_env_get_global (struct SassCompiler*, const char*);
+ADDAPI void ADDCALL sass_env_set_global (struct SassCompiler*, const char*, struct SassValue*);
// 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);
-ADDAPI const char* ADDCALL sass_import_get_source (Sass_Import_Entry);
-ADDAPI const char* ADDCALL 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
-ADDAPI char* ADDCALL sass_import_take_source (Sass_Import_Entry);
-ADDAPI char* ADDCALL sass_import_take_srcmap (Sass_Import_Entry);
+ADDAPI const char* ADDCALL sass_import_get_imp_path (struct SassImport*);
+ADDAPI const char* ADDCALL sass_import_get_abs_path (struct SassImport*);
+// ADDAPI const char* ADDCALL sass_import_get_source (struct SassImport*);
+// ADDAPI const char* ADDCALL sass_import_get_srcmap (struct SassImport*);
+ADDAPI enum SassImportFormat ADDCALL sass_import_get_type(struct SassImport*);
+
// Getters from import error entry
-ADDAPI size_t ADDCALL sass_import_get_error_line (Sass_Import_Entry);
-ADDAPI size_t ADDCALL sass_import_get_error_column (Sass_Import_Entry);
-ADDAPI const char* ADDCALL sass_import_get_error_message (Sass_Import_Entry);
+// ADDAPI uint32_t ADDCALL sass_import_get_error_line (struct SassImport*);
+// ADDAPI uint32_t ADDCALL sass_import_get_error_column (struct SassImport*);
+ADDAPI const char* ADDCALL sass_import_get_error_message (struct SassImport*);
-// Deallocator for associated memory (incl. entries)
-ADDAPI void ADDCALL sass_delete_import_list (Sass_Import_List);
// Just in case we have some stray import structs
-ADDAPI void ADDCALL sass_delete_import (Sass_Import_Entry);
-
-
+ADDAPI void ADDCALL sass_delete_import(struct SassImport*);
-// 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);
-ADDAPI void ADDCALL sass_function_set_list_entry(Sass_Function_List list, size_t pos, Sass_Function_Entry cb);
+ADDAPI struct SassFunction* ADDCALL sass_make_function (const char* signature, SassFunctionLambda cb, void* cookie);
+ADDAPI void ADDCALL sass_delete_function (struct SassFunction* entry);
// 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);
+ADDAPI const char* ADDCALL sass_function_get_signature (struct SassFunction* cb);
+ADDAPI SassFunctionLambda ADDCALL sass_function_get_function (struct SassFunction* cb);
+ADDAPI void* ADDCALL sass_function_get_cookie (struct SassFunction* cb);
#ifdef __cplusplus
diff --git a/include/sass/fwdecl.h b/include/sass/fwdecl.h
new file mode 100644
index 0000000000..b3d7ac9eaf
--- /dev/null
+++ b/include/sass/fwdecl.h
@@ -0,0 +1,32 @@
+#ifndef SASS_C_FWDECL_H
+#define SASS_C_FWDECL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Forward declare structs
+struct SassTrace;
+struct SassError;
+struct SassCompiler;
+struct SassFunction;
+
+struct SassSource;
+struct SassSrcSpan;
+
+struct SassImport;
+struct SassImporter;
+
+struct SassImportList;
+struct SassImporterList;
+struct SassFunctionList;
+
+// Typedef defining importer/function callback signature and return type
+typedef struct SassImportList* (*SassImporterLambda)(const char* url, struct SassImporter* cb, struct SassCompiler* compiler);
+typedef struct SassValue* (*SassFunctionLambda)(struct SassValue*, struct SassFunction* cb, struct SassCompiler* compiler);
+
+#ifdef __cplusplus
+} // __cplusplus defined.
+#endif
+
+#endif
diff --git a/include/sass/import.h b/include/sass/import.h
new file mode 100644
index 0000000000..882ee450f9
--- /dev/null
+++ b/include/sass/import.h
@@ -0,0 +1,37 @@
+#ifndef SASS_C_IMPORT_H
+#define SASS_C_IMPORT_H
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ // Create an import entry by reading from `stdin`
+ ADDAPI struct SassImport* ADDCALL sass_make_stdin_import(const char* imp_path);
+
+ // Crate import entry for input path (returns nullptr if not found or unreadable)
+ // Will read the file without LibSass internal path resolving (relative to CWD)!
+ // ADDAPI struct SassImport* ADDCALL sass_make_file_import(struct SassCompiler* compiler, const char* imp_path);
+
+ // Crate an import entry for the passed data content and optional import path.
+ // The import path is optional and defaults to `sass://data` if `null` is passed.
+ // ADDAPI struct SassImport* ADDCALL sass_make_data_import(char* content, const char* imp_path);
+
+ // Note: compiler ones do error reporting, since file loading my error ...
+ // One solution would be to postpone the file loading into the parse stage
+
+ // Crate an import entry for the passed input path
+ ADDAPI struct SassImport* ADDCALL sass_make_file_import(const char* imp_path);
+
+ // Crate an import entry for the passed input path
+ ADDAPI struct SassImport* ADDCALL sass_make_content_import(char* content, const char* imp_path);
+
+ // Set specific import format for the given import
+ ADDAPI void ADDCALL sass_import_set_format(struct SassImport* import, enum SassImportFormat format);
+
+#ifdef __cplusplus
+} // __cplusplus defined.
+#endif
+
+#endif
diff --git a/include/sass/lists.h b/include/sass/lists.h
new file mode 100644
index 0000000000..c23ea254e8
--- /dev/null
+++ b/include/sass/lists.h
@@ -0,0 +1,39 @@
+#ifndef SASS_C_LISTS_H
+#define SASS_C_LISTS_H
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ struct SassImportList;
+ struct SassImporterList;
+
+ // Creator for sass custom importer return argument list
+ ADDAPI struct SassImportList* ADDCALL sass_make_import_list();
+ ADDAPI void ADDCALL sass_delete_import_list(struct SassImportList* list);
+ ADDAPI size_t ADDCALL sass_import_list_size(struct SassImportList* list);
+
+ ADDAPI struct SassImport* ADDCALL sass_import_list_shift(struct SassImportList* list);
+ ADDAPI void ADDCALL sass_import_list_push(struct SassImportList* list, struct SassImport*);
+
+ // Creator for sass plugin loading return arguments
+ ADDAPI struct SassImporterList* ADDCALL sass_make_importer_list();
+ ADDAPI void ADDCALL sass_delete_importer_list(struct SassImporterList* list);
+ ADDAPI size_t ADDCALL sass_importer_list_size(struct SassImporterList* list);
+ ADDAPI struct SassImporter* ADDCALL sass_importer_list_shift(struct SassImporterList* list);
+ ADDAPI void ADDCALL sass_importer_list_push(struct SassImporterList* list, struct SassImporter*);
+
+ // Creators for sass function list and function descriptors
+ ADDAPI struct SassFunctionList* ADDCALL sass_make_function_list();
+ ADDAPI void ADDCALL sass_delete_function_list(struct SassFunctionList* list);
+ ADDAPI size_t ADDCALL sass_function_list_size(struct SassFunctionList* list);
+ ADDAPI struct SassFunction* ADDCALL sass_function_list_shift(struct SassFunctionList* list);
+ ADDAPI void ADDCALL sass_function_list_push(struct SassFunctionList* list, struct SassFunction*);
+
+#ifdef __cplusplus
+} // __cplusplus defined.
+#endif
+
+#endif
diff --git a/include/sass/traces.h b/include/sass/traces.h
new file mode 100644
index 0000000000..0ca8dd917a
--- /dev/null
+++ b/include/sass/traces.h
@@ -0,0 +1,50 @@
+#ifndef SASS_C_TRACES_H
+#define SASS_C_TRACES_H
+
+#include
+
+struct SassTrace;
+struct SassTraces;
+struct SassSrcSpan;
+struct SassSource;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ // Traces must be got directly from the underlying object.
+ // We expose traces during eval (BackTraces) and on when handling
+ // error (StackTraces). We can't convert a vector to
+ // vector, because they are not covariant. Easiest to add
+ // two implementation to fetch a trace and make the cast there.
+
+ // ADDAPI size_t ADDCALL sass_traces_get_size(struct SassTraces* traces);
+ // ADDAPI struct SassTrace* ADDCALL sass_traces_get_last(struct SassTraces* traces);
+ // ADDAPI struct SassTrace* ADDCALL sass_traces_get_trace(struct SassTraces* traces, size_t i);
+
+ // ADDAPI size_t ADDCALL sass_traces_get_size(struct SassTraces* traces);
+
+ ADDAPI const char* ADDCALL sass_trace_get_name(struct SassTrace* trace);
+ ADDAPI bool ADDCALL sass_trace_get_was_fncall(struct SassTrace* trace);
+ ADDAPI const struct SassSrcSpan* ADDCALL sass_trace_get_srcspan(struct SassTrace* trace);
+
+ ADDAPI size_t ADDCALL sass_srcspan_get_src_ln(struct SassSrcSpan* pstate);
+ ADDAPI size_t ADDCALL sass_srcspan_get_src_col(struct SassSrcSpan* pstate);
+ ADDAPI size_t ADDCALL sass_srcspan_get_span_ln(struct SassSrcSpan* pstate);
+ ADDAPI size_t ADDCALL sass_srcspan_get_span_col(struct SassSrcSpan* pstate);
+ ADDAPI size_t ADDCALL sass_srcspan_get_src_line(struct SassSrcSpan* pstate);
+ ADDAPI size_t ADDCALL sass_srcspan_get_src_column(struct SassSrcSpan* pstate);
+
+ ADDAPI struct SassSource* ADDCALL sass_srcspan_get_source(struct SassSrcSpan* pstate);
+
+ ADDAPI const char* ADDCALL sass_source_get_abs_path(struct SassSource* source);
+ ADDAPI const char* ADDCALL sass_source_get_imp_path(struct SassSource* source);
+ ADDAPI const char* ADDCALL sass_source_get_content(struct SassSource* source);
+ ADDAPI const char* ADDCALL sass_source_get_srcmap(struct SassSource* source);
+
+
+#ifdef __cplusplus
+} // __cplusplus defined.
+#endif
+
+#endif
diff --git a/include/sass/values.h b/include/sass/values.h
index 9832038b71..ee6ec1c913 100644
--- a/include/sass/values.h
+++ b/include/sass/values.h
@@ -1,20 +1,30 @@
#ifndef SASS_C_VALUES_H
#define SASS_C_VALUES_H
-#include
-#include
#include
+// Implementation Notes: While I was refactoring for LibSass 4.0, I figured we should get
+// rid of all intermediate structs that we created when converting back and forth from C
+// to CPP. I researched several approaches and will document my findings here. C only knows
+// about structs, therefore we can export any struct-ptr from C++ directly to C. This would
+// have been the most desirable approach, since any class in C++ can be turned into a struct
+// but there are limitations. Mainly we cannot export a name-spaced struct, so we would need to
+// define all our "classes" on the root namespace. The main benefit would be that we could
+// inspect objects during debugging if linking statically. Another approach would be to wrap
+// a ValueObj inside a struct. My final conclusion was to simply create an "anonymous" struct
+// on the C-API side, which has no implementation at all. In the actual implementation we
+// just trust the pointer to be of the type it should be, or you get undefined behavior.
+// Since underlying the pointer is a SharedObj, we know how to handle the reference count
+// for memory management when destruction is requested from C-API. Whenever the created value
+// is a e.g. added to container, the actual destruction of the original is skipped.
+
#ifdef __cplusplus
extern "C" {
#endif
-// Forward declaration
-union Sass_Value;
-
// Type for Sass values
-enum Sass_Tag {
+enum SassValueType {
SASS_BOOLEAN,
SASS_NUMBER,
SASS_COLOR,
@@ -23,120 +33,154 @@ enum Sass_Tag {
SASS_MAP,
SASS_NULL,
SASS_ERROR,
- SASS_WARNING
+ SASS_WARNING,
+ SASS_FUNCTION,
+ SASS_PARENT,
};
-// Tags for denoting Sass list separators
-enum Sass_Separator {
+// List Separators
+enum SassSeparator {
SASS_COMMA,
SASS_SPACE,
- // only used internally to represent a hash map before evaluation
- // otherwise we would be too early to check for duplicate keys
- SASS_HASH
+ // A separator that hasn't yet been determined.
+ // Singleton lists and empty lists don't have separators defined. This means
+ // that list functions will prefer other lists' separators if possible.
+ SASS_UNDEF,
};
// Value Operators
-enum Sass_OP {
- AND, OR, // logical connectives
+enum SassOperator {
+ OR, AND, // logical connectives
EQ, NEQ, GT, GTE, LT, LTE, // arithmetic relations
ADD, SUB, MUL, DIV, MOD, // arithmetic functions
- NUM_OPS // so we know how big to make the op table
+ IESEQ // special IE single equal
};
// Creator functions for all value types
-ADDAPI union Sass_Value* ADDCALL sass_make_null (void);
-ADDAPI union Sass_Value* ADDCALL sass_make_boolean (bool val);
-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, 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);
+ADDAPI struct SassValue* ADDCALL sass_make_null (void);
+ADDAPI struct SassValue* ADDCALL sass_make_boolean (bool val);
+ADDAPI struct SassValue* ADDCALL sass_make_string (const char* val, bool is_quoted);
+ADDAPI struct SassValue* ADDCALL sass_make_number (double val, const char* unit);
+
+ADDAPI struct SassValue* ADDCALL sass_make_number2(double val, const char* unit);
+
+
+ADDAPI struct SassValue* ADDCALL sass_make_color (double r, double g, double b, double a);
+ADDAPI struct SassValue* ADDCALL sass_make_list (enum SassSeparator sep, bool is_bracketed);
+ADDAPI struct SassValue* ADDCALL sass_make_map ();
+ADDAPI struct SassValue* ADDCALL sass_make_error (const char* msg);
+ADDAPI struct SassValue* ADDCALL sass_make_warning (const char* msg);
// Generic destructor function for all types
// Will release memory of all associated Sass_Values
// Means we will delete recursively for lists and maps
-ADDAPI void ADDCALL sass_delete_value (union Sass_Value* val);
+ADDAPI void ADDCALL sass_delete_value(struct SassValue* val);
// Make a deep cloned copy of the given sass value
-ADDAPI union Sass_Value* ADDCALL sass_clone_value (const union Sass_Value* val);
+ADDAPI struct SassValue* ADDCALL sass_clone_value (struct SassValue* val);
// Execute an operation for two Sass_Values and return the result as a Sass_Value too
-ADDAPI union Sass_Value* ADDCALL sass_value_op (enum Sass_OP op, const union Sass_Value* a, const union Sass_Value* b);
+ADDAPI struct SassValue* ADDCALL sass_value_op (enum SassOperator op, struct SassValue* a, struct SassValue* b);
// Stringify a Sass_Values and also return the result as a Sass_Value (of type STRING)
-ADDAPI union Sass_Value* ADDCALL sass_value_stringify (const union Sass_Value* a, bool compressed, int precision);
+ADDAPI struct SassValue* ADDCALL sass_value_stringify (struct SassValue* a, bool compressed, int precision);
// Return the sass tag for a generic sass value
// Check is needed before accessing specific values!
-ADDAPI enum Sass_Tag ADDCALL sass_value_get_tag (const union Sass_Value* v);
+ADDAPI enum SassValueType ADDCALL sass_value_get_tag (struct SassValue* v);
// Check value to be of a specific type
// Can also be used before accessing properties!
-ADDAPI bool ADDCALL sass_value_is_null (const union Sass_Value* v);
-ADDAPI bool ADDCALL sass_value_is_number (const union Sass_Value* v);
-ADDAPI bool ADDCALL sass_value_is_string (const union Sass_Value* v);
-ADDAPI bool ADDCALL sass_value_is_boolean (const union Sass_Value* v);
-ADDAPI bool ADDCALL sass_value_is_color (const union Sass_Value* v);
-ADDAPI bool ADDCALL sass_value_is_list (const union Sass_Value* v);
-ADDAPI bool ADDCALL sass_value_is_map (const union Sass_Value* v);
-ADDAPI bool ADDCALL sass_value_is_error (const union Sass_Value* v);
-ADDAPI bool ADDCALL sass_value_is_warning (const union Sass_Value* v);
+ADDAPI bool ADDCALL sass_value_is_null (struct SassValue* v);
+ADDAPI bool ADDCALL sass_value_is_number (struct SassValue* v);
+ADDAPI bool ADDCALL sass_value_is_string (struct SassValue* v);
+ADDAPI bool ADDCALL sass_value_is_boolean (struct SassValue* v);
+ADDAPI bool ADDCALL sass_value_is_color (struct SassValue* v);
+ADDAPI bool ADDCALL sass_value_is_list (struct SassValue* v);
+ADDAPI bool ADDCALL sass_value_is_map (struct SassValue* v);
+ADDAPI bool ADDCALL sass_value_is_error (struct SassValue* v);
+ADDAPI bool ADDCALL sass_value_is_warning (struct SassValue* v);
// Getters and setters for Sass_Number
-ADDAPI double ADDCALL sass_number_get_value (const union Sass_Value* v);
-ADDAPI void ADDCALL sass_number_set_value (union Sass_Value* v, double value);
-ADDAPI const char* ADDCALL sass_number_get_unit (const union Sass_Value* v);
-ADDAPI void ADDCALL sass_number_set_unit (union Sass_Value* v, char* unit);
+ADDAPI double ADDCALL sass_number_get_value (struct SassValue* v);
+ADDAPI void ADDCALL sass_number_set_value (struct SassValue* v, double value);
+ADDAPI const char* ADDCALL sass_number_get_unit (struct SassValue* v);
+ADDAPI void ADDCALL sass_number_set_unit (struct SassValue* v, const char* unit);
+ADDAPI void ADDCALL sass_number_normalize(struct SassValue* v); // What does it do?
+ADDAPI void ADDCALL sass_number_reduce(struct SassValue* v);
// Getters and setters for Sass_String
-ADDAPI const char* ADDCALL sass_string_get_value (const union Sass_Value* v);
-ADDAPI void ADDCALL sass_string_set_value (union Sass_Value* v, char* value);
-ADDAPI bool ADDCALL sass_string_is_quoted(const union Sass_Value* v);
-ADDAPI void ADDCALL sass_string_set_quoted(union Sass_Value* v, bool quoted);
+ADDAPI const char* ADDCALL sass_string_get_value (struct SassValue* v);
+ADDAPI void ADDCALL sass_string_set_value (struct SassValue* v, char* value);
+ADDAPI bool ADDCALL sass_string_is_quoted(struct SassValue* v);
+ADDAPI void ADDCALL sass_string_set_quoted(struct SassValue* v, bool quoted);
// Getters and setters for Sass_Boolean
-ADDAPI bool ADDCALL sass_boolean_get_value (const union Sass_Value* v);
-ADDAPI void ADDCALL sass_boolean_set_value (union Sass_Value* v, bool value);
+ADDAPI bool ADDCALL sass_boolean_get_value (struct SassValue* v);
+ADDAPI void ADDCALL sass_boolean_set_value (struct SassValue* v, bool value);
// Getters and setters for Sass_Color
-ADDAPI double ADDCALL sass_color_get_r (const union Sass_Value* v);
-ADDAPI void ADDCALL sass_color_set_r (union Sass_Value* v, double r);
-ADDAPI double ADDCALL sass_color_get_g (const union Sass_Value* v);
-ADDAPI void ADDCALL sass_color_set_g (union Sass_Value* v, double g);
-ADDAPI double ADDCALL sass_color_get_b (const union Sass_Value* v);
-ADDAPI void ADDCALL sass_color_set_b (union Sass_Value* v, double b);
-ADDAPI double ADDCALL sass_color_get_a (const union Sass_Value* v);
-ADDAPI void ADDCALL sass_color_set_a (union Sass_Value* v, double a);
-
-// Getter for the number of items in list
-ADDAPI size_t ADDCALL sass_list_get_length (const union Sass_Value* v);
+ADDAPI double ADDCALL sass_color_get_r (struct SassValue* v);
+ADDAPI void ADDCALL sass_color_set_r (struct SassValue* v, double r);
+ADDAPI double ADDCALL sass_color_get_g (struct SassValue* v);
+ADDAPI void ADDCALL sass_color_set_g (struct SassValue* v, double g);
+ADDAPI double ADDCALL sass_color_get_b (struct SassValue* v);
+ADDAPI void ADDCALL sass_color_set_b (struct SassValue* v, double b);
+ADDAPI double ADDCALL sass_color_get_a (struct SassValue* v);
+ADDAPI void ADDCALL sass_color_set_a (struct SassValue* v, double a);
+
+ADDAPI size_t ADDCALL sass_list_get_size(struct SassValue* list);
+ADDAPI void ADDCALL sass_list_push(struct SassValue* list, struct SassValue* value);
+ADDAPI struct SassValue* ADDCALL sass_list_at(struct SassValue* list, size_t i);
+ADDAPI struct SassValue* ADDCALL sass_list_pop(struct SassValue* list, struct SassValue* value);
+ADDAPI struct SassValue* ADDCALL sass_list_shift(struct SassValue* list, struct SassValue* value);
+
+
+
// 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);
+ADDAPI enum SassSeparator ADDCALL sass_list_get_separator (struct SassValue* v);
+ADDAPI void ADDCALL sass_list_set_separator (struct SassValue* v, enum SassSeparator value);
+ADDAPI bool ADDCALL sass_list_get_is_bracketed (struct SassValue* v);
+ADDAPI void ADDCALL sass_list_set_is_bracketed (struct SassValue* 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);
+ADDAPI struct SassValue* ADDCALL sass_list_get_value (struct SassValue* v, size_t i);
+ADDAPI void ADDCALL sass_list_set_value (struct SassValue* v, size_t i, struct SassValue* value);
// Getter for the number of items in map
-ADDAPI size_t ADDCALL sass_map_get_length (const union Sass_Value* v);
+// ADDAPI size_t ADDCALL sass_map_get_size (struct SassValue* v);
+
+ADDAPI void ADDCALL sass_map_set(struct SassValue* m, struct SassValue* k, struct SassValue* v);
+
+struct SassMapIterator;
+
+ADDAPI struct SassMapIterator* ADDCALL sass_map_make_iterator(struct SassValue* map);
+ADDAPI void ADDCALL sass_map_delete_iterator(struct SassMapIterator* it);
+ADDAPI bool ADDCALL sass_map_iterator_exhausted(struct SassMapIterator* it);
+ADDAPI struct SassValue* ADDCALL sass_map_iterator_get_key(struct SassMapIterator* it);
+ADDAPI struct SassValue* ADDCALL sass_map_iterator_get_value(struct SassMapIterator* it);
+ADDAPI void ADDCALL sass_map_iterator_next(struct SassMapIterator* it);
+
+// sass_map_get_iterator();
+// sass_map_iterator_next(it);
+
+
+ADDAPI void ADDCALL sass_map_set(struct SassValue* m, struct SassValue* k, struct SassValue* v);
+ADDAPI struct SassValue* ADDCALL sass_map_get(struct SassValue* m, struct SassValue* k);
+
+
// Getters and setters for Sass_Map keys and values
-ADDAPI union Sass_Value* ADDCALL sass_map_get_key (const union Sass_Value* v, size_t i);
-ADDAPI void ADDCALL sass_map_set_key (union Sass_Value* v, size_t i, union Sass_Value*);
-ADDAPI union Sass_Value* ADDCALL sass_map_get_value (const union Sass_Value* v, size_t i);
-ADDAPI void ADDCALL sass_map_set_value (union Sass_Value* v, size_t i, union Sass_Value*);
+//ADDAPI struct SassValue* ADDCALL sass_map_get_key (struct SassValue* v, size_t i);
+//ADDAPI void ADDCALL sass_map_set_key (struct SassValue* v, size_t i, struct SassValue*);
+//ADDAPI struct SassValue* ADDCALL sass_map_get_value (struct SassValue* v, size_t i);
+//ADDAPI void ADDCALL sass_map_set_value (struct SassValue* v, size_t i, struct SassValue*);
// Getters and setters for Sass_Error
-ADDAPI char* ADDCALL sass_error_get_message (const union Sass_Value* v);
-ADDAPI void ADDCALL sass_error_set_message (union Sass_Value* v, char* msg);
+ADDAPI const char* ADDCALL sass_error_get_message (struct SassValue* v);
+ADDAPI void ADDCALL sass_error_set_message (struct SassValue* v, const char* msg);
// Getters and setters for Sass_Warning
-ADDAPI char* ADDCALL sass_warning_get_message (const union Sass_Value* v);
-ADDAPI void ADDCALL sass_warning_set_message (union Sass_Value* v, char* msg);
+ADDAPI const char* ADDCALL sass_warning_get_message (struct SassValue* v);
+ADDAPI void ADDCALL sass_warning_set_message (struct SassValue* v, const char* msg);
#ifdef __cplusplus
} // __cplusplus defined.
diff --git a/include/sass/version.h b/include/sass/version.h
index 56ea016a25..e3cd91ca68 100644
--- a/include/sass/version.h
+++ b/include/sass/version.h
@@ -1,12 +1,12 @@
-#ifndef SASS_VERSION_H
-#define SASS_VERSION_H
+#ifndef SASS_C_VERSION_H
+#define SASS_C_VERSION_H
#ifndef LIBSASS_VERSION
#define LIBSASS_VERSION "[NA]"
#endif
#ifndef LIBSASS_LANGUAGE_VERSION
-#define LIBSASS_LANGUAGE_VERSION "3.5"
+#define LIBSASS_LANGUAGE_VERSION "3.9"
#endif
#endif
diff --git a/include/sass/version.h.in b/include/sass/version.h.in
index b8d4072d4d..8d3f35b04d 100644
--- a/include/sass/version.h.in
+++ b/include/sass/version.h.in
@@ -1,12 +1,12 @@
-#ifndef SASS_VERSION_H
-#define SASS_VERSION_H
+#ifndef SASS_C_VERSION_H
+#define SASS_C_VERSION_H
#ifndef LIBSASS_VERSION
#define LIBSASS_VERSION "@PACKAGE_VERSION@"
#endif
#ifndef LIBSASS_LANGUAGE_VERSION
-#define LIBSASS_LANGUAGE_VERSION "3.5"
+#define LIBSASS_LANGUAGE_VERSION "3.7"
#endif
#endif
diff --git a/include/sass2scss.h b/include/sass2scss.h
deleted file mode 100644
index 8736b2cb9d..0000000000
--- a/include/sass2scss.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/**
- * sass2scss
- * Licensed under the MIT License
- * Copyright (c) Marcel Greter
- */
-
-#ifndef SASS2SCSS_H
-#define SASS2SCSS_H
-
-#ifdef _WIN32
-
- /* You should define ADD_EXPORTS *only* when building the DLL. */
- #ifdef ADD_EXPORTS
- #define ADDAPI __declspec(dllexport)
- #define ADDCALL __cdecl
- #else
- #define ADDAPI
- #define ADDCALL
- #endif
-
-#else /* _WIN32 not defined. */
-
- /* Define with no value on non-Windows OSes. */
- #define ADDAPI
- #define ADDCALL
-
-#endif
-
-#ifdef __cplusplus
-
-#include
-#include
-#include
-#include
-#include
-
-#ifndef SASS2SCSS_VERSION
-// Hardcode once the file is copied from
-// https://github.com/mgreter/sass2scss
-#define SASS2SCSS_VERSION "1.1.1"
-#endif
-
-// add namespace for c++
-namespace Sass
-{
-
- // pretty print options
- const int SASS2SCSS_PRETTIFY_0 = 0;
- const int SASS2SCSS_PRETTIFY_1 = 1;
- const int SASS2SCSS_PRETTIFY_2 = 2;
- const int SASS2SCSS_PRETTIFY_3 = 3;
-
- // remove one-line comment
- const int SASS2SCSS_KEEP_COMMENT = 32;
- // remove multi-line comments
- const int SASS2SCSS_STRIP_COMMENT = 64;
- // convert one-line to multi-line
- const int SASS2SCSS_CONVERT_COMMENT = 128;
-
- // String for finding something interesting
- const std::string SASS2SCSS_FIND_WHITESPACE = " \t\n\v\f\r";
-
- // converter struct
- // holding all states
- struct converter
- {
- // bit options
- int options;
- // is selector
- bool selector;
- // concat lists
- bool comma;
- // has property
- bool property;
- // has semicolon
- bool semicolon;
- // comment context
- std::string comment;
- // flag end of file
- bool end_of_file;
- // whitespace buffer
- std::string whitespace;
- // context/block stack
- std::stack indents;
- };
-
- // function only available in c++ code
- char* sass2scss (const std::string& sass, const int options);
-
-}
-// EO namespace
-
-// declare for c
-extern "C" {
-#endif
-
- // prettyfy print options
- #define SASS2SCSS_PRETTIFY_0 0
- #define SASS2SCSS_PRETTIFY_1 1
- #define SASS2SCSS_PRETTIFY_2 2
- #define SASS2SCSS_PRETTIFY_3 3
-
- // keep one-line comments
- #define SASS2SCSS_KEEP_COMMENT 32
- // remove multi-line comments
- #define SASS2SCSS_STRIP_COMMENT 64
- // convert one-line to multi-line
- #define SASS2SCSS_CONVERT_COMMENT 128
-
- // available to c and c++ code
- ADDAPI char* ADDCALL sass2scss (const char* sass, const int options);
-
- // Get compiled sass2scss version
- ADDAPI const char* ADDCALL sass2scss_version(void);
-
-#ifdef __cplusplus
-} // __cplusplus defined.
-#endif
-
-#endif
\ No newline at end of file
diff --git a/script/bootstrap b/script/bootstrap
index b0df8b2367..cb814484a3 100755
--- a/script/bootstrap
+++ b/script/bootstrap
@@ -7,11 +7,11 @@ script/branding
: ${SASS_SASSC_PATH:="sassc" }
if [ ! -d $LIBSASS_SPEC_PATH ]; then
- git clone https://github.com/mgreter/libsass-spec.git $LIBSASS_SPEC_PATH
+ git clone https://github.com/mgreter/libsass-spec.git --branch refactor/libsass-4-alpha $LIBSASS_SPEC_PATH
fi
if [ ! -d $SASS_SPEC_PATH ]; then
- git clone https://github.com/sass/sass-spec.git $SASS_SPEC_PATH
+ git clone https://github.com/mgreter/sass-spec.git --branch refactor/libsass-4-alpha $SASS_SPEC_PATH
fi
if [ ! -d $SASS_SASSC_PATH ]; then
- git clone https://github.com/sass/sassc.git $SASS_SASSC_PATH
+ git clone https://github.com/mgreter/sassc.git --branch refactor/libsass-4-alpha $SASS_SASSC_PATH
fi
diff --git a/script/ci-build-libsass b/script/ci-build-libsass
index d4ade4eb73..c26191388f 100755
--- a/script/ci-build-libsass
+++ b/script/ci-build-libsass
@@ -58,9 +58,9 @@ fi
if [ "x$CC" == "xclang" ]; then
if [ "x$COVERAGE" != "xyes" ]; then
if [ "$TRAVIS_OS_NAME" == "linux" ]; then
- export EXTRA_CFLAGS="$EXTRA_CFLAGS -fsanitize=address"
- export EXTRA_CXXFLAGS="$EXTRA_CXXFLAGS -fsanitize=address"
- export EXTRA_LDFLAGS="$EXTRA_LDFLAGS -fsanitize=address"
+ export EXTRA_CFLAGS="$EXTRA_CFLAGS -g -fsanitize=address"
+ export EXTRA_CXXFLAGS="$EXTRA_CXXFLAGS -g -fsanitize=address"
+ export EXTRA_LDFLAGS="$EXTRA_LDFLAGS -g -fsanitize=address"
fi
fi
fi
@@ -90,8 +90,8 @@ else
make $MAKE_OPTS clean
# Run C++ unit tests
- make -C test clean
- make -C test test
+ # make -C test clean
+ # make -C test test
fi
@@ -107,28 +107,42 @@ if [ "$CONTINUOUS_INTEGRATION" == "true" ] && [ "$TRAVIS_PULL_REQUEST" != "false
([ "$TRAVIS_OS_NAME" == "linux" ] || [ "$TRAVIS_OS_NAME" == "osx" ] || [ "$TRAVIS_OS_NAME" == "cygwin" ]);
then
- echo "Fetching PR $TRAVIS_PULL_REQUEST"
+ if [ "x$TRAVIS_PULL_REQUEST" != "2918" ]; then
- JSON=$(curl -L -sS https://api.github.com/repos/sass/libsass/pulls/$TRAVIS_PULL_REQUEST)
+ echo "Checking out refactoring branch"
+ cd sass-spec
+ if ! git config remote.mgreter.url > /dev/null; then
+ git remote add mgreter https://github.com/mgreter/sass-spec.git -f
+ git checkout -b refactoring mgreter/feature/libsass-parser-backport
+ fi
+ cd ..
+ make $MAKE_OPTS test_probe
- if [[ $JSON =~ "API rate limit exceeded" ]];
- then
- echo "Travis rate limit on github exceeded"
- echo "Retrying via 'special purpose proxy'"
- JSON=$(curl -L -sS https://github-api-reverse-proxy.herokuapp.com/repos/sass/libsass/pulls/$TRAVIS_PULL_REQUEST)
- fi
+ else
- RE_SPEC_PR="sass\/sass-spec(#|\/pull\/)([0-9]+)"
+ echo "Fetching PR $TRAVIS_PULL_REQUEST"
- if [[ $JSON =~ $RE_SPEC_PR ]];
- then
- SPEC_PR="${BASH_REMATCH[2]}"
- echo "Fetching Sass Spec PR $SPEC_PR"
- git -C sass-spec fetch -u origin pull/$SPEC_PR/head:ci-spec-pr-$SPEC_PR
- git -C sass-spec checkout --force ci-spec-pr-$SPEC_PR
- make $MAKE_OPTS test_probe
- else
- make $MAKE_OPTS test_probe
+ JSON=$(curl -L -sS https://api.github.com/repos/sass/libsass/pulls/$TRAVIS_PULL_REQUEST)
+
+ if [[ $JSON =~ "API rate limit exceeded" ]];
+ then
+ echo "Travis rate limit on github exceeded"
+ echo "Retrying via 'special purpose proxy'"
+ JSON=$(curl -L -sS https://github-api-reverse-proxy.herokuapp.com/repos/sass/libsass/pulls/$TRAVIS_PULL_REQUEST)
+ fi
+
+ RE_SPEC_PR="sass\/sass-spec(#|\/pull\/)([0-9]+)"
+
+ if [[ $JSON =~ $RE_SPEC_PR ]];
+ then
+ SPEC_PR="${BASH_REMATCH[2]}"
+ echo "Fetching Sass Spec PR $SPEC_PR"
+ git -C sass-spec fetch -u origin pull/$SPEC_PR/head:ci-spec-pr-$SPEC_PR
+ git -C sass-spec checkout --force ci-spec-pr-$SPEC_PR
+ make $MAKE_OPTS test_probe
+ else
+ make $MAKE_OPTS test_probe
+ fi
fi
else
make $MAKE_OPTS test_probe
diff --git a/script/ci-build-plugin b/script/ci-build-plugin
index 533a3f512e..0fc4a9ea4e 100755
--- a/script/ci-build-plugin
+++ b/script/ci-build-plugin
@@ -34,8 +34,10 @@ fi
mkdir -p plugins
if [ ! -d plugins/libsass-${PLUGIN} ] ; then
- if [ "$PLUGIN" == "tests" ]; then
- git clone https://github.com/mgreter/libsass-${PLUGIN} plugins/libsass-${PLUGIN} --branch master
+ if [ "$PLUGIN" == "math" ]; then
+ git clone https://github.com/mgreter/libsass-${PLUGIN} plugins/libsass-${PLUGIN} --branch feature/libsass-3.7
+ elif [ "$PLUGIN" == "tests" ]; then
+ git clone https://github.com/mgreter/libsass-${PLUGIN} plugins/libsass-${PLUGIN} --branch feature/libsass-4.0
else
git clone https://github.com/mgreter/libsass-${PLUGIN} plugins/libsass-${PLUGIN}
fi
diff --git a/script/ci-report-coverage b/script/ci-report-coverage
index 495cb05cbd..a5a42ec192 100755
--- a/script/ci-report-coverage
+++ b/script/ci-report-coverage
@@ -19,11 +19,9 @@ if [ "x$COVERAGE" = "xyes" ]; then
--exclude src/cencode.c
--exclude src/b64
--exclude src/utf8
- --exclude src/utf8_string.hpp
+ --exclude src/unicode.hpp
--exclude src/utf8.h
- --exclude src/utf8_string.cpp
- --exclude src/sass2scss.h
- --exclude src/sass2scss.cpp
+ --exclude src/unicode.cpp
--exclude src/test
--exclude src/posix
--exclude src/debugger.hpp"
diff --git a/src/GNUmakefile.am b/src/GNUmakefile.am
index 9b0e6a99b3..71a834de3a 100644
--- a/src/GNUmakefile.am
+++ b/src/GNUmakefile.am
@@ -38,8 +38,7 @@ nodist_EXTRA_libsass_la_SOURCES = non-existent-file-to-force-CXX-linking.cxx
endif
endif
-include_HEADERS = $(top_srcdir)/include/sass.h \
- $(top_srcdir)/include/sass2scss.h
+include_HEADERS = $(top_srcdir)/include/sass.h
sass_includedir = $(includedir)/sass
diff --git a/src/LUrlParser/LUrlParser.cpp b/src/LUrlParser/LUrlParser.cpp
new file mode 100644
index 0000000000..9884a908fb
--- /dev/null
+++ b/src/LUrlParser/LUrlParser.cpp
@@ -0,0 +1,265 @@
+/*
+ * Lightweight URL & URI parser (RFC 1738, RFC 3986)
+ * https://github.com/corporateshark/LUrlParser
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (C) 2015 Sergey Kosarevsky (sk@linderdaum.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "LUrlParser.hpp"
+
+#include
+#include
+#include
+
+// check if the scheme name is valid
+static bool IsSchemeValid( const std::string& SchemeName )
+{
+ for ( auto c : SchemeName )
+ {
+ if ( !isalpha( c ) && c != '+' && c != '-' && c != '.' ) return false;
+ }
+
+ return true;
+}
+
+bool LUrlParser::clParseURL::GetPort( int* OutPort ) const
+{
+ if ( !IsValid() ) { return false; }
+
+ int Port = atoi( m_Port.c_str() );
+
+ if ( Port <= 0 || Port > 65535 ) { return false; }
+
+ if ( OutPort ) { *OutPort = Port; }
+
+ return true;
+}
+
+// based on RFC 1738 and RFC 3986
+LUrlParser::clParseURL LUrlParser::clParseURL::ParseURL( const std::string& URL )
+{
+ LUrlParser::clParseURL Result;
+
+ const char* CurrentString = URL.c_str();
+
+ /*
+ * :
+ * := [a-z\+\-\.]+
+ * For resiliency, programs interpreting URLs should treat upper case letters as equivalent to lower case in scheme names
+ */
+
+ // try to read scheme
+ {
+ const char* LocalString = strchr( CurrentString, ':' );
+
+ if ( !LocalString )
+ {
+ return clParseURL(LUrlParserError::NoUrlCharacter );
+ }
+
+ // save the scheme name
+ Result.m_Scheme = std::string( CurrentString, LocalString - CurrentString );
+
+ if ( !IsSchemeValid( Result.m_Scheme ) )
+ {
+ return clParseURL( LUrlParserError::InvalidSchemeName );
+ }
+
+ // scheme should be lowercase
+ std::transform( Result.m_Scheme.begin(), Result.m_Scheme.end(), Result.m_Scheme.begin(), ::tolower );
+
+ // skip ':'
+ CurrentString = LocalString+1;
+ }
+
+ /*
+ * //:@:/
+ * any ":", "@" and "/" must be normalized
+ */
+
+ // skip "//"
+ if ( *CurrentString++ != '/' ) return clParseURL( LUrlParserError::NoDoubleSlash );
+ if ( *CurrentString++ != '/' ) return clParseURL( LUrlParserError::NoDoubleSlash );
+
+ // check if the user name and password are specified
+ bool bHasUserName = false;
+
+ const char* LocalString = CurrentString;
+
+ while ( *LocalString )
+ {
+ if ( *LocalString == '@' )
+ {
+ // user name and password are specified
+ bHasUserName = true;
+ break;
+ }
+ else if ( *LocalString == '/' )
+ {
+ // end of : specification
+ bHasUserName = false;
+ break;
+ }
+
+ LocalString++;
+ }
+
+ // user name and password
+ LocalString = CurrentString;
+
+ if ( bHasUserName )
+ {
+ // read user name
+ while ( *LocalString && *LocalString != ':' && *LocalString != '@' ) LocalString++;
+
+ Result.m_UserName = std::string( CurrentString, LocalString - CurrentString );
+
+ // proceed with the current pointer
+ CurrentString = LocalString;
+
+ if ( *CurrentString == ':' )
+ {
+ // skip ':'
+ CurrentString++;
+
+ // read password
+ LocalString = CurrentString;
+
+ while ( *LocalString && *LocalString != '@' ) LocalString++;
+
+ Result.m_Password = std::string( CurrentString, LocalString - CurrentString );
+
+ CurrentString = LocalString;
+ }
+
+ // skip '@'
+ if ( *CurrentString != '@' )
+ {
+ return clParseURL( LUrlParserError::NoAtSign );
+ }
+
+ CurrentString++;
+ }
+
+ bool bHasBracket = ( *CurrentString == '[' );
+
+ // go ahead, read the host name
+ LocalString = CurrentString;
+
+ while ( *LocalString )
+ {
+ if ( bHasBracket && *LocalString == ']' )
+ {
+ // end of IPv6 address
+ LocalString++;
+ break;
+ }
+ else if ( !bHasBracket && ( *LocalString == ':' || *LocalString == '/' ) )
+ {
+ // port number is specified
+ break;
+ }
+
+ LocalString++;
+ }
+
+ Result.m_Host = std::string( CurrentString, LocalString - CurrentString );
+
+ CurrentString = LocalString;
+
+ // is port number specified?
+ if ( *CurrentString == ':' )
+ {
+ CurrentString++;
+
+ // read port number
+ LocalString = CurrentString;
+
+ while ( *LocalString && *LocalString != '/' ) LocalString++;
+
+ Result.m_Port = std::string( CurrentString, LocalString - CurrentString );
+
+ CurrentString = LocalString;
+ }
+
+ // end of string
+ if ( !*CurrentString )
+ {
+ Result.m_ErrorCode = LUrlParserError::Ok;
+
+ return Result;
+ }
+
+ // skip '/'
+ if ( *CurrentString != '/' )
+ {
+ return clParseURL( LUrlParserError::NoSlash );
+ }
+
+ CurrentString++;
+
+ // parse the path
+ LocalString = CurrentString;
+
+ while ( *LocalString && *LocalString != '#' && *LocalString != '?' ) LocalString++;
+
+ Result.m_Path = std::string( CurrentString, LocalString - CurrentString );
+
+ CurrentString = LocalString;
+
+ // check for query
+ if ( *CurrentString == '?' )
+ {
+ // skip '?'
+ CurrentString++;
+
+ // read query
+ LocalString = CurrentString;
+
+ while ( *LocalString && *LocalString != '#' ) LocalString++;
+
+ Result.m_Query = std::string( CurrentString, LocalString - CurrentString );
+
+ CurrentString = LocalString;
+ }
+
+ // check for fragment
+ if ( *CurrentString == '#' )
+ {
+ // skip '#'
+ CurrentString++;
+
+ // read fragment
+ LocalString = CurrentString;
+
+ while ( *LocalString ) LocalString++;
+
+ Result.m_Fragment = std::string( CurrentString, LocalString - CurrentString );
+
+ CurrentString = LocalString;
+ }
+
+ Result.m_ErrorCode = LUrlParserError::Ok;
+
+ return Result;
+}
diff --git a/src/LUrlParser/LUrlParser.hpp b/src/LUrlParser/LUrlParser.hpp
new file mode 100644
index 0000000000..a4b5d759d8
--- /dev/null
+++ b/src/LUrlParser/LUrlParser.hpp
@@ -0,0 +1,80 @@
+/*
+ * Lightweight URL & URI parser (RFC 1738, RFC 3986)
+ * https://github.com/corporateshark/LUrlParser
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (C) 2015 Sergey Kosarevsky (sk@linderdaum.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+#include
+
+namespace LUrlParser
+{
+
+ // LibSass change: made enum scoped
+ enum class LUrlParserError
+ {
+ Ok = 0,
+ Uninitialized = 1,
+ NoUrlCharacter = 2,
+ InvalidSchemeName = 3,
+ NoDoubleSlash = 4,
+ NoAtSign = 5,
+ UnexpectedEndOfLine = 6,
+ NoSlash = 7,
+ };
+
+ class clParseURL
+ {
+ public:
+ LUrlParserError m_ErrorCode;
+ std::string m_Scheme;
+ std::string m_Host;
+ std::string m_Port;
+ std::string m_Path;
+ std::string m_Query;
+ std::string m_Fragment;
+ std::string m_UserName;
+ std::string m_Password;
+
+ clParseURL()
+ : m_ErrorCode(LUrlParserError::Uninitialized )
+ {}
+
+ /// return 'true' if the parsing was successful
+ bool IsValid() const { return m_ErrorCode == LUrlParserError::Ok; }
+
+ /// helper to convert the port number to int, return 'true' if the port is valid (within the 0..65535 range)
+ bool GetPort( int* OutPort ) const;
+
+ /// parse the URL
+ static clParseURL ParseURL( const std::string& URL );
+
+ private:
+ explicit clParseURL( LUrlParserError ErrorCode )
+ : m_ErrorCode( ErrorCode )
+ {}
+ };
+
+} // namespace LUrlParser
diff --git a/src/MurmurHash2.hpp b/src/MurmurHash2.hpp
index ab9b1634c6..3a58265a57 100644
--- a/src/MurmurHash2.hpp
+++ b/src/MurmurHash2.hpp
@@ -1,15 +1,18 @@
-//-----------------------------------------------------------------------------
-// MurmurHash2 was written by Austin Appleby, and is placed in the public
-// domain. The author hereby disclaims copyright to this source code.
-//-----------------------------------------------------------------------------
-// LibSass only needs MurmurHash2, so we made this header only
-//-----------------------------------------------------------------------------
+/*****************************************************************************/
+/* Part of LibSass, released under the MIT license (See LICENSE.txt). */
+/*****************************************************************************/
+/* MurmurHash2 was written by Austin Appleby, and is placed in the public */
+/* domain. The author hereby disclaims copyright to this source code. */
+/*****************************************************************************/
+/* LibSass only needs MurmurHash2, so we made this header only */
+/*****************************************************************************/
#ifndef _MURMURHASH2_H_
#define _MURMURHASH2_H_
-//-----------------------------------------------------------------------------
+/////////////////////////////////////////////////////////////////////////
// Platform-specific functions and macros
+/////////////////////////////////////////////////////////////////////////
// Microsoft Visual Studio
@@ -23,11 +26,12 @@ typedef unsigned __int64 uint64_t;
#else // defined(_MSC_VER)
-#include
+#include
#endif // !defined(_MSC_VER)
-//-----------------------------------------------------------------------------
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
inline uint32_t MurmurHash2 ( const void * key, int len, uint32_t seed )
{
@@ -85,7 +89,8 @@ inline uint32_t MurmurHash2 ( const void * key, int len, uint32_t seed )
return h;
}
-//-----------------------------------------------------------------------------
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
#endif // _MURMURHASH2_H_
diff --git a/src/ast.cpp b/src/ast.cpp
index 2c0dd64c94..43d2894305 100644
--- a/src/ast.cpp
+++ b/src/ast.cpp
@@ -1,953 +1,131 @@
-// sass.hpp must go before all system headers to get the
-// __EXTENSIONS__ fix on Solaris.
-#include "sass.hpp"
-
+/*****************************************************************************/
+/* Part of LibSass, released under the MIT license (See LICENSE.txt). */
+/*****************************************************************************/
#include "ast.hpp"
-namespace Sass {
-
- static Null sass_null(SourceSpan("null"));
-
- const char* sass_op_to_name(enum Sass_OP op) {
- switch (op) {
- case AND: return "and";
- case OR: return "or";
- case EQ: return "eq";
- case NEQ: return "neq";
- case GT: return "gt";
- case GTE: return "gte";
- case LT: return "lt";
- case LTE: return "lte";
- case ADD: return "plus";
- case SUB: return "minus";
- case MUL: return "times";
- case DIV: return "div";
- case MOD: return "mod";
- // this is only used internally!
- case NUM_OPS: return "[OPS]";
- default: return "invalid";
- }
- }
-
- const char* sass_op_separator(enum Sass_OP op) {
- switch (op) {
- case AND: return "&&";
- case OR: return "||";
- case EQ: return "==";
- case NEQ: return "!=";
- case GT: return ">";
- case GTE: return ">=";
- case LT: return "<";
- case LTE: return "<=";
- case ADD: return "+";
- case SUB: return "-";
- case MUL: return "*";
- case DIV: return "/";
- case MOD: return "%";
- // this is only used internally!
- case NUM_OPS: return "[OPS]";
- default: return "invalid";
- }
- }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- void AST_Node::update_pstate(const SourceSpan& pstate)
- {
- pstate_.offset += pstate.position - pstate_.position + pstate.offset;
- }
-
- sass::string AST_Node::to_string(Sass_Inspect_Options opt) const
- {
- Sass_Output_Options out(opt);
- Emitter emitter(out);
- Inspect i(emitter);
- i.in_declaration = true;
- // ToDo: inspect should be const
- const_cast(this)->perform(&i);
- return i.get_buffer();
- }
-
- sass::string AST_Node::to_css(Sass_Inspect_Options opt) const
- {
- opt.output_style = TO_CSS;
- Sass_Output_Options out(opt);
- Emitter emitter(out);
- Inspect i(emitter);
- i.in_declaration = true;
- // ToDo: inspect should be const
- const_cast(this)->perform(&i);
- return i.get_buffer();
- }
-
- sass::string AST_Node::to_string() const
- {
- return to_string({ NESTED, 5 });
- }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- Statement::Statement(SourceSpan pstate, Type st, size_t t)
- : AST_Node(pstate), statement_type_(st), tabs_(t), group_end_(false)
- { }
- Statement::Statement(const Statement* ptr)
- : AST_Node(ptr),
- statement_type_(ptr->statement_type_),
- tabs_(ptr->tabs_),
- group_end_(ptr->group_end_)
- { }
-
- bool Statement::bubbles()
- {
- return false;
- }
-
- bool Statement::has_content()
- {
- return statement_type_ == CONTENT;
- }
-
- bool Statement::is_invisible() const
- {
- return false;
- }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- Block::Block(SourceSpan pstate, size_t s, bool r)
- : Statement(pstate),
- Vectorized(s),
- is_root_(r)
- { }
- Block::Block(const Block* ptr)
- : Statement(ptr),
- Vectorized(*ptr),
- is_root_(ptr->is_root_)
- { }
-
- bool Block::isInvisible() const
- {
- for (auto& item : elements()) {
- if (!item->is_invisible()) return false;
- }
- return true;
- }
-
- bool Block::has_content()
- {
- for (size_t i = 0, L = elements().size(); i < L; ++i) {
- if (elements()[i]->has_content()) return true;
- }
- return Statement::has_content();
- }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- ParentStatement::ParentStatement(SourceSpan pstate, Block_Obj b)
- : Statement(pstate), block_(b)
- { }
- ParentStatement::ParentStatement(const ParentStatement* ptr)
- : Statement(ptr), block_(ptr->block_)
- { }
-
- bool ParentStatement::has_content()
- {
- return (block_ && block_->has_content()) || Statement::has_content();
- }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- StyleRule::StyleRule(SourceSpan pstate, SelectorListObj s, Block_Obj b)
- : ParentStatement(pstate, b), selector_(s), schema_(), is_root_(false)
- { statement_type(RULESET); }
- StyleRule::StyleRule(const StyleRule* ptr)
- : ParentStatement(ptr),
- selector_(ptr->selector_),
- schema_(ptr->schema_),
- is_root_(ptr->is_root_)
- { statement_type(RULESET); }
-
- bool StyleRule::is_invisible() const {
- if (const SelectorList * sl = Cast(selector())) {
- for (size_t i = 0, L = sl->length(); i < L; i += 1)
- if (!(*sl)[i]->isInvisible()) return false;
- }
- return true;
- }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- Bubble::Bubble(SourceSpan pstate, Statement_Obj n, Statement_Obj g, size_t t)
- : Statement(pstate, Statement::BUBBLE, t), node_(n), group_end_(g == nullptr)
- { }
- Bubble::Bubble(const Bubble* ptr)
- : Statement(ptr),
- node_(ptr->node_),
- group_end_(ptr->group_end_)
- { }
-
- bool Bubble::bubbles()
- {
- return true;
- }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- Trace::Trace(SourceSpan pstate, sass::string n, Block_Obj b, char type)
- : ParentStatement(pstate, b), type_(type), name_(n)
- { }
- Trace::Trace(const Trace* ptr)
- : ParentStatement(ptr),
- type_(ptr->type_),
- name_(ptr->name_)
- { }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- AtRule::AtRule(SourceSpan pstate, sass::string kwd, SelectorListObj sel, Block_Obj b, ExpressionObj val)
- : ParentStatement(pstate, b), keyword_(kwd), selector_(sel), value_(val) // set value manually if needed
- { statement_type(DIRECTIVE); }
- AtRule::AtRule(const AtRule* ptr)
- : ParentStatement(ptr),
- keyword_(ptr->keyword_),
- selector_(ptr->selector_),
- value_(ptr->value_) // set value manually if needed
- { statement_type(DIRECTIVE); }
-
- bool AtRule::bubbles() { return is_keyframes() || is_media(); }
-
- bool AtRule::is_media() {
- return keyword_.compare("@-webkit-media") == 0 ||
- keyword_.compare("@-moz-media") == 0 ||
- keyword_.compare("@-o-media") == 0 ||
- keyword_.compare("@media") == 0;
- }
- bool AtRule::is_keyframes() {
- return keyword_.compare("@-webkit-keyframes") == 0 ||
- keyword_.compare("@-moz-keyframes") == 0 ||
- keyword_.compare("@-o-keyframes") == 0 ||
- keyword_.compare("@keyframes") == 0;
- }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- Keyframe_Rule::Keyframe_Rule(SourceSpan pstate, Block_Obj b)
- : ParentStatement(pstate, b), name_()
- { statement_type(KEYFRAMERULE); }
- Keyframe_Rule::Keyframe_Rule(const Keyframe_Rule* ptr)
- : ParentStatement(ptr), name_(ptr->name_)
- { statement_type(KEYFRAMERULE); }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- Declaration::Declaration(SourceSpan pstate, String_Obj prop, ExpressionObj val, bool i, bool c, Block_Obj b)
- : ParentStatement(pstate, b), property_(prop), value_(val), is_important_(i), is_custom_property_(c), is_indented_(false)
- { statement_type(DECLARATION); }
- Declaration::Declaration(const Declaration* ptr)
- : ParentStatement(ptr),
- property_(ptr->property_),
- value_(ptr->value_),
- is_important_(ptr->is_important_),
- is_custom_property_(ptr->is_custom_property_),
- is_indented_(ptr->is_indented_)
- { statement_type(DECLARATION); }
-
- bool Declaration::is_invisible() const
- {
- if (is_custom_property()) return false;
- return !(value_ && !Cast(value_));
- }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- Assignment::Assignment(SourceSpan pstate, sass::string var, ExpressionObj val, bool is_default, bool is_global)
- : Statement(pstate), variable_(var), value_(val), is_default_(is_default), is_global_(is_global)
- { statement_type(ASSIGNMENT); }
- Assignment::Assignment(const Assignment* ptr)
- : Statement(ptr),
- variable_(ptr->variable_),
- value_(ptr->value_),
- is_default_(ptr->is_default_),
- is_global_(ptr->is_global_)
- { statement_type(ASSIGNMENT); }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- Import::Import(SourceSpan pstate)
- : Statement(pstate),
- urls_(sass::vector()),
- incs_(sass::vector()),
- import_queries_()
- { statement_type(IMPORT); }
- Import::Import(const Import* ptr)
- : Statement(ptr),
- urls_(ptr->urls_),
- incs_(ptr->incs_),
- import_queries_(ptr->import_queries_)
- { statement_type(IMPORT); }
-
- sass::vector& Import::incs() { return incs_; }
- sass::vector& Import::urls() { return urls_; }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- Import_Stub::Import_Stub(SourceSpan pstate, Include res)
- : Statement(pstate), resource_(res)
- { statement_type(IMPORT_STUB); }
- Import_Stub::Import_Stub(const Import_Stub* ptr)
- : Statement(ptr), resource_(ptr->resource_)
- { statement_type(IMPORT_STUB); }
- Include Import_Stub::resource() { return resource_; };
- sass::string Import_Stub::imp_path() { return resource_.imp_path; };
- sass::string Import_Stub::abs_path() { return resource_.abs_path; };
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- WarningRule::WarningRule(SourceSpan pstate, ExpressionObj msg)
- : Statement(pstate), message_(msg)
- { statement_type(WARNING); }
- WarningRule::WarningRule(const WarningRule* ptr)
- : Statement(ptr), message_(ptr->message_)
- { statement_type(WARNING); }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- ErrorRule::ErrorRule(SourceSpan pstate, ExpressionObj msg)
- : Statement(pstate), message_(msg)
- { statement_type(ERROR); }
- ErrorRule::ErrorRule(const ErrorRule* ptr)
- : Statement(ptr), message_(ptr->message_)
- { statement_type(ERROR); }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
+#include "cssize.hpp"
+#include "inspect.hpp"
+#include "dart_helpers.hpp"
- DebugRule::DebugRule(SourceSpan pstate, ExpressionObj val)
- : Statement(pstate), value_(val)
- { statement_type(DEBUGSTMT); }
- DebugRule::DebugRule(const DebugRule* ptr)
- : Statement(ptr), value_(ptr->value_)
- { statement_type(DEBUGSTMT); }
+namespace Sass {
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
- Comment::Comment(SourceSpan pstate, String_Obj txt, bool is_important)
- : Statement(pstate), text_(txt), is_important_(is_important)
- { statement_type(COMMENT); }
- Comment::Comment(const Comment* ptr)
- : Statement(ptr),
- text_(ptr->text_),
- is_important_(ptr->is_important_)
- { statement_type(COMMENT); }
-
- bool Comment::is_invisible() const
- {
- return false;
- }
+ // Needs to be in sync with SassOp enum
+ uint8_t SassOpPresedence[15] = {
+ 1, 2, 3, 3, 4, 4, 4, 4,
+ 5, 5, 6, 6, 6, 9, 255
+ };
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
+ // Needs to be in sync with SassOp enum
+ const char* SassOpName[15] = {
+ "or", "and", "eq", "neq", "gt", "gte", "lt", "lte",
+ "plus", "minus", "times", "div", "mod", "seq", "invalid"
+ };
- If::If(SourceSpan pstate, ExpressionObj pred, Block_Obj con, Block_Obj alt)
- : ParentStatement(pstate, con), predicate_(pred), alternative_(alt)
- { statement_type(IF); }
- If::If(const If* ptr)
- : ParentStatement(ptr),
- predicate_(ptr->predicate_),
- alternative_(ptr->alternative_)
- { statement_type(IF); }
+ // Needs to be in sync with SassOp enum
+ const char* SassOpOperator[15] = {
+ "||", "&&", "==", "!=", ">", ">=", "<", "<=",
+ "+", "-", "*", "/", "%", "=", "invalid"
+ };
- bool If::has_content()
+ // Precedence is used to decide order
+ // in ExpressionParser::addOperator.
+ uint8_t sass_op_to_precedence(enum SassOperator op)
{
- return ParentStatement::has_content() || (alternative_ && alternative_->has_content());
+ return SassOpPresedence[op];
}
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- ForRule::ForRule(SourceSpan pstate,
- sass::string var, ExpressionObj lo, ExpressionObj hi, Block_Obj b, bool inc)
- : ParentStatement(pstate, b),
- variable_(var), lower_bound_(lo), upper_bound_(hi), is_inclusive_(inc)
- { statement_type(FOR); }
- ForRule::ForRule(const ForRule* ptr)
- : ParentStatement(ptr),
- variable_(ptr->variable_),
- lower_bound_(ptr->lower_bound_),
- upper_bound_(ptr->upper_bound_),
- is_inclusive_(ptr->is_inclusive_)
- { statement_type(FOR); }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- EachRule::EachRule(SourceSpan pstate, sass::vector vars, ExpressionObj lst, Block_Obj b)
- : ParentStatement(pstate, b), variables_(vars), list_(lst)
- { statement_type(EACH); }
- EachRule::EachRule(const EachRule* ptr)
- : ParentStatement(ptr), variables_(ptr->variables_), list_(ptr->list_)
- { statement_type(EACH); }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- WhileRule::WhileRule(SourceSpan pstate, ExpressionObj pred, Block_Obj b)
- : ParentStatement(pstate, b), predicate_(pred)
- { statement_type(WHILE); }
- WhileRule::WhileRule(const WhileRule* ptr)
- : ParentStatement(ptr), predicate_(ptr->predicate_)
- { statement_type(WHILE); }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- Return::Return(SourceSpan pstate, ExpressionObj val)
- : Statement(pstate), value_(val)
- { statement_type(RETURN); }
- Return::Return(const Return* ptr)
- : Statement(ptr), value_(ptr->value_)
- { statement_type(RETURN); }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- ExtendRule::ExtendRule(SourceSpan pstate, SelectorListObj s)
- : Statement(pstate), isOptional_(false), selector_(s), schema_()
- { statement_type(EXTEND); }
- ExtendRule::ExtendRule(SourceSpan pstate, Selector_Schema_Obj s)
- : Statement(pstate), isOptional_(false), selector_(), schema_(s)
+ // Get readable name for error messages
+ const char* sass_op_to_name(enum SassOperator op)
{
- statement_type(EXTEND);
+ return SassOpName[op];
}
- ExtendRule::ExtendRule(const ExtendRule* ptr)
- : Statement(ptr),
- isOptional_(ptr->isOptional_),
- selector_(ptr->selector_),
- schema_(ptr->schema_)
- { statement_type(EXTEND); }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- Definition::Definition(const Definition* ptr)
- : ParentStatement(ptr),
- name_(ptr->name_),
- parameters_(ptr->parameters_),
- environment_(ptr->environment_),
- type_(ptr->type_),
- native_function_(ptr->native_function_),
- c_function_(ptr->c_function_),
- cookie_(ptr->cookie_),
- is_overload_stub_(ptr->is_overload_stub_),
- signature_(ptr->signature_)
- { }
-
- Definition::Definition(SourceSpan pstate,
- sass::string n,
- Parameters_Obj params,
- Block_Obj b,
- Type t)
- : ParentStatement(pstate, b),
- name_(n),
- parameters_(params),
- environment_(0),
- type_(t),
- native_function_(0),
- c_function_(0),
- cookie_(0),
- is_overload_stub_(false),
- signature_(0)
- { }
-
- Definition::Definition(SourceSpan pstate,
- Signature sig,
- sass::string n,
- Parameters_Obj params,
- Native_Function func_ptr,
- bool overload_stub)
- : ParentStatement(pstate, {}),
- name_(n),
- parameters_(params),
- environment_(0),
- type_(FUNCTION),
- native_function_(func_ptr),
- c_function_(0),
- cookie_(0),
- is_overload_stub_(overload_stub),
- signature_(sig)
- { }
- Definition::Definition(SourceSpan pstate,
- Signature sig,
- sass::string n,
- Parameters_Obj params,
- Sass_Function_Entry c_func)
- : ParentStatement(pstate, {}),
- name_(n),
- parameters_(params),
- environment_(0),
- type_(FUNCTION),
- native_function_(0),
- c_function_(c_func),
- cookie_(sass_function_get_cookie(c_func)),
- is_overload_stub_(false),
- signature_(sig)
- { }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- Mixin_Call::Mixin_Call(SourceSpan pstate, sass::string n, Arguments_Obj args, Parameters_Obj b_params, Block_Obj b)
- : ParentStatement(pstate, b), name_(n), arguments_(args), block_parameters_(b_params)
- { }
- Mixin_Call::Mixin_Call(const Mixin_Call* ptr)
- : ParentStatement(ptr),
- name_(ptr->name_),
- arguments_(ptr->arguments_),
- block_parameters_(ptr->block_parameters_)
- { }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- Content::Content(SourceSpan pstate, Arguments_Obj args)
- : Statement(pstate),
- arguments_(args)
- { statement_type(CONTENT); }
- Content::Content(const Content* ptr)
- : Statement(ptr),
- arguments_(ptr->arguments_)
- { statement_type(CONTENT); }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- Expression::Expression(SourceSpan pstate, bool d, bool e, bool i, Type ct)
- : AST_Node(pstate),
- is_delayed_(d),
- is_expanded_(e),
- is_interpolant_(i),
- concrete_type_(ct)
- { }
-
- Expression::Expression(const Expression* ptr)
- : AST_Node(ptr),
- is_delayed_(ptr->is_delayed_),
- is_expanded_(ptr->is_expanded_),
- is_interpolant_(ptr->is_interpolant_),
- concrete_type_(ptr->concrete_type_)
- { }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- Unary_Expression::Unary_Expression(SourceSpan pstate, Type t, ExpressionObj o)
- : Expression(pstate), optype_(t), operand_(o), hash_(0)
- { }
- Unary_Expression::Unary_Expression(const Unary_Expression* ptr)
- : Expression(ptr),
- optype_(ptr->optype_),
- operand_(ptr->operand_),
- hash_(ptr->hash_)
- { }
- const sass::string Unary_Expression::type_name() {
- switch (optype_) {
- case PLUS: return "plus";
- case MINUS: return "minus";
- case SLASH: return "slash";
- case NOT: return "not";
- default: return "invalid";
- }
- }
- bool Unary_Expression::operator==(const Expression& rhs) const
- {
- try
- {
- const Unary_Expression* m = Cast(&rhs);
- if (m == 0) return false;
- return type() == m->type() &&
- *operand() == *m->operand();
- }
- catch (std::bad_cast&)
- {
- return false;
- }
- catch (...) { throw; }
- }
- size_t Unary_Expression::hash() const
+ // Get readable name for operator (e.g. `==`)
+ const char* sass_op_separator(enum SassOperator op)
{
- if (hash_ == 0) {
- hash_ = std::hash()(optype_);
- hash_combine(hash_, operand()->hash());
- };
- return hash_;
+ return SassOpOperator[op];
}
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
- Argument::Argument(SourceSpan pstate, ExpressionObj val, sass::string n, bool rest, bool keyword)
- : Expression(pstate), value_(val), name_(n), is_rest_argument_(rest), is_keyword_argument_(keyword), hash_(0)
+ sass::string Selector::inspect(int precision) const
{
- if (!name_.empty() && is_rest_argument_) {
- coreError("variable-length argument may not be passed by name", pstate_);
- }
- }
- Argument::Argument(const Argument* ptr)
- : Expression(ptr),
- value_(ptr->value_),
- name_(ptr->name_),
- is_rest_argument_(ptr->is_rest_argument_),
- is_keyword_argument_(ptr->is_keyword_argument_),
- hash_(ptr->hash_)
- {
- if (!name_.empty() && is_rest_argument_) {
- coreError("variable-length argument may not be passed by name", pstate_);
- }
- }
-
- void Argument::set_delayed(bool delayed)
- {
- if (value_) value_->set_delayed(delayed);
- is_delayed(delayed);
+ SassOutputOptionsCpp out({
+ SASS_STYLE_NESTED,
+ precision });
+ Inspect i(out, false);
+ i.inspect = true;
+ // Inspect must be const, accept isn't
+ const_cast(this)->accept(&i);
+ return i.get_buffer();
}
- bool Argument::operator==(const Expression& rhs) const
+ sass::string Value::inspect(int precision, bool quotes) const
{
- try
- {
- const Argument* m = Cast(&rhs);
- if (!(m && name() == m->name())) return false;
- return *value() == *m->value();
- }
- catch (std::bad_cast&)
- {
- return false;
- }
- catch (...) { throw; }
+ SassOutputOptionsCpp out({
+ SASS_STYLE_NESTED,
+ precision });
+ Inspect i(out, false);
+ i.inspect = true;
+ i.quotes = quotes;
+ // Inspect must be const, accept isn't
+ const_cast(this)->accept(&i);
+ return i.get_buffer();
}
- size_t Argument::hash() const
+ sass::string Value::toCss(Logger& logger, bool quote) const
{
- if (hash_ == 0) {
- hash_ = std::hash()(name());
- hash_combine(hash_, value()->hash());
- }
- return hash_;
+ SassOutputOptionsCpp out({
+ SASS_STYLE_TO_CSS,
+ SassDefaultPrecision });
+ Cssize i(out, false);
+ i.quotes = quote;
+ // Inspect must be const, accept isn't
+ const_cast(this)->accept(&i);
+ return i.get_buffer();
}
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- Arguments::Arguments(SourceSpan pstate)
- : Expression(pstate),
- Vectorized(),
- has_named_arguments_(false),
- has_rest_argument_(false),
- has_keyword_argument_(false)
- { }
- Arguments::Arguments(const Arguments* ptr)
- : Expression(ptr),
- Vectorized(*ptr),
- has_named_arguments_(ptr->has_named_arguments_),
- has_rest_argument_(ptr->has_rest_argument_),
- has_keyword_argument_(ptr->has_keyword_argument_)
- { }
-
- void Arguments::set_delayed(bool delayed)
- {
- for (Argument_Obj arg : elements()) {
- if (arg) arg->set_delayed(delayed);
- }
- is_delayed(delayed);
- }
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
- Argument_Obj Arguments::get_rest_argument()
+ // Only used for nth sass function
+ // Single values act like lists with 1 item
+ // Doesn't allow overflow of index (throw error)
+ // Allows negative index but no overflow either
+ Value* Value::getValueAt(Value* index, Logger& logger)
{
- if (this->has_rest_argument()) {
- for (Argument_Obj arg : this->elements()) {
- if (arg->is_rest_argument()) {
- return arg;
- }
- }
- }
- return {};
+ // Check out of boundary access
+ sassIndexToListIndex(index, logger, "n");
+ // Return single value
+ return this;
}
- Argument_Obj Arguments::get_keyword_argument()
+ // Only used for nth sass function
+ // Doesn't allow overflow of index (throw error)
+ // Allows negative index but no overflow either
+ Value* Map::getValueAt(Value* index, Logger& logger)
{
- if (this->has_keyword_argument()) {
- for (Argument_Obj arg : this->elements()) {
- if (arg->is_keyword_argument()) {
- return arg;
- }
- }
- }
- return {};
+ return getPairAsList(sassIndexToListIndex(index, logger, "n"));
}
- void Arguments::adjust_after_pushing(Argument_Obj a)
- {
- if (!a->name().empty()) {
- if (has_keyword_argument()) {
- coreError("named arguments must precede variable-length argument", a->pstate());
- }
- has_named_arguments(true);
- }
- else if (a->is_rest_argument()) {
- if (has_rest_argument()) {
- coreError("functions and mixins may only be called with one variable-length argument", a->pstate());
- }
- if (has_keyword_argument_) {
- coreError("only keyword arguments may follow variable arguments", a->pstate());
- }
- has_rest_argument(true);
- }
- else if (a->is_keyword_argument()) {
- if (has_keyword_argument()) {
- coreError("functions and mixins may only be called with one keyword argument", a->pstate());
- }
- has_keyword_argument(true);
- }
- else {
- if (has_rest_argument()) {
- coreError("ordinal arguments must precede variable-length arguments", a->pstate());
- }
- if (has_named_arguments()) {
- coreError("ordinal arguments must precede named arguments", a->pstate());
- }
- }
+ // Search the position of the given value
+ size_t List::indexOf(Value* value) {
+ return Sass::indexOf(elements(), value);
}
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- Media_Query::Media_Query(SourceSpan pstate, String_Obj t, size_t s, bool n, bool r)
- : Expression(pstate), Vectorized(s),
- media_type_(t), is_negated_(n), is_restricted_(r)
- { }
- Media_Query::Media_Query(const Media_Query* ptr)
- : Expression(ptr),
- Vectorized(*ptr),
- media_type_(ptr->media_type_),
- is_negated_(ptr->is_negated_),
- is_restricted_(ptr->is_restricted_)
- { }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- Media_Query_Expression::Media_Query_Expression(SourceSpan pstate,
- ExpressionObj f, ExpressionObj v, bool i)
- : Expression(pstate), feature_(f), value_(v), is_interpolated_(i)
- { }
- Media_Query_Expression::Media_Query_Expression(const Media_Query_Expression* ptr)
- : Expression(ptr),
- feature_(ptr->feature_),
- value_(ptr->value_),
- is_interpolated_(ptr->is_interpolated_)
- { }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- At_Root_Query::At_Root_Query(SourceSpan pstate, ExpressionObj f, ExpressionObj v, bool i)
- : Expression(pstate), feature_(f), value_(v)
- { }
- At_Root_Query::At_Root_Query(const At_Root_Query* ptr)
- : Expression(ptr),
- feature_(ptr->feature_),
- value_(ptr->value_)
- { }
-
- bool At_Root_Query::exclude(sass::string str)
+ // Only used for nth sass function
+ // Doesn't allow overflow of index (throw error)
+ // Allows negative index but no overflow either
+ Value* List::getValueAt(Value* index, Logger& logger)
{
- bool with = feature() && unquote(feature()->to_string()).compare("with") == 0;
- List* l = static_cast(value().ptr());
- sass::string v;
-
- if (with)
- {
- if (!l || l->length() == 0) return str.compare("rule") != 0;
- for (size_t i = 0, L = l->length(); i < L; ++i)
- {
- v = unquote((*l)[i]->to_string());
- if (v.compare("all") == 0 || v == str) return false;
- }
- return true;
- }
- else
- {
- if (!l || !l->length()) return str.compare("rule") == 0;
- for (size_t i = 0, L = l->length(); i < L; ++i)
- {
- v = unquote((*l)[i]->to_string());
- if (v.compare("all") == 0 || v == str) return true;
- }
- return false;
- }
+ return get(sassIndexToListIndex(index, logger, "n"));
}
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- AtRootRule::AtRootRule(SourceSpan pstate, Block_Obj b, At_Root_Query_Obj e)
- : ParentStatement(pstate, b), expression_(e)
- { statement_type(ATROOT); }
- AtRootRule::AtRootRule(const AtRootRule* ptr)
- : ParentStatement(ptr), expression_(ptr->expression_)
- { statement_type(ATROOT); }
-
- bool AtRootRule::bubbles() {
- return true;
- }
-
- bool AtRootRule::exclude_node(Statement_Obj s) {
- if (expression() == nullptr)
- {
- return s->statement_type() == Statement::RULESET;
- }
-
- if (s->statement_type() == Statement::DIRECTIVE)
- {
- if (AtRuleObj dir = Cast(s))
- {
- sass::string keyword(dir->keyword());
- if (keyword.length() > 0) keyword.erase(0, 1);
- return expression()->exclude(keyword);
- }
- }
- if (s->statement_type() == Statement::MEDIA)
- {
- return expression()->exclude("media");
- }
- if (s->statement_type() == Statement::RULESET)
- {
- return expression()->exclude("rule");
- }
- if (s->statement_type() == Statement::SUPPORTS)
- {
- return expression()->exclude("supports");
- }
- if (AtRuleObj dir = Cast(s))
- {
- if (dir->is_keyframes()) return expression()->exclude("keyframes");
- }
- return false;
- }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- Parameter::Parameter(SourceSpan pstate, sass::string n, ExpressionObj def, bool rest)
- : AST_Node(pstate), name_(n), default_value_(def), is_rest_parameter_(rest)
- { }
- Parameter::Parameter(const Parameter* ptr)
- : AST_Node(ptr),
- name_(ptr->name_),
- default_value_(ptr->default_value_),
- is_rest_parameter_(ptr->is_rest_parameter_)
- { }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- Parameters::Parameters(SourceSpan pstate)
- : AST_Node(pstate),
- Vectorized(),
- has_optional_parameters_(false),
- has_rest_parameter_(false)
- { }
- Parameters::Parameters(const Parameters* ptr)
- : AST_Node(ptr),
- Vectorized(*ptr),
- has_optional_parameters_(ptr->has_optional_parameters_),
- has_rest_parameter_(ptr->has_rest_parameter_)
- { }
-
- void Parameters::adjust_after_pushing(Parameter_Obj p)
- {
- if (p->default_value()) {
- if (has_rest_parameter()) {
- coreError("optional parameters may not be combined with variable-length parameters", p->pstate());
- }
- has_optional_parameters(true);
- }
- else if (p->is_rest_parameter()) {
- if (has_rest_parameter()) {
- coreError("functions and mixins cannot have more than one variable-length parameter", p->pstate());
- }
- has_rest_parameter(true);
- }
- else {
- if (has_rest_parameter()) {
- coreError("required parameters must precede variable-length parameters", p->pstate());
- }
- if (has_optional_parameters()) {
- coreError("required parameters must precede optional parameters", p->pstate());
- }
- }
- }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- // If you forget to add a class here you will get
- // undefined reference to `vtable for Sass::Class'
-
- IMPLEMENT_AST_OPERATORS(StyleRule);
- IMPLEMENT_AST_OPERATORS(MediaRule);
- IMPLEMENT_AST_OPERATORS(CssMediaRule);
- IMPLEMENT_AST_OPERATORS(CssMediaQuery);
- IMPLEMENT_AST_OPERATORS(Import);
- IMPLEMENT_AST_OPERATORS(Import_Stub);
- IMPLEMENT_AST_OPERATORS(AtRule);
- IMPLEMENT_AST_OPERATORS(AtRootRule);
- IMPLEMENT_AST_OPERATORS(WhileRule);
- IMPLEMENT_AST_OPERATORS(EachRule);
- IMPLEMENT_AST_OPERATORS(ForRule);
- IMPLEMENT_AST_OPERATORS(If);
- IMPLEMENT_AST_OPERATORS(Mixin_Call);
- IMPLEMENT_AST_OPERATORS(ExtendRule);
- IMPLEMENT_AST_OPERATORS(Media_Query);
- IMPLEMENT_AST_OPERATORS(Media_Query_Expression);
- IMPLEMENT_AST_OPERATORS(DebugRule);
- IMPLEMENT_AST_OPERATORS(ErrorRule);
- IMPLEMENT_AST_OPERATORS(WarningRule);
- IMPLEMENT_AST_OPERATORS(Assignment);
- IMPLEMENT_AST_OPERATORS(Return);
- IMPLEMENT_AST_OPERATORS(At_Root_Query);
- IMPLEMENT_AST_OPERATORS(Comment);
- IMPLEMENT_AST_OPERATORS(Parameters);
- IMPLEMENT_AST_OPERATORS(Parameter);
- IMPLEMENT_AST_OPERATORS(Arguments);
- IMPLEMENT_AST_OPERATORS(Argument);
- IMPLEMENT_AST_OPERATORS(Unary_Expression);
- IMPLEMENT_AST_OPERATORS(Block);
- IMPLEMENT_AST_OPERATORS(Content);
- IMPLEMENT_AST_OPERATORS(Trace);
- IMPLEMENT_AST_OPERATORS(Keyframe_Rule);
- IMPLEMENT_AST_OPERATORS(Bubble);
- IMPLEMENT_AST_OPERATORS(Definition);
- IMPLEMENT_AST_OPERATORS(Declaration);
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
}
diff --git a/src/ast.hpp b/src/ast.hpp
index e7dcaf657d..7cef4a1eee 100644
--- a/src/ast.hpp
+++ b/src/ast.hpp
@@ -1,1064 +1,24 @@
-#ifndef SASS_AST_H
-#define SASS_AST_H
-
-// sass.hpp must go before all system headers to get the
-// __EXTENSIONS__ fix on Solaris.
-#include "sass.hpp"
-
-#include
-#include
-
-#include "sass/base.h"
-#include "ast_helpers.hpp"
-#include "ast_fwd_decl.hpp"
+/*****************************************************************************/
+/* Part of LibSass, released under the MIT license (See LICENSE.txt). */
+/*****************************************************************************/
+#ifndef SASS_AST_HPP
+#define SASS_AST_HPP
+
+// sass.hpp must go before all system headers
+// to get the __EXTENSIONS__ fix on Solaris.
+#include "capi_sass.hpp"
+
+#include "ast_css.hpp"
+#include "ast_callables.hpp"
+#include "ast_containers.hpp"
+#include "ast_expressions.hpp"
#include "ast_def_macros.hpp"
-
-#include "file.hpp"
-#include "position.hpp"
-#include "operation.hpp"
-#include "environment.hpp"
-#include "fn_utils.hpp"
-
-namespace Sass {
-
- // ToDo: where does this fit best?
- // We don't share this with C-API?
- class Operand {
- public:
- Operand(Sass_OP operand, bool ws_before = false, bool ws_after = false)
- : operand(operand), ws_before(ws_before), ws_after(ws_after)
- { }
- public:
- enum Sass_OP operand;
- bool ws_before;
- bool ws_after;
- };
-
- //////////////////////////////////////////////////////////
- // `hash_combine` comes from boost (functional/hash):
- // http://www.boost.org/doc/libs/1_35_0/doc/html/hash/combine.html
- // Boost Software License - Version 1.0
- // http://www.boost.org/users/license.html
- template
- void hash_combine (std::size_t& seed, const T& val)
- {
- seed ^= std::hash()(val) + 0x9e3779b9
- + (seed<<6) + (seed>>2);
- }
- //////////////////////////////////////////////////////////
-
- const char* sass_op_to_name(enum Sass_OP op);
-
- const char* sass_op_separator(enum Sass_OP op);
-
- //////////////////////////////////////////////////////////
- // Abstract base class for all abstract syntax tree nodes.
- //////////////////////////////////////////////////////////
- class AST_Node : public SharedObj {
- ADD_PROPERTY(SourceSpan, pstate)
- public:
- AST_Node(SourceSpan pstate)
- : pstate_(pstate)
- { }
- AST_Node(const AST_Node* ptr)
- : pstate_(ptr->pstate_)
- { }
-
- // allow implicit conversion to string
- // needed for by SharedPtr implementation
- operator sass::string() {
- return to_string();
- }
-
- // AST_Node(AST_Node& ptr) = delete;
-
- virtual ~AST_Node() = 0;
- virtual size_t hash() const { return 0; }
- virtual sass::string inspect() const { return to_string({ INSPECT, 5 }); }
- virtual sass::string to_sass() const { return to_string({ TO_SASS, 5 }); }
- virtual sass::string to_string(Sass_Inspect_Options opt) const;
- virtual sass::string to_css(Sass_Inspect_Options opt) const;
- virtual sass::string to_string() const;
- virtual void cloneChildren() {};
- // generic find function (not fully implemented yet)
- // ToDo: add specific implementations to all children
- virtual bool find ( bool (*f)(AST_Node_Obj) ) { return f(this); };
- void update_pstate(const SourceSpan& pstate);
-
- // Some objects are not meant to be compared
- // ToDo: maybe fall-back to pointer comparison?
- virtual bool operator== (const AST_Node& rhs) const {
- throw std::runtime_error("operator== not implemented");
- }
-
- // We can give some reasonable implementations by using
- // invert operators on the specialized implementations
- virtual bool operator!= (const AST_Node& rhs) const {
- // Unequal if not equal
- return !(*this == rhs);
- }
-
- ATTACH_ABSTRACT_AST_OPERATIONS(AST_Node);
- ATTACH_ABSTRACT_CRTP_PERFORM_METHODS()
- };
- 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
- // represents elements in value contexts, which exist primarily to be
- // evaluated and returned.
- //////////////////////////////////////////////////////////////////////
- class Expression : public AST_Node {
- public:
- enum Type {
- NONE,
- BOOLEAN,
- NUMBER,
- COLOR,
- STRING,
- LIST,
- MAP,
- SELECTOR,
- NULL_VAL,
- FUNCTION_VAL,
- C_WARNING,
- C_ERROR,
- FUNCTION,
- VARIABLE,
- PARENT,
- NUM_TYPES
- };
- private:
- // expressions in some contexts shouldn't be evaluated
- ADD_PROPERTY(bool, is_delayed)
- ADD_PROPERTY(bool, is_expanded)
- ADD_PROPERTY(bool, is_interpolant)
- ADD_PROPERTY(Type, concrete_type)
- public:
- Expression(SourceSpan pstate, bool d = false, bool e = false, bool i = false, Type ct = NONE);
- virtual operator bool() { return true; }
- virtual ~Expression() { }
- virtual bool is_invisible() const { return false; }
-
- virtual sass::string type() const { return ""; }
- static sass::string type_name() { return ""; }
-
- virtual bool is_false() { return false; }
- // virtual bool is_true() { return !is_false(); }
- virtual bool operator< (const Expression& rhs) const { return false; }
- virtual bool operator== (const Expression& rhs) const { return false; }
- inline bool operator>(const Expression& rhs) const { return rhs < *this; }
- inline bool operator!=(const Expression& rhs) const { return !(rhs == *this); }
- virtual bool eq(const Expression& rhs) const { return *this == rhs; };
- virtual void set_delayed(bool delayed) { is_delayed(delayed); }
- virtual bool has_interpolant() const { return is_interpolant(); }
- virtual bool is_left_interpolant() const { return is_interpolant(); }
- virtual bool is_right_interpolant() const { return is_interpolant(); }
- ATTACH_VIRTUAL_AST_OPERATIONS(Expression);
- size_t hash() const override { return 0; }
- };
-
-}
-
-/////////////////////////////////////////////////////////////////////////////////////
-// Hash method specializations for std::unordered_map to work with Sass::Expression
-/////////////////////////////////////////////////////////////////////////////////////
-
-namespace std {
- template<>
- struct hash
- {
- size_t operator()(Sass::ExpressionObj s) const
- {
- return s->hash();
- }
- };
- template<>
- struct equal_to
- {
- bool operator()( Sass::ExpressionObj lhs, Sass::ExpressionObj rhs) const
- {
- return lhs->hash() == rhs->hash();
- }
- };
-}
-
-namespace Sass {
-
- /////////////////////////////////////////////////////////////////////////////
- // Mixin class for AST nodes that should behave like vectors. Uses the
- // "Template Method" design pattern to allow subclasses to adjust their flags
- // when certain objects are pushed.
- /////////////////////////////////////////////////////////////////////////////
- template
- class Vectorized {
- sass::vector elements_;
- protected:
- mutable size_t hash_;
- void reset_hash() { hash_ = 0; }
- virtual void adjust_after_pushing(T element) { }
- public:
- Vectorized(size_t s = 0) : hash_(0)
- { elements_.reserve(s); }
- Vectorized(sass::vector vec) :
- elements_(std::move(vec)),
- hash_(0)
- {}
- virtual ~Vectorized() = 0;
- size_t length() const { return elements_.size(); }
- bool empty() const { return elements_.empty(); }
- void clear() { return elements_.clear(); }
- T& last() { return elements_.back(); }
- T& first() { return elements_.front(); }
- const T& last() const { return elements_.back(); }
- const T& first() const { return elements_.front(); }
-
- bool operator== (const Vectorized& rhs) const {
- // Abort early if sizes do not match
- if (length() != rhs.length()) return false;
- // Otherwise test each node for object equalicy in order
- return std::equal(begin(), end(), rhs.begin(), ObjEqualityFn);
- }
-
- bool operator!= (const Vectorized& rhs) const {
- return !(*this == rhs);
- }
-
- T& operator[](size_t i) { return elements_[i]; }
- virtual const T& at(size_t i) const { return elements_.at(i); }
- virtual T& at(size_t i) { return elements_.at(i); }
- const T& get(size_t i) const { return elements_[i]; }
- const T& operator[](size_t i) const { return elements_[i]; }
-
- // Implicitly get the sass::vector from our object
- // Makes the Vector directly assignable to sass::vector
- // You are responsible to make a copy if needed
- // Note: since this returns the real object, we can't
- // Note: guarantee that the hash will not get out of sync
- operator sass::vector&() { return elements_; }
- operator const sass::vector&() const { return elements_; }
-
- // Explicitly request all elements as a real sass::vector
- // You are responsible to make a copy if needed
- // Note: since this returns the real object, we can't
- // Note: guarantee that the hash will not get out of sync
- sass::vector& elements() { return elements_; }
- const sass::vector& elements() const { return elements_; }
-
- // Insert all items from compatible vector
- void concat(const sass::vector& v)
- {
- if (!v.empty()) reset_hash();
- elements().insert(end(), v.begin(), v.end());
- }
-
- // Syntatic sugar for pointers
- void concat(const Vectorized* v)
- {
- if (v != nullptr) {
- return concat(*v);
- }
- }
-
- // Insert one item on the front
- void unshift(T element)
- {
- reset_hash();
- elements_.insert(begin(), element);
- }
-
- // Remove and return item on the front
- // ToDo: handle empty vectors
- T shift() {
- reset_hash();
- T first = get(0);
- elements_.erase(begin());
- return first;
- }
-
- // Insert one item on the back
- // ToDo: rename this to push
- void append(T element)
- {
- reset_hash();
- elements_.insert(end(), element);
- // ToDo: Mostly used by parameters and arguments
- // ToDo: Find a more elegant way to support this
- adjust_after_pushing(element);
- }
-
- // Check if an item already exists
- // Uses underlying object `operator==`
- // E.g. compares the actual objects
- bool contains(const T& el) const {
- for (const T& rhs : elements_) {
- // Test the underlying objects for equality
- // A std::find checks for pointer equality
- if (ObjEqualityFn(el, rhs)) {
- return true;
- }
- }
- return false;
- }
-
- // This might be better implemented as `operator=`?
- void elements(sass::vector e) {
- reset_hash();
- elements_ = std::move(e);
- }
-
- virtual size_t hash() const
- {
- if (hash_ == 0) {
- for (const T& el : elements_) {
- hash_combine(hash_, el->hash());
- }
- }
- return hash_;
- }
-
- template
- typename sass::vector::iterator insert(P position, const V& val) {
- reset_hash();
- return elements_.insert(position, val);
- }
-
- typename sass::vector::iterator end() { return elements_.end(); }
- typename sass::vector::iterator begin() { return elements_.begin(); }
- typename sass::vector::const_iterator end() const { return elements_.end(); }
- typename sass::vector::const_iterator begin() const { return elements_.begin(); }
- typename sass::vector::iterator erase(typename sass::vector::iterator el) { reset_hash(); return elements_.erase(el); }
- typename sass::vector::const_iterator erase(typename sass::vector::const_iterator el) { reset_hash(); return elements_.erase(el); }
-
- };
- template
- inline Vectorized::~Vectorized() { }
-
- /////////////////////////////////////////////////////////////////////////////
- // Mixin class for AST nodes that should behave like a hash table. Uses an
- // extra internally to maintain insertion order for interation.
- /////////////////////////////////////////////////////////////////////////////
- template
- class Hashed {
- private:
- std::unordered_map<
- K, T, ObjHash, ObjHashEquality
- > elements_;
-
- sass::vector _keys;
- sass::vector _values;
- protected:
- mutable size_t hash_;
- K duplicate_key_;
- void reset_hash() { hash_ = 0; }
- void reset_duplicate_key() { duplicate_key_ = {}; }
- virtual void adjust_after_pushing(std::pair p) { }
- public:
- Hashed(size_t s = 0)
- : elements_(),
- _keys(),
- _values(),
- hash_(0), duplicate_key_({})
- {
- _keys.reserve(s);
- _values.reserve(s);
- elements_.reserve(s);
- }
- virtual ~Hashed();
- size_t length() const { return _keys.size(); }
- bool empty() const { return _keys.empty(); }
- bool has(K k) const {
- return elements_.find(k) != elements_.end();
- }
- T at(K k) const {
- if (elements_.count(k))
- {
- return elements_.at(k);
- }
- else { return {}; }
- }
- bool has_duplicate_key() const { return duplicate_key_ != nullptr; }
- K get_duplicate_key() const { return duplicate_key_; }
- const std::unordered_map<
- K, T, ObjHash, ObjHashEquality
- >& elements() { return elements_; }
- Hashed& operator<<(std::pair p)
- {
- reset_hash();
-
- if (!has(p.first)) {
- _keys.push_back(p.first);
- _values.push_back(p.second);
- }
- else if (!duplicate_key_) {
- duplicate_key_ = p.first;
- }
-
- elements_[p.first] = p.second;
-
- adjust_after_pushing(p);
- return *this;
- }
- Hashed& operator+=(Hashed* h)
- {
- if (length() == 0) {
- this->elements_ = h->elements_;
- this->_values = h->_values;
- this->_keys = h->_keys;
- return *this;
- }
-
- for (auto key : h->keys()) {
- *this << std::make_pair(key, h->at(key));
- }
-
- reset_duplicate_key();
- return *this;
- }
- const std::unordered_map<
- K, T, ObjHash, ObjHashEquality
- >& pairs() const { return elements_; }
-
- const sass::vector& keys() const { return _keys; }
- const sass::vector& values() const { return _values; }
-
-// std::unordered_map::iterator end() { return elements_.end(); }
-// std::unordered_map::iterator begin() { return elements_.begin(); }
-// std::unordered_map::const_iterator end() const { return elements_.end(); }
-// std::unordered_map::const_iterator begin() const { return elements_.begin(); }
-
- };
- template
- inline Hashed::~Hashed() { }
-
- /////////////////////////////////////////////////////////////////////////
- // Abstract base class for statements. This side of the AST hierarchy
- // represents elements in expansion contexts, which exist primarily to be
- // rewritten and macro-expanded.
- /////////////////////////////////////////////////////////////////////////
- class Statement : public AST_Node {
- public:
- enum Type {
- NONE,
- RULESET,
- MEDIA,
- DIRECTIVE,
- SUPPORTS,
- ATROOT,
- BUBBLE,
- CONTENT,
- KEYFRAMERULE,
- DECLARATION,
- ASSIGNMENT,
- IMPORT_STUB,
- IMPORT,
- COMMENT,
- WARNING,
- RETURN,
- EXTEND,
- ERROR,
- DEBUGSTMT,
- WHILE,
- EACH,
- FOR,
- IF
- };
- private:
- ADD_PROPERTY(Type, statement_type)
- ADD_PROPERTY(size_t, tabs)
- ADD_PROPERTY(bool, group_end)
- public:
- Statement(SourceSpan pstate, Type st = NONE, size_t t = 0);
- virtual ~Statement() = 0; // virtual destructor
- // needed for rearranging nested rulesets during CSS emission
- virtual bool bubbles();
- virtual bool has_content();
- virtual bool is_invisible() const;
- ATTACH_VIRTUAL_AST_OPERATIONS(Statement)
- };
- inline Statement::~Statement() { }
-
- ////////////////////////
- // Blocks of statements.
- ////////////////////////
- class Block final : public Statement, public Vectorized {
- ADD_PROPERTY(bool, is_root)
- // needed for properly formatted CSS emission
- protected:
- void adjust_after_pushing(Statement_Obj s) override {}
- public:
- Block(SourceSpan pstate, size_t s = 0, bool r = false);
- bool isInvisible() const;
- bool has_content() override;
- ATTACH_AST_OPERATIONS(Block)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- ////////////////////////////////////////////////////////////////////////
- // Abstract base class for statements that contain blocks of statements.
- ////////////////////////////////////////////////////////////////////////
- class ParentStatement : public Statement {
- ADD_PROPERTY(Block_Obj, block)
- public:
- ParentStatement(SourceSpan pstate, Block_Obj b);
- ParentStatement(const ParentStatement* ptr); // copy constructor
- virtual ~ParentStatement() = 0; // virtual destructor
- virtual bool has_content() override;
- };
- inline ParentStatement::~ParentStatement() { }
-
- /////////////////////////////////////////////////////////////////////////////
- // Rulesets (i.e., sets of styles headed by a selector and containing a block
- // of style declarations.
- /////////////////////////////////////////////////////////////////////////////
- class StyleRule final : public ParentStatement {
- ADD_PROPERTY(SelectorListObj, selector)
- ADD_PROPERTY(Selector_Schema_Obj, schema)
- ADD_PROPERTY(bool, is_root);
- public:
- StyleRule(SourceSpan pstate, SelectorListObj s = {}, Block_Obj b = {});
- bool is_invisible() const override;
- ATTACH_AST_OPERATIONS(StyleRule)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- /////////////////
- // Bubble.
- /////////////////
- class Bubble final : public Statement {
- ADD_PROPERTY(Statement_Obj, node)
- ADD_PROPERTY(bool, group_end)
- public:
- Bubble(SourceSpan pstate, Statement_Obj n, Statement_Obj g = {}, size_t t = 0);
- bool bubbles() override;
- ATTACH_AST_OPERATIONS(Bubble)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- /////////////////
- // Trace.
- /////////////////
- class Trace final : public ParentStatement {
- ADD_CONSTREF(char, type)
- ADD_CONSTREF(sass::string, name)
- public:
- Trace(SourceSpan pstate, sass::string n, Block_Obj b = {}, char type = 'm');
- ATTACH_AST_OPERATIONS(Trace)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- ///////////////////////////////////////////////////////////////////////
- // At-rules -- arbitrary directives beginning with "@" that may have an
- // optional statement block.
- ///////////////////////////////////////////////////////////////////////
- class AtRule final : public ParentStatement {
- ADD_CONSTREF(sass::string, keyword)
- ADD_PROPERTY(SelectorListObj, selector)
- ADD_PROPERTY(ExpressionObj, value)
- public:
- AtRule(SourceSpan pstate, sass::string kwd, SelectorListObj sel = {}, Block_Obj b = {}, ExpressionObj val = {});
- bool bubbles() override;
- bool is_media();
- bool is_keyframes();
- ATTACH_AST_OPERATIONS(AtRule)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- ///////////////////////////////////////////////////////////////////////
- // Keyframe-rules -- the child blocks of "@keyframes" nodes.
- ///////////////////////////////////////////////////////////////////////
- class Keyframe_Rule final : public ParentStatement {
- // according to css spec, this should be
- // = |
- ADD_PROPERTY(SelectorListObj, name)
- public:
- Keyframe_Rule(SourceSpan pstate, Block_Obj b);
- ATTACH_AST_OPERATIONS(Keyframe_Rule)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- ////////////////////////////////////////////////////////////////////////
- // Declarations -- style rules consisting of a property name and values.
- ////////////////////////////////////////////////////////////////////////
- class Declaration final : public ParentStatement {
- ADD_PROPERTY(String_Obj, property)
- ADD_PROPERTY(ExpressionObj, value)
- ADD_PROPERTY(bool, is_important)
- ADD_PROPERTY(bool, is_custom_property)
- ADD_PROPERTY(bool, is_indented)
- public:
- Declaration(SourceSpan pstate, String_Obj prop, ExpressionObj val, bool i = false, bool c = false, Block_Obj b = {});
- bool is_invisible() const override;
- ATTACH_AST_OPERATIONS(Declaration)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- /////////////////////////////////////
- // Assignments -- variable and value.
- /////////////////////////////////////
- class Assignment final : public Statement {
- ADD_CONSTREF(sass::string, variable)
- ADD_PROPERTY(ExpressionObj, value)
- ADD_PROPERTY(bool, is_default)
- ADD_PROPERTY(bool, is_global)
- public:
- Assignment(SourceSpan pstate, sass::string var, ExpressionObj val, bool is_default = false, bool is_global = false);
- ATTACH_AST_OPERATIONS(Assignment)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // Import directives. CSS and Sass import lists can be intermingled, so it's
- // necessary to store a list of each in an Import node.
- ////////////////////////////////////////////////////////////////////////////
- class Import final : public Statement {
- sass::vector urls_;
- sass::vector incs_;
- ADD_PROPERTY(List_Obj, import_queries);
- public:
- Import(SourceSpan pstate);
- sass::vector& incs();
- sass::vector& urls();
- ATTACH_AST_OPERATIONS(Import)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- // not yet resolved single import
- // so far we only know requested name
- class Import_Stub final : public Statement {
- Include resource_;
- public:
- Import_Stub(SourceSpan pstate, Include res);
- Include resource();
- sass::string imp_path();
- sass::string abs_path();
- ATTACH_AST_OPERATIONS(Import_Stub)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- //////////////////////////////
- // The Sass `@warn` directive.
- //////////////////////////////
- class WarningRule final : public Statement {
- ADD_PROPERTY(ExpressionObj, message)
- public:
- WarningRule(SourceSpan pstate, ExpressionObj msg);
- ATTACH_AST_OPERATIONS(WarningRule)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- ///////////////////////////////
- // The Sass `@error` directive.
- ///////////////////////////////
- class ErrorRule final : public Statement {
- ADD_PROPERTY(ExpressionObj, message)
- public:
- ErrorRule(SourceSpan pstate, ExpressionObj msg);
- ATTACH_AST_OPERATIONS(ErrorRule)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- ///////////////////////////////
- // The Sass `@debug` directive.
- ///////////////////////////////
- class DebugRule final : public Statement {
- ADD_PROPERTY(ExpressionObj, value)
- public:
- DebugRule(SourceSpan pstate, ExpressionObj val);
- ATTACH_AST_OPERATIONS(DebugRule)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- ///////////////////////////////////////////
- // CSS comments. These may be interpolated.
- ///////////////////////////////////////////
- class Comment final : public Statement {
- ADD_PROPERTY(String_Obj, text)
- ADD_PROPERTY(bool, is_important)
- public:
- Comment(SourceSpan pstate, String_Obj txt, bool is_important);
- virtual bool is_invisible() const override;
- ATTACH_AST_OPERATIONS(Comment)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- ////////////////////////////////////
- // The Sass `@if` control directive.
- ////////////////////////////////////
- class If final : public ParentStatement {
- ADD_PROPERTY(ExpressionObj, predicate)
- ADD_PROPERTY(Block_Obj, alternative)
- public:
- If(SourceSpan pstate, ExpressionObj pred, Block_Obj con, Block_Obj alt = {});
- virtual bool has_content() override;
- ATTACH_AST_OPERATIONS(If)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- /////////////////////////////////////
- // The Sass `@for` control directive.
- /////////////////////////////////////
- class ForRule final : public ParentStatement {
- ADD_CONSTREF(sass::string, variable)
- ADD_PROPERTY(ExpressionObj, lower_bound)
- ADD_PROPERTY(ExpressionObj, upper_bound)
- ADD_PROPERTY(bool, is_inclusive)
- public:
- ForRule(SourceSpan pstate, sass::string var, ExpressionObj lo, ExpressionObj hi, Block_Obj b, bool inc);
- ATTACH_AST_OPERATIONS(ForRule)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- //////////////////////////////////////
- // The Sass `@each` control directive.
- //////////////////////////////////////
- class EachRule final : public ParentStatement {
- ADD_PROPERTY(sass::vector, variables)
- ADD_PROPERTY(ExpressionObj, list)
- public:
- EachRule(SourceSpan pstate, sass::vector vars, ExpressionObj lst, Block_Obj b);
- ATTACH_AST_OPERATIONS(EachRule)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- ///////////////////////////////////////
- // The Sass `@while` control directive.
- ///////////////////////////////////////
- class WhileRule final : public ParentStatement {
- ADD_PROPERTY(ExpressionObj, predicate)
- public:
- WhileRule(SourceSpan pstate, ExpressionObj pred, Block_Obj b);
- ATTACH_AST_OPERATIONS(WhileRule)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- /////////////////////////////////////////////////////////////
- // The @return directive for use inside SassScript functions.
- /////////////////////////////////////////////////////////////
- class Return final : public Statement {
- ADD_PROPERTY(ExpressionObj, value)
- public:
- Return(SourceSpan pstate, ExpressionObj val);
- ATTACH_AST_OPERATIONS(Return)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- /////////////////////////////////////////////////////////////////////////////
- // Definitions for both mixins and functions. The two cases are distinguished
- // by a type tag.
- /////////////////////////////////////////////////////////////////////////////
- class Definition final : public ParentStatement {
- public:
- enum Type { MIXIN, FUNCTION };
- ADD_CONSTREF(sass::string, name)
- ADD_PROPERTY(Parameters_Obj, parameters)
- ADD_PROPERTY(Env*, environment)
- ADD_PROPERTY(Type, type)
- ADD_PROPERTY(Native_Function, native_function)
- ADD_PROPERTY(Sass_Function_Entry, c_function)
- ADD_PROPERTY(void*, cookie)
- ADD_PROPERTY(bool, is_overload_stub)
- ADD_PROPERTY(Signature, signature)
- public:
- Definition(SourceSpan pstate,
- sass::string n,
- Parameters_Obj params,
- Block_Obj b,
- Type t);
- Definition(SourceSpan pstate,
- Signature sig,
- sass::string n,
- Parameters_Obj params,
- Native_Function func_ptr,
- bool overload_stub = false);
- Definition(SourceSpan pstate,
- Signature sig,
- sass::string n,
- Parameters_Obj params,
- Sass_Function_Entry c_func);
- ATTACH_AST_OPERATIONS(Definition)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- //////////////////////////////////////
- // Mixin calls (i.e., `@include ...`).
- //////////////////////////////////////
- class Mixin_Call final : public ParentStatement {
- ADD_CONSTREF(sass::string, name)
- ADD_PROPERTY(Arguments_Obj, arguments)
- ADD_PROPERTY(Parameters_Obj, block_parameters)
- public:
- Mixin_Call(SourceSpan pstate, sass::string n, Arguments_Obj args, Parameters_Obj b_params = {}, Block_Obj b = {});
- ATTACH_AST_OPERATIONS(Mixin_Call)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- ///////////////////////////////////////////////////
- // The @content directive for mixin content blocks.
- ///////////////////////////////////////////////////
- class Content final : public Statement {
- ADD_PROPERTY(Arguments_Obj, arguments)
- public:
- Content(SourceSpan pstate, Arguments_Obj args);
- ATTACH_AST_OPERATIONS(Content)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // Arithmetic negation (logical negation is just an ordinary function call).
- ////////////////////////////////////////////////////////////////////////////
- class Unary_Expression final : public Expression {
- public:
- enum Type { PLUS, MINUS, NOT, SLASH };
- private:
- HASH_PROPERTY(Type, optype)
- HASH_PROPERTY(ExpressionObj, operand)
- mutable size_t hash_;
- public:
- Unary_Expression(SourceSpan pstate, Type t, ExpressionObj o);
- const sass::string type_name();
- virtual bool operator==(const Expression& rhs) const override;
- size_t hash() const override;
- ATTACH_AST_OPERATIONS(Unary_Expression)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- ////////////////////////////////////////////////////////////
- // Individual argument objects for mixin and function calls.
- ////////////////////////////////////////////////////////////
- class Argument final : public Expression {
- HASH_PROPERTY(ExpressionObj, value)
- HASH_CONSTREF(sass::string, name)
- ADD_PROPERTY(bool, is_rest_argument)
- ADD_PROPERTY(bool, is_keyword_argument)
- mutable size_t hash_;
- public:
- Argument(SourceSpan pstate, ExpressionObj val, sass::string n = "", bool rest = false, bool keyword = false);
- void set_delayed(bool delayed) override;
- bool operator==(const Expression& rhs) const override;
- size_t hash() const override;
- ATTACH_AST_OPERATIONS(Argument)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- ////////////////////////////////////////////////////////////////////////
- // Argument lists -- in their own class to facilitate context-sensitive
- // error checking (e.g., ensuring that all ordinal arguments precede all
- // named arguments).
- ////////////////////////////////////////////////////////////////////////
- class Arguments final : public Expression, public Vectorized {
- ADD_PROPERTY(bool, has_named_arguments)
- ADD_PROPERTY(bool, has_rest_argument)
- ADD_PROPERTY(bool, has_keyword_argument)
- protected:
- void adjust_after_pushing(Argument_Obj a) override;
- public:
- Arguments(SourceSpan pstate);
- void set_delayed(bool delayed) override;
- Argument_Obj get_rest_argument();
- Argument_Obj get_keyword_argument();
- ATTACH_AST_OPERATIONS(Arguments)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
-
- // A Media StyleRule before it has been evaluated
- // Could be already final or an interpolation
- class MediaRule final : public ParentStatement {
- ADD_PROPERTY(List_Obj, schema)
- public:
- MediaRule(SourceSpan pstate, Block_Obj block = {});
-
- bool bubbles() override { return true; };
- bool is_invisible() const override { return false; };
- ATTACH_AST_OPERATIONS(MediaRule)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- // A Media StyleRule after it has been evaluated
- // Representing the static or resulting css
- class CssMediaRule final : public ParentStatement,
- public Vectorized {
- public:
- CssMediaRule(SourceSpan pstate, Block_Obj b);
- bool bubbles() override { return true; };
- bool isInvisible() const { return empty(); }
- bool is_invisible() const override { return false; };
-
- public:
- // Hash and equality implemtation from vector
- size_t hash() const override { return Vectorized::hash(); }
- // Check if two instances are considered equal
- bool operator== (const CssMediaRule& rhs) const {
- return Vectorized::operator== (rhs);
- }
- bool operator!=(const CssMediaRule& rhs) const {
- // Invert from equality
- return !(*this == rhs);
- }
-
- ATTACH_AST_OPERATIONS(CssMediaRule)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- // Media Queries after they have been evaluated
- // Representing the static or resulting css
- class CssMediaQuery final : public AST_Node {
-
- // The modifier, probably either "not" or "only".
- // This may be `null` if no modifier is in use.
- ADD_PROPERTY(sass::string, modifier);
-
- // The media type, for example "screen" or "print".
- // This may be `null`. If so, [features] will not be empty.
- ADD_PROPERTY(sass::string, type);
-
- // Feature queries, including parentheses.
- ADD_PROPERTY(sass::vector, features);
-
- public:
- CssMediaQuery(SourceSpan pstate);
-
- // Check if two instances are considered equal
- bool operator== (const CssMediaQuery& rhs) const;
- bool operator!=(const CssMediaQuery& rhs) const {
- // Invert from equality
- return !(*this == rhs);
- }
-
- // Returns true if this query is empty
- // Meaning it has no type and features
- bool empty() const {
- return type_.empty()
- && modifier_.empty()
- && features_.empty();
- }
-
- // Whether this media query matches all media types.
- bool matchesAllTypes() const {
- return type_.empty() || Util::equalsLiteral("all", type_);
- }
-
- // Merges this with [other] and adds a query that matches the intersection
- // of both inputs to [result]. Returns false if the result is unrepresentable
- CssMediaQuery_Obj merge(CssMediaQuery_Obj& other);
-
- ATTACH_AST_OPERATIONS(CssMediaQuery)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- ////////////////////////////////////////////////////
- // Media queries (replaced by MediaRule at al).
- // ToDo: only used for interpolation case
- ////////////////////////////////////////////////////
- class Media_Query final : public Expression,
- public Vectorized {
- ADD_PROPERTY(String_Obj, media_type)
- ADD_PROPERTY(bool, is_negated)
- ADD_PROPERTY(bool, is_restricted)
- public:
- Media_Query(SourceSpan pstate, String_Obj t = {}, size_t s = 0, bool n = false, bool r = false);
- ATTACH_AST_OPERATIONS(Media_Query)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- ////////////////////////////////////////////////////
- // Media expressions (for use inside media queries).
- // ToDo: only used for interpolation case
- ////////////////////////////////////////////////////
- class Media_Query_Expression final : public Expression {
- ADD_PROPERTY(ExpressionObj, feature)
- ADD_PROPERTY(ExpressionObj, value)
- ADD_PROPERTY(bool, is_interpolated)
- public:
- Media_Query_Expression(SourceSpan pstate, ExpressionObj f, ExpressionObj v, bool i = false);
- ATTACH_AST_OPERATIONS(Media_Query_Expression)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- /////////////////////////////////////////////////
- // At root expressions (for use inside @at-root).
- /////////////////////////////////////////////////
- class At_Root_Query final : public Expression {
- private:
- ADD_PROPERTY(ExpressionObj, feature)
- ADD_PROPERTY(ExpressionObj, value)
- public:
- At_Root_Query(SourceSpan pstate, ExpressionObj f = {}, ExpressionObj v = {}, bool i = false);
- bool exclude(sass::string str);
- ATTACH_AST_OPERATIONS(At_Root_Query)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- ///////////
- // At-root.
- ///////////
- class AtRootRule final : public ParentStatement {
- ADD_PROPERTY(At_Root_Query_Obj, expression)
- public:
- AtRootRule(SourceSpan pstate, Block_Obj b = {}, At_Root_Query_Obj e = {});
- bool bubbles() override;
- bool exclude_node(Statement_Obj s);
- ATTACH_AST_OPERATIONS(AtRootRule)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- /////////////////////////////////////////////////////////
- // Individual parameter objects for mixins and functions.
- /////////////////////////////////////////////////////////
- class Parameter final : public AST_Node {
- ADD_CONSTREF(sass::string, name)
- ADD_PROPERTY(ExpressionObj, default_value)
- ADD_PROPERTY(bool, is_rest_parameter)
- public:
- Parameter(SourceSpan pstate, sass::string n, ExpressionObj def = {}, bool rest = false);
- ATTACH_AST_OPERATIONS(Parameter)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
- /////////////////////////////////////////////////////////////////////////
- // Parameter lists -- in their own class to facilitate context-sensitive
- // error checking (e.g., ensuring that all optional parameters follow all
- // required parameters).
- /////////////////////////////////////////////////////////////////////////
- class Parameters final : public AST_Node, public Vectorized {
- ADD_PROPERTY(bool, has_optional_parameters)
- ADD_PROPERTY(bool, has_rest_parameter)
- protected:
- void adjust_after_pushing(Parameter_Obj p) override;
- public:
- Parameters(SourceSpan pstate);
- ATTACH_AST_OPERATIONS(Parameters)
- ATTACH_CRTP_PERFORM_METHODS()
- };
-
-}
-
-#include "ast_values.hpp"
-#include "ast_supports.hpp"
+#include "ast_fwd_decl.hpp"
+#include "ast_helpers.hpp"
+#include "ast_nodes.hpp"
#include "ast_selectors.hpp"
-
-#ifdef __clang__
-
-// #pragma clang diagnostic pop
-// #pragma clang diagnostic push
-
-#endif
+#include "ast_statements.hpp"
+#include "ast_supports.hpp"
+#include "ast_values.hpp"
#endif
diff --git a/src/ast2.hpp b/src/ast2.hpp
new file mode 100644
index 0000000000..2d6ef1bef5
--- /dev/null
+++ b/src/ast2.hpp
@@ -0,0 +1,1560 @@
+#ifndef SASS_AST_H
+#define SASS_AST_H
+
+// sass.hpp must go before all system headers to get the
+// __EXTENSIONS__ fix on Solaris.
+#include "sass.hpp"
+
+#include
+#include
+#include
+
+#include "sass/base.h"
+#include "ast_helpers.hpp"
+#include "ast_fwd_decl.hpp"
+#include "ast_def_macros.hpp"
+#include "ordered_map.hpp"
+
+#include "file.hpp"
+#include "memory.hpp"
+#include "mapping.hpp"
+#include "position.hpp"
+#include "operation.hpp"
+#include "environment.hpp"
+#include "fn_utils.hpp"
+#include "environment_stack.hpp"
+
+#include "ordered-map/ordered_map.h"
+
+namespace Sass {
+
+ uint8_t sass_op_to_precedence(enum Sass_OP op);
+
+ const char* sass_op_to_name(enum Sass_OP op);
+
+ const char* sass_op_separator(enum Sass_OP op);
+
+ //////////////////////////////////////////////////////////
+ // Abstract base class for all abstract syntax tree nodes.
+ //////////////////////////////////////////////////////////
+ class AST_Node : public SharedObj {
+ ADD_PROPERTY(SourceSpan, pstate);
+ public:
+ AST_Node(const SourceSpan& pstate)
+ : SharedObj(), pstate_(pstate)
+ { }
+ AST_Node(SourceSpan&& pstate)
+ : SharedObj(), pstate_(std::move(pstate))
+ { }
+ AST_Node(const AST_Node* ptr)
+ : pstate_(ptr->pstate_)
+ { }
+
+ // void* operator new(size_t nbytes) {
+ // return ::operator new(nbytes);
+ // }
+ //
+ // void operator delete(void* ptr) {
+ // return ::operator delete(ptr);
+ // }
+
+ // allow implicit conversion to string
+ // needed for by SharedPtr implementation
+ operator sass::string() {
+ return to_string();
+ }
+
+ // AST_Node(AST_Node& ptr) = delete;
+
+ virtual ~AST_Node() = 0;
+ virtual size_t hash() const { return 0; }
+ virtual sass::string inspect() const { return to_string({ INSPECT, 5 }); }
+ virtual sass::string to_sass() const { return to_string({ TO_SASS, 5 }); }
+ virtual sass::string to_string(Sass_Inspect_Options opt) const;
+ virtual sass::string to_css(Sass_Inspect_Options opt, bool quotes = false) const;
+ virtual sass::string to_css(Sass_Inspect_Options opt, sass::vector& mappings, bool quotes = false) const;
+ virtual sass::string to_string() const;
+ virtual sass::string to_css(sass::vector& mappings, bool quotes = false) const;
+ virtual sass::string to_css(bool quotes = false) const;
+ virtual void cloneChildren() {};
+ // generic find function (not fully implemented yet)
+ // ToDo: add specific implementions to all children
+ virtual bool find ( bool (*f)(AST_Node_Obj) ) { return f(this); };
+ // Offset off() { return pstate(); }
+ // Position pos() { return pstate(); }
+
+ // Subclasses should only override these methods
+ // The full set is emulated by calling only those
+ // Make sure the left side is resonably upcasted!
+ virtual bool operator< (const AST_Node& rhs) const {
+ throw std::runtime_error("operator< not implemented");
+ }
+ virtual bool operator== (const AST_Node& rhs) const {
+ throw std::runtime_error("operator== not implemented");
+ }
+
+
+ // We can give some reasonable implementations by using
+ // inverst operators on the specialized implementations
+ virtual bool operator>(const AST_Node& rhs) const { return rhs < *this; };
+ virtual bool operator<=(const AST_Node& rhs) const { return !(rhs < *this); };
+ virtual bool operator>=(const AST_Node& rhs) const { return !(*this < rhs); };
+ virtual bool operator!=(const AST_Node& rhs) const { return !(*this == rhs); }
+
+ ATTACH_ABSTRACT_COPY_OPERATIONS(AST_Node);
+ ATTACH_ABSTRACT_CRTP_PERFORM_METHODS()
+ };
+ 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;
+ };
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ class SassNode : public AST_Node {
+ public:
+ SassNode(const SourceSpan& pstate) :
+ AST_Node(pstate) {};
+ SassNode(SourceSpan&& pstate) :
+ AST_Node(std::move(pstate)) {};
+ ATTACH_VIRTUAL_COPY_OPERATIONS(SassNode);
+ ATTACH_CRTP_PERFORM_METHODS();
+ };
+
+ class CallableInvocation {
+ // The arguments passed to the callable.
+ ADD_PROPERTY(ArgumentInvocationObj, arguments);
+ public:
+ CallableInvocation(
+ ArgumentInvocation* arguments) :
+ arguments_(arguments) {}
+ };
+
+
+ class ArgumentDeclaration : public SassNode {
+
+ // The arguments that are taken.
+ ADD_CONSTREF(sass::vector, arguments);
+
+ // The name of the rest argument (as in `$args...`),
+ // or `null` if none was declared.
+ ADD_CONSTREF(sass::string, restArg);
+
+ public:
+
+ ArgumentDeclaration(
+ const SourceSpan& pstate,
+ const sass::vector& arguments,
+ const sass::string& restArg = "");
+
+ bool isEmpty() const {
+ return arguments_.empty()
+ && restArg_.empty();
+ }
+
+ static ArgumentDeclaration* parse(
+ Context& context,
+ const sass::string& contents);
+
+ void verify(
+ size_t positional,
+ const KeywordMap& names,
+ const SourceSpan& pstate,
+ const Backtraces& traces);
+
+ bool matches(
+ size_t positional,
+ const KeywordMap& names);
+
+ sass::string toString2() const;
+
+ };
+
+
+ /// The result of evaluating arguments to a function or mixin.
+ class ArgumentResults2 {
+
+ // Arguments passed by position.
+ ADD_REF(sass::vector, positional);
+
+ // The [AstNode]s that hold the spans for each [positional]
+ // argument, or `null` if source span tracking is disabled. This
+ // stores [AstNode]s rather than [FileSpan]s so it can avoid
+ // calling [AstNode.span] if the span isn't required, since
+ // some nodes need to do real work to manufacture a source span.
+ // sass::vector positionalNodes;
+
+ // Arguments passed by name.
+ // A list implementation might be more efficient
+ // I dont expect any function to have many arguments
+ // Normally the tradeoff is around 8 items in the list
+ ADD_REF(KeywordMap, named);
+
+ // The [AstNode]s that hold the spans for each [named] argument,
+ // or `null` if source span tracking is disabled. This stores
+ // [AstNode]s rather than [FileSpan]s so it can avoid calling
+ // [AstNode.span] if the span isn't required, since some nodes
+ // need to do real work to manufacture a source span.
+ // KeywordMap namedNodes;
+
+ // The separator used for the rest argument list, if any.
+ ADD_REF(Sass_Separator, separator);
+
+ public:
+
+ ArgumentResults2() {};
+
+ ArgumentResults2(
+ const ArgumentResults2& other);
+
+ ArgumentResults2(
+ ArgumentResults2&& other);
+
+ ArgumentResults2& operator=(
+ ArgumentResults2&& other);
+
+ ArgumentResults2(
+ const sass::vector& positional,
+ const KeywordMap& named,
+ Sass_Separator separator);
+
+ ArgumentResults2(
+ sass::vector && positional,
+ KeywordMap&& named,
+ Sass_Separator separator);
+
+ };
+
+
+ class ArgumentInvocation : public SassNode {
+
+ // The arguments passed by position.
+ ADD_REF(sass::vector, positional);
+ public:
+ //
+ ArgumentResults2 evaluated;
+
+ // The arguments passed by name.
+ ADD_CONSTREF(KeywordMap, named);
+
+ // The first rest argument (as in `$args...`).
+ ADD_PROPERTY(ExpressionObj, restArg);
+
+ // The second rest argument, which is expected to only contain a keyword map.
+ ADD_PROPERTY(ExpressionObj, kwdRest);
+
+ public:
+
+ ArgumentInvocation(const SourceSpan& pstate,
+ const sass::vector& positional,
+ const KeywordMap& named,
+ Expression* restArgs = nullptr,
+ Expression* kwdRest = nullptr);
+
+ // Returns whether this invocation passes no arguments.
+ bool isEmpty() const;
+
+ sass::string toString() const;
+
+ ATTACH_CRTP_PERFORM_METHODS();
+
+ };
+
+ //////////////////////////////////////////////////////////////////////
+ // Abstract base class for expressions. This side of the AST hierarchy
+ // represents elements in value contexts, which exist primarily to be
+ // evaluated and returned.
+ //////////////////////////////////////////////////////////////////////
+ class Expression : public SassNode {
+ public:
+ enum Type {
+ NONE,
+ BOOLEAN,
+ NUMBER,
+ COLOR,
+ STRING,
+ LIST,
+ MAP,
+ NULL_VAL,
+ FUNCTION_VAL,
+ C_WARNING,
+ C_ERROR,
+ FUNCTION,
+ VARIABLE,
+ PARENT,
+ NUM_TYPES
+ };
+ private:
+ // expressions in some contexts shouldn't be evaluated
+ ADD_PROPERTY(Type, concrete_type)
+ public:
+ Expression(SourceSpan&& pstate, bool d = false, bool e = false, bool i = false, Type ct = NONE);
+ Expression(const SourceSpan& pstate, bool d = false, bool e = false, bool i = false, Type ct = NONE);
+ virtual operator bool() { return true; }
+ virtual ~Expression() { }
+ virtual bool is_invisible() const { return false; }
+
+ virtual const sass::string& type() const {
+ throw std::runtime_error("Invalid reflection");
+ }
+
+ virtual Expression* withoutSlash() {
+ return this;
+ }
+
+ virtual Expression* removeSlash() {
+ return this;
+ }
+
+ virtual bool is_false() { return false; }
+ // virtual bool is_true() { return !is_false(); }
+ virtual bool operator== (const Expression& rhs) const { return false; }
+ inline bool operator!=(const Expression& rhs) const { return !(rhs == *this); }
+ ATTACH_VIRTUAL_COPY_OPERATIONS(Expression);
+ size_t hash() const override { return 0; }
+ };
+
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Hash method specializations for std::unordered_map to work with Sass::Expression
+/////////////////////////////////////////////////////////////////////////////////////
+
+namespace std {
+ template<>
+ struct hash
+ {
+ size_t operator()(Sass::Expression_Obj s) const
+ {
+ return s->hash();
+ }
+ };
+ template<>
+ struct equal_to
+ {
+ bool operator()( Sass::Expression_Obj lhs, Sass::Expression_Obj rhs) const
+ {
+ return lhs->hash() == rhs->hash();
+ }
+ };
+}
+
+namespace Sass {
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Mixin class for AST nodes that should behave like vectors. Uses the
+ // "Template Method" design pattern to allow subclasses to adjust their flags
+ // when certain objects are pushed.
+ /////////////////////////////////////////////////////////////////////////////
+ template
+ class Vectorized {
+ sass::vector elements_;
+ protected:
+ mutable size_t hash_;
+ void reset_hash() { hash_ = 0; }
+ public:
+ Vectorized(size_t s = 0) : hash_(0)
+ { elements_.reserve(s); }
+ Vectorized(const Vectorized* vec) :
+ elements_(vec->elements_),
+ hash_(0)
+ {}
+ Vectorized(sass::vector vec) :
+ elements_(std::move(vec)),
+ hash_(0)
+ {}
+ ~Vectorized() {};
+ size_t length() const { return elements_.size(); }
+ bool empty() const { return elements_.empty(); }
+ void clear() { return elements_.clear(); }
+ T& last() { return elements_.back(); }
+ T& first() { return elements_.front(); }
+ const T& last() const { return elements_.back(); }
+ const T& first() const { return elements_.front(); }
+
+ bool operator== (const Vectorized& rhs) const {
+ // Abort early if sizes do not match
+ if (length() != rhs.length()) return false;
+ // Otherwise test each node for object equalicy in order
+ return std::equal(begin(), end(), rhs.begin(), ObjEqualityFn);
+ }
+
+ bool operator!= (const Vectorized& rhs) const {
+ return !(*this == rhs);
+ }
+
+ T& operator[](size_t i) { return elements_[i]; }
+ virtual const T& at(size_t i) const { return elements_.at(i); }
+ virtual T& at(size_t i) { return elements_.at(i); }
+ const T& get(size_t i) const { return elements_[i]; }
+ // ToDo: might insert am item (update ordered list)
+ const T& operator[](size_t i) const { return elements_[i]; }
+
+ // Implicitly get the std::vector from our object
+ // Makes the Vector directly assignable to std::vector
+ // You are responsible to make a copy if needed
+ // Note: since this returns the real object, we can't
+ // Note: guarantee that the hash will not get out of sync
+ operator sass::vector&() { return elements_; }
+ operator const sass::vector&() const { return elements_; }
+
+ // Explicitly request all elements as a real std::vector
+ // You are responsible to make a copy if needed
+ // Note: since this returns the real object, we can't
+ // Note: guarantee that the hash will not get out of sync
+ sass::vector& elements() { return elements_; }
+ const sass::vector& elements() const { return elements_; }
+
+ // Insert all items from compatible vector
+ void concat(const sass::vector& v)
+ {
+ if (!v.empty()) reset_hash();
+ elements().insert(end(), v.begin(), v.end());
+ }
+
+ // Insert all items from compatible vector
+ void concat(sass::vector&& v)
+ {
+ if (!v.empty()) reset_hash();
+ std::move(v.begin(), v.end(),
+ std::back_inserter(elements_));
+ // elements().insert(end(), v.begin(), v.end());
+ }
+
+
+ // Syntatic sugar for pointers
+ void concat(const Vectorized* v)
+ {
+ if (v != nullptr) {
+ return concat(*v);
+ }
+ }
+
+ // Insert one item on the front
+ void unshift(T element)
+ {
+ reset_hash();
+ elements_.insert(begin(), element);
+ }
+
+ // Remove and return item on the front
+ // ToDo: handle empty vectors
+ T shift() {
+ reset_hash();
+ T first = get(0);
+ elements_.erase(begin());
+ return first;
+ }
+
+ // Insert one item on the back
+ // ToDo: rename this to push
+ void append(T element)
+ {
+ if (!element) {
+ std::cerr << "APPEND NULL PTR\n";
+ }
+ reset_hash();
+ elements_.emplace_back(element);
+ }
+
+ // Check if an item already exists
+ // Uses underlying object `operator==`
+ // E.g. compares the actual objects
+ bool contains(const T& el) const {
+ for (const T& rhs : elements_) {
+ // Test the underlying objects for equality
+ // A std::find checks for pointer equality
+ if (ObjEqualityFn(el, rhs)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // This might be better implemented as `operator=`?
+ void elements(sass::vector e) {
+ reset_hash();
+ elements_ = std::move(e);
+ }
+
+ virtual size_t hash() const
+ {
+ if (hash_ == 0) {
+ for (const T& el : elements_) {
+ hash_combine(hash_, el->hash());
+ }
+ }
+ return hash_;
+ }
+
+ template
+ typename sass::vector::iterator insert(P position, const V& val) {
+ reset_hash();
+ return elements_.insert(position, val);
+ }
+
+ typename sass::vector::iterator end() { return elements_.end(); }
+ typename sass::vector::iterator begin() { return elements_.begin(); }
+ typename sass::vector::const_iterator end() const { return elements_.end(); }
+ typename sass::vector::const_iterator begin() const { return elements_.begin(); }
+ typename sass::vector::iterator erase(typename sass::vector::iterator el) { reset_hash(); return elements_.erase(el); }
+ typename sass::vector::const_iterator erase(typename sass::vector::const_iterator el) { reset_hash(); return elements_.erase(el); }
+
+ };
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Mixin class for AST nodes that should behave like a hash table. Uses an
+ // extra internally to maintain insertion order for interation.
+ /////////////////////////////////////////////////////////////////////////////
+ template
+ class Hashed {
+
+
+ using ordered_map_type = typename tsl::ordered_map<
+ K, T, ObjHash, ObjEquality,
+ SassAllocator>,
+ sass::vector>
+ >;
+
+ protected:
+
+ ordered_map_type elements_;
+
+ mutable size_t hash_;
+
+ void reset_hash() { hash_ = 0; }
+
+ public:
+
+ Hashed()
+ : elements_(),
+ hash_(0)
+ {
+ // elements_.reserve(s);
+ }
+
+ // Copy constructor
+ Hashed(const Hashed& copy) :
+ elements_(), hash_(0)
+ {
+ // this seems to expensive!?
+ // elements_.reserve(copy.size());
+ elements_ = copy.elements_;
+ };
+
+ // Move constructor
+ Hashed(Hashed&& move) :
+ elements_(std::move(move.elements_)),
+ hash_(move.hash_) {};
+
+ virtual ~Hashed();
+
+ size_t size() const { return elements_.size(); }
+ bool empty() const { return elements_.empty(); }
+
+ bool has(K k) const {
+ return elements_.count(k) == 1;
+ }
+
+ void reserve(size_t size)
+ {
+ elements_.reserve(size);
+ }
+
+ T at(K k) const {
+ auto it = elements_.find(k);
+ if (it == elements_.end()) return {};
+ else return it->second;
+ }
+
+ bool erase(K key)
+ {
+ reset_hash();
+ return elements_.erase(key);
+ }
+
+ void set(std::pair& kv)
+ {
+ reset_hash();
+ elements_[kv.first] = kv.second;
+ }
+
+ void insert(K key, T val)
+ {
+ reset_hash();
+ elements_[key] = val;
+ }
+
+ void concat(Hashed arr)
+ {
+ reset_hash();
+ for (const auto& kv : arr) {
+ elements_[kv.first] = kv.second;
+ }
+ // elements_.append(arr.elements());
+ }
+
+ // Return unmodifiable reference
+ const ordered_map_type& elements() const {
+ return elements_;
+ }
+
+ const sass::vector keys() const {
+ sass::vector list;
+ for (auto kv : elements_) {
+ list.emplace_back(kv.first);
+ }
+ return list;
+ }
+ const sass::vector values() const {
+ sass::vector list;
+ for (auto kv : elements_) {
+ list.emplace_back(kv.second);
+ }
+ return list;
+ }
+
+ typename ordered_map_type::iterator end() { return elements_.end(); }
+ typename ordered_map_type::iterator begin() { return elements_.begin(); }
+ typename ordered_map_type::const_iterator end() const { return elements_.end(); }
+ typename ordered_map_type::const_iterator begin() const { return elements_.begin(); }
+
+ };
+
+ template
+ inline Hashed::~Hashed() { }
+
+ /////////////////////////////////////////////////////////////////////////
+ // Abstract base class for statements. This side of the AST hierarchy
+ // represents elements in expansion contexts, which exist primarily to be
+ // rewritten and macro-expanded.
+ /////////////////////////////////////////////////////////////////////////
+ class Statement : public AST_Node {
+ private:
+ ADD_PROPERTY(size_t, tabs)
+ ADD_PROPERTY(bool, group_end)
+ public:
+ Statement(SourceSpan&& pstate, size_t t = 0);
+ Statement(const SourceSpan& pstate, size_t t = 0);
+ virtual ~Statement() = 0; // virtual destructor
+ // needed for rearranging nested rulesets during CSS emission
+ virtual bool bubbles() const;
+ virtual bool has_content();
+ virtual bool is_invisible() const;
+ ATTACH_VIRTUAL_COPY_OPERATIONS(Statement)
+ };
+ inline Statement::~Statement() { }
+
+ ////////////////////////
+ // Blocks of statements.
+ ////////////////////////
+ class Block final : public Statement, public Vectorized {
+ ADD_POINTER(IDXS*, idxs);
+ ADD_PROPERTY(bool, is_root);
+ // needed for properly formatted CSS emission
+ public:
+ Block(const SourceSpan& pstate, size_t s = 0, bool r = false);
+ Block(const SourceSpan& pstate, const sass::vector& vec, bool r = false);
+ Block(const SourceSpan& pstate, sass::vector&& vec, bool r = false);
+ bool isInvisible() const;
+ bool is_invisible() const override {
+ return isInvisible();
+ }
+ bool has_content() override;
+ // ATTACH_CLONE_OPERATIONS(Block)
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ ////////////////////////////////////////////////////////////////////////
+ // Abstract base class for statements that contain blocks of statements.
+ ////////////////////////////////////////////////////////////////////////
+
+ // [X] AtRootRule
+ // [X] AtRule
+ // [X] CallableDeclaration
+ // [X] Declaration
+ // [X] EachRule
+ // [X] ForRule
+ // [X] MediaRule
+ // [X] StyleRule
+ // [ ] Stylesheet
+ // [X] SupportsRule
+ // [X] WhileRule
+ class ParentStatement : public Statement {
+ ADD_PROPERTY(Block_Obj, block)
+ public:
+ void concat(const sass::vector& vec) {
+ if (block_.ptr() == nullptr) {
+ block_ = SASS_MEMORY_NEW(Block, pstate_);
+ }
+ block_->concat(vec);
+ }
+ void concat(sass::vector&& vec) {
+ if (block_.ptr() == nullptr) {
+ block_ = SASS_MEMORY_NEW(Block, pstate_);
+ }
+ block_->concat(std::move(vec));
+ }
+ ParentStatement(SourceSpan&& pstate, Block_Obj b);
+ ParentStatement(const SourceSpan& pstate, Block_Obj b);
+ ParentStatement(const ParentStatement* ptr); // copy constructor
+ virtual ~ParentStatement() = 0; // virtual destructor
+ virtual bool has_content() override;
+ };
+ inline ParentStatement::~ParentStatement() { }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // A style rule. This applies style declarations to elements
+ // that match a given selector. Formerly known as `Ruleset`.
+ /////////////////////////////////////////////////////////////////////////////
+ class StyleRule final : public ParentStatement {
+ // The selector to which the declaration will be applied.
+ // This is only parsed after the interpolation has been resolved.
+ ADD_PROPERTY(InterpolationObj, interpolation);
+ ADD_POINTER(IDXS*, idxs);
+ public:
+ StyleRule(SourceSpan&& pstate, Interpolation* s, Block_Obj b = {});
+ bool empty() const { return block().isNull() || block()->empty(); }
+ // ATTACH_CLONE_OPERATIONS(StyleRule)
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ // ToDo: ParentStatement
+ ///////////////////////////////////////////////////////////////////////
+ // At-rules -- arbitrary directives beginning with "@" that may have an
+ // optional statement block.
+ ///////////////////////////////////////////////////////////////////////
+ class AtRule final : public ParentStatement {
+ ADD_PROPERTY(InterpolationObj, name);
+ ADD_PROPERTY(InterpolationObj, value);
+ public:
+ AtRule(const SourceSpan& pstate,
+ InterpolationObj name,
+ ExpressionObj value,
+ Block_Obj b = {});
+ ATTACH_CLONE_OPERATIONS(AtRule);
+ ATTACH_CRTP_PERFORM_METHODS();
+ };
+
+ /////////////////
+ // Bubble.
+ /////////////////
+ class Bubble final : public Statement {
+ ADD_PROPERTY(Statement_Obj, node)
+ ADD_PROPERTY(bool, group_end)
+ public:
+ Bubble(const SourceSpan& pstate, Statement_Obj n, Statement_Obj g = {}, size_t t = 0);
+ bool bubbles() const override final;
+ // ATTACH_CLONE_OPERATIONS(Bubble)
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ /////////////////
+ // Trace.
+ /////////////////
+ class Trace final : public ParentStatement {
+ ADD_CONSTREF(char, type)
+ ADD_CONSTREF(sass::string, name)
+ public:
+ Trace(const SourceSpan& pstate, const sass::string& name, Block_Obj b = {}, char type = 'm');
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ ///////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////
+
+ // An expression that directly embeds a [Value]. This is never
+ // constructed by the parser. It's only used when ASTs are
+ // constructed dynamically, as for the `call()` function.
+ class ValueExpression : public Expression {
+ ADD_PROPERTY(ValueObj, value);
+ public:
+ ValueExpression(
+ const SourceSpan& pstate,
+ ValueObj value);
+ ATTACH_CRTP_PERFORM_METHODS();
+ };
+
+ class ListExpression : public Expression {
+ ADD_CONSTREF(sass::vector, contents);
+ ADD_PROPERTY(Sass_Separator, separator);
+ ADD_PROPERTY(bool, hasBrackets);
+ public:
+ ListExpression(const SourceSpan& pstate, Sass_Separator separator = SASS_UNDEF);
+ void concat(sass::vector& expressions) {
+ std::copy(
+ expressions.begin(), expressions.end(),
+ std::back_inserter(contents_)
+ );
+ }
+ size_t size() const {
+ return contents_.size();
+ }
+ Expression* get(size_t i) {
+ return contents_[i];
+ }
+ void append(Expression* expression) {
+ contents_.emplace_back(expression);
+ }
+ sass::string toString() {
+ // var buffer = StringBuffer();
+ // if (hasBrackets) buffer.writeCharCode($lbracket);
+ // buffer.write(contents
+ // .map((element) = >
+ // _elementNeedsParens(element) ? "($element)" : element.toString())
+ // .join(separator == ListSeparator.comma ? ", " : " "));
+ // if (hasBrackets) buffer.writeCharCode($rbracket);
+ // return buffer.toString();
+ return "ListExpression";
+ }
+ // Returns whether [expression], contained in [this],
+ // needs parentheses when printed as Sass source.
+ bool _elementNeedsParens(Expression* expression) {
+ /*
+ if (expression is ListExpression) {
+ if (expression.contents.length < 2) return false;
+ if (expression.hasBrackets) return false;
+ return separator == ListSeparator.comma
+ ? separator == ListSeparator.comma
+ : separator != ListSeparator.undecided;
+ }
+
+ if (separator != ListSeparator.space) return false;
+
+ if (expression is UnaryOperationExpression) {
+ return expression.operator == UnaryOperator.plus ||
+ expression.operator == UnaryOperator.minus;
+ }
+
+ */
+ return false;
+ }
+ ATTACH_CRTP_PERFORM_METHODS();
+ };
+
+ ///////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////
+
+ class MapExpression final : public Expression {
+ ADD_CONSTREF(sass::vector, kvlist);
+ public:
+ void append(Expression* kv) {
+ kvlist_.emplace_back(kv);
+ }
+ size_t size() const {
+ return kvlist_.size();
+ }
+ Expression* get(size_t i) {
+ return kvlist_[i];
+ }
+ MapExpression(const SourceSpan& pstate);
+ ATTACH_CRTP_PERFORM_METHODS();
+ };
+
+
+ ////////////////////////////////////////////////////////////////////////
+ // Declarations -- style rules consisting of a property name and values.
+ ////////////////////////////////////////////////////////////////////////
+ class Declaration final : public ParentStatement {
+ ADD_PROPERTY(InterpolationObj, name);
+ ADD_PROPERTY(ExpressionObj, value);
+ ADD_PROPERTY(bool, is_custom_property);
+ public:
+ Declaration(const SourceSpan& pstate, InterpolationObj name, ExpressionObj value = {}, bool c = false, Block_Obj b = {});
+ bool is_invisible() const override;
+ // ATTACH_CLONE_OPERATIONS(Declaration)
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ /////////////////////////////////////
+ // Assignments -- variable and value.
+ /////////////////////////////////////
+ class Assignment final : public Statement {
+ ADD_CONSTREF(EnvString, variable);
+ ADD_PROPERTY(ExpressionObj, value);
+ ADD_PROPERTY(IdxRef, vidx);
+ ADD_PROPERTY(bool, is_default);
+ ADD_PROPERTY(bool, is_global);
+ public:
+ Assignment(const SourceSpan& pstate, const sass::string& var, IdxRef vidx, Expression_Obj val, bool is_default = false, bool is_global = false);
+ // ATTACH_CLONE_OPERATIONS(Assignment)
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ class ImportBase : public Statement {
+ public:
+ ImportBase(const SourceSpan& pstate);
+ ATTACH_VIRTUAL_COPY_OPERATIONS(ImportBase);
+ };
+
+ class StaticImport final : public ImportBase {
+ ADD_PROPERTY(InterpolationObj, url);
+ ADD_PROPERTY(CssStringObj, url2);
+ ADD_PROPERTY(SupportsCondition_Obj, supports);
+ ADD_PROPERTY(InterpolationObj, media);
+ ADD_PROPERTY(bool, outOfOrder);
+ public:
+ StaticImport(const SourceSpan& pstate, InterpolationObj url, SupportsCondition_Obj supports = {}, InterpolationObj media = {});
+ // ATTACH_CLONE_OPERATIONS(StaticImport);
+ ATTACH_CRTP_PERFORM_METHODS();
+ };
+
+ class DynamicImport final : public ImportBase {
+ ADD_CONSTREF(sass::string, url);
+ public:
+ DynamicImport(const SourceSpan& pstate, const sass::string& url);
+ // ATTACH_CLONE_OPERATIONS(DynamicImport);
+ ATTACH_CRTP_PERFORM_METHODS();
+ };
+
+
+ class ImportRule final : public Statement, public Vectorized {
+ public:
+ ImportRule(const SourceSpan& pstate);
+ // ATTACH_CLONE_OPERATIONS(ImportRule);
+ ATTACH_CRTP_PERFORM_METHODS();
+ };
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Import directives. CSS and Sass import lists can be intermingled, so it's
+ // necessary to store a list of each in an Import node.
+ ////////////////////////////////////////////////////////////////////////////
+ class Import final : public ImportBase {
+ sass::vector urls_;
+ sass::vector incs_;
+ // sass::vector imports_;
+ ADD_CONSTREF(sass::vector, import_queries);
+ ADD_CONSTREF(sass::vector, queries);
+ public:
+ Import(const SourceSpan& pstate);
+ sass::vector& incs();
+ sass::vector& urls();
+ // sass::vector& imports();
+ sass::vector& queries2();
+ bool is_invisible() const override;
+ // ATTACH_CLONE_OPERATIONS(Import)
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ // not yet resolved single import
+ // so far we only know requested name
+ class Import_Stub final : public ImportBase {
+ Include resource_;
+ // Sass_Import_Entry import_;
+ public:
+ Import_Stub(const SourceSpan& pstate, Include res/*,
+ Sass_Import_Entry import*/);
+ Include resource();
+ // Sass_Import_Entry import();
+ sass::string imp_path();
+ sass::string abs_path();
+ // ATTACH_CLONE_OPERATIONS(Import_Stub)
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ //////////////////////////////
+ // The Sass `@warn` directive.
+ //////////////////////////////
+ class WarnRule final : public Statement {
+ ADD_PROPERTY(ExpressionObj, expression);
+ public:
+ WarnRule(const SourceSpan& pstate,
+ ExpressionObj expression);
+ // String toString() => "@warn $expression;";
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ ///////////////////////////////
+ // The Sass `@error` directive.
+ ///////////////////////////////
+ class ErrorRule final : public Statement {
+ ADD_PROPERTY(ExpressionObj, expression);
+ public:
+ ErrorRule(const SourceSpan& pstate,
+ ExpressionObj expression);
+ // String toString() => "@error $expression;";
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ ///////////////////////////////
+ // The Sass `@debug` directive.
+ ///////////////////////////////
+ class DebugRule final : public Statement {
+ ADD_PROPERTY(ExpressionObj, expression);
+ public:
+ DebugRule(const SourceSpan& pstate,
+ ExpressionObj expression);
+ // String toString() => "@debug $expression;";
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ ///////////////////////////////////////////
+ // CSS comments. These may be interpolated.
+ ///////////////////////////////////////////
+ class LoudComment final : public Statement {
+ // The interpolated text of this comment, including comment characters.
+ ADD_PROPERTY(InterpolationObj, text)
+ public:
+ LoudComment(const SourceSpan& pstate, InterpolationObj itpl);
+ // ATTACH_CLONE_OPERATIONS(LoudComment)
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ class SilentComment final : public Statement {
+ // The text of this comment, including comment characters.
+ ADD_CONSTREF(sass::string, text)
+ public:
+ SilentComment(const SourceSpan& pstate, const sass::string& text);
+ // not used in dart sass beside tests!?
+ // sass::string getDocComment() const;
+ // ATTACH_CLONE_OPERATIONS(SilentComment)
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ ////////////////////////////////////
+ // The Sass `@if` control directive.
+ ////////////////////////////////////
+ class If final : public ParentStatement {
+ ADD_POINTER(IDXS*, idxs);
+ ADD_PROPERTY(Expression_Obj, predicate);
+ ADD_PROPERTY(Block_Obj, alternative);
+ public:
+ If(const SourceSpan& pstate, Expression_Obj pred, Block_Obj con, Block_Obj alt = {});
+ virtual bool has_content() override;
+ // ATTACH_CLONE_OPERATIONS(If)
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ /////////////////////////////////////
+ // The Sass `@for` control directive.
+ /////////////////////////////////////
+ class For final : public ParentStatement {
+ ADD_CONSTREF(EnvString, variable);
+ ADD_PROPERTY(Expression_Obj, lower_bound);
+ ADD_PROPERTY(Expression_Obj, upper_bound);
+ ADD_POINTER(IDXS*, idxs);
+ ADD_PROPERTY(bool, is_inclusive);
+ public:
+ For(const SourceSpan& pstate, const EnvString& var, Expression_Obj lo, Expression_Obj hi, bool inc = false, Block_Obj b = {});
+ // ATTACH_CLONE_OPERATIONS(For)
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ //////////////////////////////////////
+ // The Sass `@each` control directive.
+ //////////////////////////////////////
+ class Each final : public ParentStatement {
+ ADD_CONSTREF(sass::vector, variables);
+ ADD_POINTER(IDXS*, idxs);
+ ADD_PROPERTY(Expression_Obj, list);
+ public:
+ Each(const SourceSpan& pstate, const sass::vector& vars, Expression_Obj lst, Block_Obj b = {});
+ // ATTACH_CLONE_OPERATIONS(Each)
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ ///////////////////////////////////////
+ // The Sass `@while` control directive.
+ ///////////////////////////////////////
+ class WhileRule final : public ParentStatement {
+ ADD_PROPERTY(ExpressionObj, condition);
+ ADD_POINTER(IDXS*, idxs);
+ public:
+ WhileRule(const SourceSpan& pstate,
+ ExpressionObj condition,
+ Block_Obj b = {});
+ // String toString() = > "@while $condition {${children.join(" ")}}";
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ /////////////////////////////////////////////////////////////
+ // The @return directive for use inside SassScript functions.
+ /////////////////////////////////////////////////////////////
+ class Return final : public Statement {
+ ADD_PROPERTY(Expression_Obj, value);
+ public:
+ Return(const SourceSpan& pstate, Expression_Obj val);
+ // ATTACH_CLONE_OPERATIONS(Return)
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ class InvocationExpression :
+ public Expression,
+ public CallableInvocation {
+ public:
+ InvocationExpression(const SourceSpan& pstate,
+ ArgumentInvocation* arguments) :
+ Expression(pstate),
+ CallableInvocation(arguments)
+ {
+ }
+ };
+
+ class InvocationStatement :
+ public Statement,
+ public CallableInvocation {
+ public:
+ InvocationStatement(const SourceSpan& pstate,
+ ArgumentInvocation* arguments) :
+ Statement(pstate),
+ CallableInvocation(arguments)
+ {
+ }
+ };
+
+ /// A function invocation.
+ ///
+ /// This may be a plain CSS function or a Sass function.
+ class IfExpression : public InvocationExpression {
+
+ public:
+ IfExpression(const SourceSpan& pstate,
+ ArgumentInvocation* arguments) :
+ InvocationExpression(pstate, arguments)
+ {
+ }
+
+ sass::string toString() const {
+ return "if" + arguments_->toString();
+ }
+
+ ATTACH_CRTP_PERFORM_METHODS();
+ };
+
+ /// A function invocation.
+ ///
+ /// This may be a plain CSS function or a Sass function.
+ class FunctionExpression : public InvocationExpression {
+
+ // The namespace of the function being invoked,
+ // or `null` if it's invoked without a namespace.
+ ADD_CONSTREF(sass::string, ns);
+
+ ADD_PROPERTY(IdxRef, fidx);
+
+ // The name of the function being invoked. If this is
+ // interpolated, the function will be interpreted as plain
+ // CSS, even if it has the same name as a Sass function.
+ ADD_PROPERTY(InterpolationObj, name);
+
+ public:
+ FunctionExpression(const SourceSpan& pstate,
+ Interpolation* name,
+ ArgumentInvocation* arguments,
+ const sass::string& ns = "") :
+ InvocationExpression(pstate, arguments),
+ ns_(ns), name_(name)
+ {
+
+ }
+
+ ATTACH_CRTP_PERFORM_METHODS();
+ };
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Definitions for both mixins and functions. The two cases are distinguished
+ // by a type tag.
+ /////////////////////////////////////////////////////////////////////////////
+ class CallableDeclaration : public ParentStatement {
+ // The name of this callable.
+ // This may be empty for callables without names.
+ ADD_CONSTREF(EnvString, name);
+ ADD_POINTER(IDXS*, idxs);
+ ADD_PROPERTY(IdxRef, fidx);
+ ADD_PROPERTY(IdxRef, cidx);
+
+ // The comment immediately preceding this declaration.
+ ADD_PROPERTY(SilentCommentObj, comment);
+ // The declared arguments this callable accepts.
+ ADD_PROPERTY(ArgumentDeclarationObj, arguments);
+ public:
+ CallableDeclaration(
+ const SourceSpan& pstate,
+ const EnvString& name,
+ ArgumentDeclaration* arguments,
+ SilentComment* comment = nullptr,
+ Block* block = nullptr);
+
+ // Stringify declarations etc. (dart)
+ virtual sass::string toString1() const = 0;
+
+ ATTACH_ABSTRACT_CRTP_PERFORM_METHODS();
+ };
+
+ class ContentBlock :
+ public CallableDeclaration {
+ public:
+ ContentBlock(
+ const SourceSpan& pstate,
+ ArgumentDeclaration* arguments = nullptr,
+ const sass::vector& children = {});
+ sass::string toString1() const override final;
+ ATTACH_CRTP_PERFORM_METHODS();
+ };
+
+ class FunctionRule final :
+ public CallableDeclaration {
+ public:
+ FunctionRule(
+ const SourceSpan& pstate,
+ const EnvString& name,
+ ArgumentDeclaration* arguments,
+ SilentComment* comment = nullptr,
+ Block* block = nullptr);
+ sass::string toString1() const override final;
+ ATTACH_CRTP_PERFORM_METHODS();
+ };
+
+ class MixinRule final :
+ public CallableDeclaration {
+ ADD_CONSTREF(IdxRef, cidx);
+ public:
+ MixinRule(
+ const SourceSpan& pstate,
+ const sass::string& name,
+ ArgumentDeclaration* arguments,
+ SilentComment* comment = nullptr,
+ Block* block = nullptr);
+ sass::string toString1() const override final;
+ ATTACH_CRTP_PERFORM_METHODS();
+ };
+
+ class IncludeRule final : public InvocationStatement {
+
+ // The namespace of the mixin being invoked, or
+ // `null` if it's invoked without a namespace.
+ ADD_CONSTREF(sass::string, ns);
+
+ // The name of the mixin being invoked.
+ ADD_CONSTREF(EnvString, name);
+
+ // The block that will be invoked for [ContentRule]s in the mixin
+ // being invoked, or `null` if this doesn't pass a content block.
+ ADD_PROPERTY(ContentBlockObj, content);
+
+ ADD_CONSTREF(IdxRef, midx);
+
+ public:
+
+ IncludeRule(
+ const SourceSpan& pstate,
+ const EnvString& name,
+ ArgumentInvocation* arguments,
+ const sass::string& ns = "",
+ ContentBlock* content = nullptr,
+ Block* block = nullptr);
+
+ bool has_content() override final;
+
+ ATTACH_CRTP_PERFORM_METHODS();
+ };
+
+ ///////////////////////////////////////////////////
+ // The @content directive for mixin content blocks.
+ ///////////////////////////////////////////////////
+ class ContentRule final : public Statement {
+ ADD_PROPERTY(ArgumentInvocationObj, arguments);
+ public:
+ ContentRule(const SourceSpan& pstate,
+ ArgumentInvocation* arguments);
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ ////////////////////////////////////////////////////////////////////////////
+ class ParenthesizedExpression final : public Expression {
+ ADD_PROPERTY(ExpressionObj, expression)
+ public:
+ ParenthesizedExpression(const SourceSpan& pstate, Expression* expression);
+ // ATTACH_CLONE_OPERATIONS(ParenthesizedExpression);
+ ATTACH_CRTP_PERFORM_METHODS();
+ };
+ ////////////////////////////////////////////////////////////////////////////
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Arithmetic negation (logical negation is just an ordinary function call).
+ ////////////////////////////////////////////////////////////////////////////
+ class Unary_Expression final : public Expression {
+ public:
+ enum Type { PLUS, MINUS, NOT, SLASH };
+ private:
+ ADD_PROPERTY(Type, optype)
+ ADD_PROPERTY(Expression_Obj, operand)
+ public:
+ Unary_Expression(const SourceSpan& pstate, Type t, Expression_Obj o);
+ // ATTACH_CLONE_OPERATIONS(Unary_Expression)
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ // A Media Ruleset before it has been evaluated
+ // Could be already final or an interpolation
+ class MediaRule final : public ParentStatement {
+ ADD_PROPERTY(InterpolationObj, query)
+ public:
+ // The query that determines on which platforms the styles will be in effect.
+ // This is only parsed after the interpolation has been resolved.
+ MediaRule(const SourceSpan& pstate, InterpolationObj query, Block_Obj block = {});
+
+ bool bubbles() const override final { return true; };
+ bool is_invisible() const override { return false; };
+ // ATTACH_CLONE_OPERATIONS(MediaRule)
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ /////////////////////////////////////////////////
+ // A query for the `@at-root` rule.
+ /////////////////////////////////////////////////
+ class AtRootQuery final : public AST_Node {
+ private:
+ // The names of the rules included or excluded by this query. There are
+ // two special names. "all" indicates that all rules are included or
+ // excluded, and "rule" indicates style rules are included or excluded.
+ ADD_PROPERTY(StringSet, names);
+ // Whether the query includes or excludes rules with the specified names.
+ ADD_PROPERTY(bool, include);
+
+ public:
+
+ AtRootQuery(
+ const SourceSpan& pstate,
+ const StringSet& names,
+ bool include);
+
+ // Whether this includes or excludes *all* rules.
+ bool all() const;
+
+ // Whether this includes or excludes style rules.
+ bool rule() const;
+
+ // Whether this includes or excludes media rules.
+ bool media() const;
+
+ // Returns the at-rule name for [node], or `null` if it's not an at-rule.
+ sass::string _nameFor(Statement* node) const;
+
+ // Returns whether [this] excludes a node with the given [name].
+ bool excludesName(const sass::string& name) const;
+
+ // Returns whether [this] excludes [node].
+ bool excludes(Statement* node) const;
+
+ // Whether this excludes `@media` rules.
+ // Note that this takes [include] into account.
+ bool excludesMedia() const;
+
+ // Whether this excludes style rules.
+ // Note that this takes [include] into account.
+ bool excludesStyleRules() const;
+
+ // Parses an at-root query from [contents]. If passed, [url]
+ // is the name of the file from which [contents] comes.
+ // Throws a [SassFormatException] if parsing fails.
+ static AtRootQuery* parse(
+ const sass::string& contents, Context& ctx);
+
+ // The default at-root query, which excludes only style rules.
+ // ToDo: check out how to make this static
+ static AtRootQuery* defaultQuery(const SourceSpan& pstate);
+
+ // Only for debug purposes
+ sass::string toString() const;
+
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ ///////////
+ // At-root.
+ ///////////
+ class AtRootRule final : public ParentStatement {
+ ADD_PROPERTY(InterpolationObj, query);
+ ADD_POINTER(IDXS*, idxs);
+ public:
+ AtRootRule(SourceSpan&& pstate, InterpolationObj query = {}, Block_Obj b = {});
+ // ATTACH_CLONE_OPERATIONS(CssAtRootRule)
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ ////////////////////////////////////////////////////////////
+ // Individual argument objects for mixin and function calls.
+ ////////////////////////////////////////////////////////////
+ class Argument final : public Expression {
+ HASH_PROPERTY(Expression_Obj, value);
+ HASH_CONSTREF(EnvString, name);
+ ADD_PROPERTY(bool, is_rest_argument);
+ ADD_PROPERTY(bool, is_keyword_argument);
+ mutable size_t hash_;
+ public:
+ Argument(const SourceSpan& pstate, Expression_Obj val,
+ const EnvString& n, bool rest = false, bool keyword = false);
+ size_t hash() const override;
+ ATTACH_CLONE_OPERATIONS(Argument)
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ /////////////////////////////////////////////////////////////////////////
+ // Parameter lists -- in their own class to facilitate context-sensitive
+ // error checking (e.g., ensuring that all optional parameters follow all
+ // required parameters).
+ /////////////////////////////////////////////////////////////////////////
+ typedef Value* (*SassFnSig)(FN_PROTOTYPE2);
+ typedef std::pair SassFnPair;
+ typedef sass::vector SassFnPairs;
+
+ class Callable : public SassNode {
+ public:
+ Callable(const SourceSpan& pstate);
+ virtual Value* execute(Eval& eval, ArgumentInvocation* arguments, const SourceSpan& pstate) = 0;
+ virtual bool operator== (const Callable& rhs) const = 0;
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ class UserDefinedCallable : public Callable {
+ // Name of this callable (used for reporting)
+ ADD_CONSTREF(EnvString, name);
+ // The declaration (parameters this function takes).
+ ADD_PROPERTY(CallableDeclarationObj, declaration);
+ // The environment in which this callable was declared.
+ ADD_POINTER(EnvSnapshot*, snapshot);
+ public:
+ UserDefinedCallable(
+ const SourceSpan& pstate,
+ const EnvString& name,
+ CallableDeclarationObj declaration,
+ EnvSnapshot* snapshot);
+ Value* execute(Eval& eval, ArgumentInvocation* arguments, const SourceSpan& pstate) override final;
+ bool operator== (const Callable& rhs) const override final;
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ class PlainCssCallable : public Callable {
+ ADD_CONSTREF(sass::string, name);
+ public:
+ PlainCssCallable(const SourceSpan& pstate, const sass::string& name);
+ Value* execute(Eval& eval, ArgumentInvocation* arguments, const SourceSpan& pstate) override final;
+ bool operator== (const Callable& rhs) const override final;
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ class BuiltInCallable : public Callable {
+
+ // The function name
+ ADD_CONSTREF(EnvString, name);
+
+ ADD_PROPERTY(ArgumentDeclarationObj, parameters);
+
+ ADD_CONSTREF(SassFnPair, function);
+
+ public:
+
+ Value* execute(Eval& eval, ArgumentInvocation* arguments, const SourceSpan& pstate) override final;
+
+ // Value* execute(ArgumentInvocation* arguments) {
+ // // return callback(arguments);
+ // return nullptr;
+ // }
+
+ // Creates a callable with a single [arguments] declaration
+ // and a single [callback]. The argument declaration is parsed
+ // from [arguments], which should not include parentheses.
+ // Throws a [SassFormatException] if parsing fails.
+ BuiltInCallable(
+ const EnvString& name,
+ ArgumentDeclaration* parameters,
+ const SassFnSig& callback);
+
+ virtual const SassFnPair& callbackFor(
+ size_t positional,
+ const KeywordMap& names);
+
+ bool operator== (const Callable& rhs) const override final;
+
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ class BuiltInCallables : public Callable {
+
+ // The function name
+ ADD_CONSTREF(EnvString, name);
+
+ // The overloads declared for this callable.
+ ADD_PROPERTY(SassFnPairs, overloads);
+
+ public:
+
+ Value* execute(Eval& eval, ArgumentInvocation* arguments, const SourceSpan& pstate) override final;
+
+ // Value* execute(ArgumentInvocation* arguments) {
+ // // return callback(arguments);
+ // return nullptr;
+ // }
+
+ // Creates a callable with multiple implementations. Each
+ // key/value pair in [overloads] defines the argument declaration
+ // for the overload (which should not include parentheses), and
+ // the callback to execute if that argument declaration matches.
+ // Throws a [SassFormatException] if parsing fails.
+ BuiltInCallables(
+ const EnvString& name,
+ const SassFnPairs& overloads);
+
+ const SassFnPair& callbackFor(
+ size_t positional,
+ const KeywordMap& names); // override final;
+
+ bool operator== (const Callable& rhs) const override final;
+
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+ class ExternalCallable : public Callable {
+
+ // The function name
+ ADD_CONSTREF(sass::string, name);
+
+ ADD_PROPERTY(ArgumentDeclarationObj, declaration);
+
+ ADD_PROPERTY(Sass_Function_Entry, function);
+
+ ADD_POINTER(IDXS*, idxs);
+
+ public:
+
+ ExternalCallable(
+ const sass::string& name,
+ ArgumentDeclaration* parameters,
+ Sass_Function_Entry function);
+ Value* execute(Eval& eval, ArgumentInvocation* arguments, const SourceSpan& pstate) override final;
+ bool operator== (const Callable& rhs) const override final;
+
+ ATTACH_CRTP_PERFORM_METHODS()
+ };
+
+
+}
+
+#include "ast_css.hpp"
+#include "ast_values.hpp"
+#include "ast_supports.hpp"
+#include "ast_selectors.hpp"
+
+#ifdef __clang__
+
+// #pragma clang diagnostic pop
+// #pragma clang diagnostic push
+
+#endif
+
+#endif
diff --git a/src/ast2c.cpp b/src/ast2c.cpp
deleted file mode 100644
index f167b7ea77..0000000000
--- a/src/ast2c.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-// sass.hpp must go before all system headers to get the
-// __EXTENSIONS__ fix on Solaris.
-#include "sass.hpp"
-
-#include "ast2c.hpp"
-#include "ast.hpp"
-
-namespace Sass {
-
- union Sass_Value* AST2C::operator()(Boolean* b)
- { return sass_make_boolean(b->value()); }
-
- union Sass_Value* AST2C::operator()(Number* n)
- { return sass_make_number(n->value(), n->unit().c_str()); }
-
- union Sass_Value* AST2C::operator()(Custom_Warning* w)
- { return sass_make_warning(w->message().c_str()); }
-
- union Sass_Value* AST2C::operator()(Custom_Error* e)
- { return sass_make_error(e->message().c_str()); }
-
- union Sass_Value* AST2C::operator()(Color_RGBA* c)
- { return sass_make_color(c->r(), c->g(), c->b(), c->a()); }
-
- union Sass_Value* AST2C::operator()(Color_HSLA* c)
- {
- Color_RGBA_Obj rgba = c->copyAsRGBA();
- return operator()(rgba.ptr());
- }
-
- union Sass_Value* AST2C::operator()(String_Constant* s)
- {
- if (s->quote_mark()) {
- return sass_make_qstring(s->value().c_str());
- } else {
- return sass_make_string(s->value().c_str());
- }
- }
-
- union Sass_Value* AST2C::operator()(String_Quoted* s)
- { return sass_make_qstring(s->value().c_str()); }
-
- union Sass_Value* AST2C::operator()(List* l)
- {
- 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));
- }
- return v;
- }
-
- union Sass_Value* AST2C::operator()(Map* m)
- {
- union Sass_Value* v = sass_make_map(m->length());
- int i = 0;
- for (auto key : m->keys()) {
- sass_map_set_key(v, i, key->perform(this));
- sass_map_set_value(v, i, m->at(key)->perform(this));
- i++;
- }
- return v;
- }
-
- union Sass_Value* AST2C::operator()(Arguments* a)
- {
- 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));
- }
- return v;
- }
-
- union Sass_Value* AST2C::operator()(Argument* a)
- { return a->value()->perform(this); }
-
- // not strictly necessary because of the fallback
- union Sass_Value* AST2C::operator()(Null* n)
- { return sass_make_null(); }
-
-};
diff --git a/src/ast2c.hpp b/src/ast2c.hpp
deleted file mode 100644
index cd99a17c31..0000000000
--- a/src/ast2c.hpp
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef SASS_AST2C_H
-#define SASS_AST2C_H
-
-#include "ast_fwd_decl.hpp"
-#include "operation.hpp"
-#include "sass/values.h"
-
-namespace Sass {
-
- class AST2C : public Operation_CRTP {
-
- public:
-
- AST2C() { }
- ~AST2C() { }
-
- union Sass_Value* operator()(Boolean*);
- union Sass_Value* operator()(Number*);
- union Sass_Value* operator()(Color_RGBA*);
- union Sass_Value* operator()(Color_HSLA*);
- union Sass_Value* operator()(String_Constant*);
- union Sass_Value* operator()(String_Quoted*);
- union Sass_Value* operator()(Custom_Warning*);
- union Sass_Value* operator()(Custom_Error*);
- union Sass_Value* operator()(List*);
- union Sass_Value* operator()(Map*);
- union Sass_Value* operator()(Null*);
- union Sass_Value* operator()(Arguments*);
- union Sass_Value* operator()(Argument*);
-
- // return sass error if type is not supported
- union Sass_Value* fallback(AST_Node* x)
- { return sass_make_error("unknown type for C-API"); }
-
- };
-
-}
-
-#endif
diff --git a/src/ast_callables.cpp b/src/ast_callables.cpp
new file mode 100644
index 0000000000..9386b24c4a
--- /dev/null
+++ b/src/ast_callables.cpp
@@ -0,0 +1,381 @@
+/*****************************************************************************/
+/* Part of LibSass, released under the MIT license (See LICENSE.txt). */
+/*****************************************************************************/
+#include "ast_callables.hpp"
+
+#include "exceptions.hpp"
+#include "parser_scss.hpp"
+#include "eval.hpp"
+
+namespace Sass {
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ Callable::Callable(
+ const SourceSpan& pstate) :
+ AstNode(pstate)
+ {}
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ BuiltInCallable::BuiltInCallable(
+ const EnvKey& envkey,
+ ArgumentDeclaration* parameters,
+ const SassFnSig& callback) :
+ Callable(SourceSpan::tmp("[BUILTIN]")),
+ envkey_(envkey),
+ // Create a single entry in overloaded function
+ function_(SassFnPair{ parameters, callback })
+ {}
+
+ // Return callback with matching signature
+ const SassFnPair& BuiltInCallable::callbackFor(
+ const ArgumentResults& evaluated)
+ {
+ return function_;
+ }
+
+ // Equality comparator (needed for `get-function` value)
+ bool BuiltInCallable::operator==(const Callable& rhs) const
+ {
+ if (const BuiltInCallable* builtin = rhs.isaBuiltInCallable()) {
+ return envkey_ == builtin->envkey_ &&
+ function_.first == builtin->function_.first &&
+ function_.second == builtin->function_.second;
+ }
+ return false;
+ }
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ BuiltInCallables::BuiltInCallables(
+ const EnvKey& envkey,
+ const SassFnPairs& overloads) :
+ Callable(SourceSpan::tmp("[BUILTINS]")),
+ envkey_(envkey),
+ overloads_(overloads)
+ {
+ size_t size = 0;
+ for (auto fn : overloads) {
+ size = std::max(size,
+ fn.first->maxArgs());
+ }
+ for (auto fn : overloads) {
+ fn.first->maxArgs(size);
+ }
+ }
+
+ // Return callback with matching signature
+ const SassFnPair& BuiltInCallables::callbackFor(
+ const ArgumentResults& evaluated)
+ {
+ for (SassFnPair& pair : overloads_) {
+ if (pair.first->matches(evaluated)) {
+ return pair;
+ }
+ }
+ return overloads_.back();
+ }
+
+ // Equality comparator (needed for `get-function` value)
+ bool BuiltInCallables::operator==(const Callable& rhs) const
+ {
+ if (const BuiltInCallables* builtin = rhs.isaBuiltInCallables()) {
+ if (!(envkey_ == builtin->envkey_)) return false;
+ return overloads_ == builtin->overloads_;
+ }
+ return false;
+ }
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ PlainCssCallable::PlainCssCallable(
+ const SourceSpan& pstate,
+ const sass::string& fname) :
+ Callable(pstate),
+ fname_(fname)
+ {}
+
+ // Equality comparator (needed for `get-function` value)
+ bool PlainCssCallable::operator==(const Callable& rhs) const
+ {
+ if (const PlainCssCallable* builtin = rhs.isaPlainCssCallable()) {
+ return fname_ == builtin->fname_;
+ }
+ return false;
+ }
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ UserDefinedCallable::UserDefinedCallable(
+ const SourceSpan& pstate,
+ const EnvKey& envkey,
+ CallableDeclarationObj declaration,
+ UserDefinedCallable* content) :
+ Callable(pstate),
+ envkey_(envkey),
+ declaration_(declaration),
+ content_(content)
+ {}
+
+ // Equality comparator (needed for `get-function` value)
+ bool UserDefinedCallable::operator==(const Callable& rhs) const
+ {
+ if (const UserDefinedCallable* builtin = rhs.isaUserDefinedCallable()) {
+ return envkey_ == builtin->envkey_ &&
+ declaration_ == builtin->declaration_;
+ }
+ return false;
+ }
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ ExternalCallable::ExternalCallable(
+ const EnvKey& fname,
+ ArgumentDeclaration* parameters,
+ struct SassFunction* function) :
+ Callable(SourceSpan::tmp("[EXTERNAL]")),
+ envkey_(fname),
+ declaration_(parameters),
+ function_(function)
+ {}
+
+ // Equality comparator (needed for `get-function` value)
+ bool ExternalCallable::operator==(const Callable& rhs) const
+ {
+ if (const ExternalCallable* builtin = rhs.isaExternalCallable()) {
+ return envkey_ == builtin->envkey_ &&
+ function_ == builtin->function_;
+ }
+ return false;
+ }
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ Argument::Argument(const SourceSpan& pstate,
+ const EnvKey& name,
+ ExpressionObj defval,
+ bool is_rest_argument,
+ bool is_keyword_argument) :
+ AstNode(pstate),
+ name_(name),
+ defval_(defval),
+ is_rest_argument_(is_rest_argument),
+ is_keyword_argument_(is_keyword_argument)
+ {}
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ ArgumentDeclaration::ArgumentDeclaration(
+ SourceSpan&& pstate,
+ sass::vector&& arguments,
+ EnvKey&& restArg) :
+ AstNode(std::move(pstate)),
+ arguments_(std::move(arguments)),
+ restArg_(std::move(restArg)),
+ maxArgs_(arguments_.size())
+ {
+ if (!restArg_.empty()) {
+ maxArgs_ += 1;
+ }
+ }
+
+ // Parse source into arguments
+ ArgumentDeclaration* ArgumentDeclaration::parse(
+ Compiler& context, SourceData* source)
+ {
+ ScssParser parser(context, source);
+ return parser.parseArgumentDeclaration();
+ }
+
+ // Throws a [SassScriptException] if [positional] and
+ // [names] aren't valid for this argument declaration.
+ void ArgumentDeclaration::verify(
+ size_t positional,
+ const ValueFlatMap& names,
+ const SourceSpan& pstate,
+ const BackTraces& traces) const
+ {
+
+ size_t i = 0;
+ size_t namedUsed = 0;
+ size_t iL = arguments_.size();
+ while (i < std::min(positional, iL)) {
+ if (names.count(arguments_[i]->name()) == 1) {
+ throw Exception::RuntimeException(traces,
+ "Argument $" + arguments_[i]->name().orig() +
+ " name was passed both by position and by name.");
+ }
+ i++;
+ }
+ while (i < iL) {
+ if (names.count(arguments_[i]->name()) == 1) {
+ namedUsed++;
+ }
+ else if (arguments_[i]->defval() == nullptr) {
+ throw Exception::RuntimeException(traces,
+ "Missing argument $" + arguments_[i]->name().orig() + ".");
+ }
+ i++;
+ }
+
+ if (!restArg_.empty()) return;
+
+ if (positional > arguments_.size()) {
+ sass::sstream strm;
+ strm << "Only " << arguments_.size() << " "; // " positional ";
+ strm << pluralize("argument", arguments_.size());
+ strm << " allowed, but " << positional << " ";
+ strm << pluralize("was", positional, "were");
+ strm << " passed.";
+ throw Exception::RuntimeException(
+ traces, strm.str());
+ }
+
+ if (namedUsed < names.size()) {
+ ValueFlatMap unknownNames(names);
+ for (Argument* arg : arguments_) {
+ unknownNames.erase(arg->name());
+ }
+ throw Exception::RuntimeException(
+ traces, "No argument named $" +
+ toSentence(getKeyVector(unknownNames), "or") + ".");
+ }
+
+ }
+ // EO verify
+
+ // Returns whether [positional] and [names]
+ // are valid for this argument declaration.
+ bool ArgumentDeclaration::matches(
+ const ArgumentResults& evaluated) const
+ {
+ size_t namedUsed = 0; Argument* argument;
+ for (size_t i = 0, iL = arguments_.size(); i < iL; i++) {
+ argument = arguments_[i];
+ if (i < evaluated.positional().size()) {
+ if (evaluated.named().count(argument->name()) == 1) {
+ return false;
+ }
+ }
+ else if (evaluated.named().count(argument->name()) == 1) {
+ namedUsed++;
+ }
+ else if (argument->defval().isNull()) {
+ return false;
+ }
+ }
+ if (!restArg_.empty()) return true;
+ if (evaluated.positional().size() > arguments_.size()) return false;
+ if (namedUsed < evaluated.named().size()) return false;
+ return true;
+ }
+ // EO matches
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ ArgumentInvocation::ArgumentInvocation(
+ const SourceSpan& pstate,
+ ExpressionVector&& positional,
+ ExpressionFlatMap&& named,
+ Expression* restArg,
+ Expression* kwdRest) :
+ AstNode(pstate),
+ positional_(std::move(positional)),
+ named_(std::move(named)),
+ restArg_(restArg),
+ kwdRest_(kwdRest)
+ {}
+
+ ArgumentInvocation::ArgumentInvocation(
+ SourceSpan&& pstate,
+ ExpressionVector&& positional,
+ ExpressionFlatMap&& named,
+ Expression* restArg,
+ Expression* kwdRest) :
+ AstNode(std::move(pstate)),
+ positional_(std::move(positional)),
+ named_(std::move(named)),
+ restArg_(restArg),
+ kwdRest_(kwdRest)
+ {}
+
+ // Returns whether this invocation passes no arguments.
+ bool ArgumentInvocation::isEmpty() const
+ {
+ return positional_.empty()
+ && named_.empty()
+ && restArg_.isNull();
+ }
+ // EO isEmpty
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ ArgumentResults::ArgumentResults(
+ ValueVector&& positional,
+ ValueFlatMap&& named,
+ SassSeparator separator) :
+ positional_(std::move(positional)),
+ named_(std::move(named)),
+ separator_(separator)
+ {}
+
+ ArgumentResults::ArgumentResults(
+ ArgumentResults&& other) noexcept :
+ positional_(std::move(other.positional_)),
+ named_(std::move(other.named_)),
+ separator_(other.separator_)
+ {}
+
+ ArgumentResults& ArgumentResults::operator=(
+ ArgumentResults&& other) noexcept
+ {
+ positional_ = std::move(other.positional_);
+ named_ = std::move(other.named_);
+ separator_ = other.separator_;
+ return *this;
+ }
+
+ /////////////////////////////////////////////////////////////////////////
+ // Implement the execute dispatch to evaluator
+ /////////////////////////////////////////////////////////////////////////
+
+ Value* BuiltInCallable::execute(Eval& eval, ArgumentInvocation* arguments, const SourceSpan& pstate, bool selfAssign)
+ {
+ return eval.execute(this, arguments, pstate, selfAssign);
+ }
+
+ Value* BuiltInCallables::execute(Eval& eval, ArgumentInvocation* arguments, const SourceSpan& pstate, bool selfAssign)
+ {
+ return eval.execute(this, arguments, pstate, selfAssign);
+ }
+
+ Value* PlainCssCallable::execute(Eval& eval, ArgumentInvocation* arguments, const SourceSpan& pstate, bool selfAssign)
+ {
+ return eval.execute(this, arguments, pstate, selfAssign);
+ }
+
+ Value* UserDefinedCallable::execute(Eval& eval, ArgumentInvocation* arguments, const SourceSpan& pstate, bool selfAssign)
+ {
+ return eval.execute(this, arguments, pstate, selfAssign);
+ }
+
+ Value* ExternalCallable::execute(Eval& eval, ArgumentInvocation* arguments, const SourceSpan& pstate, bool selfAssign)
+ {
+ return eval.execute(this, arguments, pstate, selfAssign);
+ }
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+}
diff --git a/src/ast_callables.hpp b/src/ast_callables.hpp
new file mode 100644
index 0000000000..3369f3bc2a
--- /dev/null
+++ b/src/ast_callables.hpp
@@ -0,0 +1,416 @@
+/*****************************************************************************/
+/* Part of LibSass, released under the MIT license (See LICENSE.txt). */
+/*****************************************************************************/
+#ifndef SASS_AST_CALLABLES_HPP
+#define SASS_AST_CALLABLES_HPP
+
+// sass.hpp must go before all system headers
+// to get the __EXTENSIONS__ fix on Solaris.
+#include "capi_sass.hpp"
+
+#include "ast_nodes.hpp"
+#include "environment_key.hpp"
+#include "environment_stack.hpp"
+
+namespace Sass {
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ typedef Value* (*SassFnSig)(FN_PROTOTYPE2);
+ typedef std::pair SassFnPair;
+ typedef sass::vector SassFnPairs;
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ class Callable : public AstNode
+ {
+ public:
+
+ // Value constructor
+ Callable(const SourceSpan& pstate);
+
+ // The main entry point to execute the function (implemented in each specialization)
+ virtual Value* execute(Eval& eval, ArgumentInvocation* arguments, const SourceSpan& pstate, bool selfAssign) = 0;
+
+ // Return the function name
+ virtual const sass::string& name() const = 0;
+
+ // Equality comparator (needed for `get-function` value)
+ virtual bool operator==(const Callable& rhs) const = 0;
+
+ // Declare up-casting methods
+ DECLARE_ISA_CASTER(BuiltInCallable);
+ DECLARE_ISA_CASTER(BuiltInCallables);
+ DECLARE_ISA_CASTER(PlainCssCallable);
+ DECLARE_ISA_CASTER(UserDefinedCallable);
+ DECLARE_ISA_CASTER(ExternalCallable);
+ };
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ class BuiltInCallable final : public Callable {
+
+ // The function name
+ ADD_CONSTREF(EnvKey, envkey);
+
+ ADD_CONSTREF(ArgumentDeclarationObj, parameters);
+
+ ADD_REF(SassFnPair, function);
+
+ public:
+
+ // Creates a callable with a single [arguments] declaration
+ // and a single [callback]. The argument declaration is parsed
+ // from [arguments], which should not include parentheses.
+ // Throws a [SassFormatException] if parsing fails.
+ BuiltInCallable(
+ const EnvKey& fname,
+ ArgumentDeclaration* parameters,
+ const SassFnSig& callback);
+
+ // Return callback with matching signature
+ const SassFnPair& callbackFor(
+ const ArgumentResults& evaluated);
+
+ // The main entry point to execute the function (implemented in each specialization)
+ Value* execute(Eval& eval, ArgumentInvocation* arguments, const SourceSpan& pstate, bool selfAssign) override final;
+
+ // Return the function name
+ const sass::string& name() const override final { return envkey_.norm(); }
+
+ // Equality comparator (needed for `get-function` value)
+ bool operator==(const Callable& rhs) const override final;
+
+ IMPLEMENT_ISA_CASTER(BuiltInCallable);
+ };
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ class BuiltInCallables final : public Callable {
+
+ // The function name
+ ADD_CONSTREF(EnvKey, envkey);
+
+ // The overloads declared for this callable.
+ ADD_CONSTREF(SassFnPairs, overloads);
+
+ public:
+
+ // Creates a callable with multiple implementations. Each
+ // key/value pair in [overloads] defines the argument declaration
+ // for the overload (which should not include parentheses), and
+ // the callback to execute if that argument declaration matches.
+ // Throws a [SassFormatException] if parsing fails.
+ BuiltInCallables(
+ const EnvKey& envkey,
+ const SassFnPairs& overloads);
+
+ // Return callback with matching signature
+ const SassFnPair& callbackFor(
+ const ArgumentResults& evaluated);
+
+ // The main entry point to execute the function (implemented in each specialization)
+ Value* execute(Eval& eval, ArgumentInvocation* arguments, const SourceSpan& pstate, bool selfAssign) override final;
+
+ // Return the function name
+ const sass::string& name() const override final { return envkey_.norm(); }
+
+ // Equality comparator (needed for `get-function` value)
+ bool operator==(const Callable& rhs) const override final;
+
+ IMPLEMENT_ISA_CASTER(BuiltInCallables);
+ };
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ class PlainCssCallable final : public Callable
+ {
+ private:
+
+ ADD_CONSTREF(sass::string, fname);
+
+ public:
+
+ // Value constructor
+ PlainCssCallable(
+ const SourceSpan& pstate,
+ const sass::string& fname);
+
+ // The main entry point to execute the function (implemented in each specialization)
+ Value* execute(Eval& eval, ArgumentInvocation* arguments, const SourceSpan& pstate, bool selfAssign) override final;
+
+ // Return the function name
+ const sass::string& name() const override final { return fname(); }
+
+ // Equality comparator (needed for `get-function` value)
+ bool operator==(const Callable& rhs) const override final;
+
+ IMPLEMENT_ISA_CASTER(PlainCssCallable);
+ };
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ class UserDefinedCallable final : public Callable
+ {
+ private:
+
+ // Name of this callable (used for reporting)
+ ADD_CONSTREF(EnvKey, envkey);
+ // The declaration (parameters this function takes).
+ ADD_CONSTREF(CallableDeclarationObj, declaration);
+ // The environment in which this callable was declared.
+ ADD_PROPERTY(UserDefinedCallable*, content);
+
+ public:
+
+ // Value constructor
+ UserDefinedCallable(
+ const SourceSpan& pstate,
+ const EnvKey& fname,
+ CallableDeclarationObj declaration,
+ UserDefinedCallable* content);
+
+ // The main entry point to execute the function (implemented in each specialization)
+ Value* execute(Eval& eval, ArgumentInvocation* arguments, const SourceSpan& pstate, bool selfAssign) override final;
+
+ // Return the function name
+ const sass::string& name() const override final { return envkey_.norm(); }
+
+ // Equality comparator (needed for `get-function` value)
+ bool operator==(const Callable& rhs) const override final;
+
+ IMPLEMENT_ISA_CASTER(UserDefinedCallable);
+ };
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ class ExternalCallable final : public Callable
+ {
+ private:
+
+ // Name of this callable (used for reporting)
+ ADD_CONSTREF(EnvKey, envkey);
+ // The declaration (parameters this function takes).
+ ADD_CONSTREF(ArgumentDeclarationObj, declaration);
+ // The attached external callback reference
+ ADD_PROPERTY(struct SassFunction*, function);
+
+ public:
+
+ // Value constructor
+ ExternalCallable(
+ const EnvKey& fname,
+ ArgumentDeclaration* parameters,
+ struct SassFunction* function);
+
+ // Destructor
+ ~ExternalCallable() override final {
+ sass_delete_function(function_);
+ }
+
+ // The main entry point to execute the function (implemented in each specialization)
+ Value* execute(Eval& eval, ArgumentInvocation* arguments, const SourceSpan& pstate, bool selfAssign) override final;
+
+ // Return the function name
+ const sass::string& name() const override final { return envkey_.norm(); }
+
+ // Equality comparator (needed for `get-function` value)
+ bool operator==(const Callable& rhs) const override final;
+
+ IMPLEMENT_ISA_CASTER(ExternalCallable);
+ };
+
+ /////////////////////////////////////////////////////////////////////////
+ // Individual argument objects for mixin and function calls.
+ /////////////////////////////////////////////////////////////////////////
+ class Argument final : public AstNode
+ {
+ private:
+
+ ADD_CONSTREF(EnvKey, name);
+ ADD_CONSTREF(ExpressionObj, defval);
+ ADD_CONSTREF(bool, is_rest_argument);
+ ADD_CONSTREF(bool, is_keyword_argument);
+
+ public:
+
+ // Value constructor
+ Argument(const SourceSpan& pstate,
+ const EnvKey& name,
+ ExpressionObj defval,
+ bool is_rest_argument = false,
+ bool is_keyword_argument = false);
+
+ };
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ class ArgumentDeclaration final : public AstNode
+ {
+ private:
+
+ // The arguments that are taken.
+ ADD_REF(sass::vector, arguments);
+
+ // The name of the rest argument (as in `$args...`),
+ // or `null` if none was declared.
+ ADD_CONSTREF(EnvKey, restArg);
+
+ // This is only used for debugging
+ ADD_CONSTREF(size_t, maxArgs);
+
+ public:
+
+ // Value constructor
+ ArgumentDeclaration(SourceSpan&& pstate,
+ sass::vector&& arguments = {},
+ EnvKey&& restArg = {});
+
+ // Check if signature is void
+ bool isEmpty() const {
+ return arguments_.empty()
+ && restArg_.empty();
+ }
+
+ // Parse source into arguments
+ static ArgumentDeclaration* parse(
+ Compiler& context, SourceData* source);
+
+ // Throws a [SassScriptException] if [positional] and
+ // [names] aren't valid for this argument declaration.
+ void verify(
+ size_t positional,
+ const ValueFlatMap& names,
+ const SourceSpan& pstate,
+ const BackTraces& traces) const;
+
+ // Returns whether [positional] and [names]
+ // are valid for this argument declaration.
+ bool matches(const ArgumentResults& evaluated) const;
+
+ };
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ class ArgumentInvocation final : public AstNode
+ {
+ private:
+
+ // The arguments passed by position.
+ ADD_REF(ExpressionVector, positional);
+
+ // The argument expressions passed by name.
+ ADD_REF(ExpressionFlatMap, named);
+
+ // The first rest argument (as in `$args...`).
+ ADD_CONSTREF(ExpressionObj, restArg);
+
+ // The second rest argument, which is expected to only contain a keyword map.
+ // This can be an already evaluated Map (via call) or a MapExpression.
+ // So we must guarantee that this evaluates to a real Map value.
+ ADD_CONSTREF(ExpressionObj, kwdRest);
+
+ public:
+
+ // Value constructor
+ ArgumentInvocation(const SourceSpan& pstate,
+ ExpressionVector&& positional,
+ ExpressionFlatMap&& named,
+ Expression* restArgs = nullptr,
+ Expression* kwdRest = nullptr);
+
+ // Value constructor
+ ArgumentInvocation(SourceSpan&& pstate,
+ ExpressionVector&& positional,
+ ExpressionFlatMap&& named,
+ Expression* restArgs = nullptr,
+ Expression* kwdRest = nullptr);
+
+ // Returns whether this invocation passes no arguments.
+ bool isEmpty() const;
+
+ };
+
+ /////////////////////////////////////////////////////////////////////////
+ // The result of evaluating arguments to a function or mixin.
+ /////////////////////////////////////////////////////////////////////////
+
+ class ArgumentResults final {
+
+ // Arguments passed by position.
+ ADD_REF(ValueVector, positional);
+
+ // Arguments passed by name.
+ // A list implementation is often more efficient
+ // I don't expect any function to have many arguments
+ // Normally the trade-off is around 8 items in the list
+ ADD_REF(ValueFlatMap, named);
+
+ // The separator used for the rest argument list, if any.
+ ADD_REF(SassSeparator, separator);
+
+ public:
+
+ // Value constructor
+ ArgumentResults() :
+ separator_(SASS_UNDEF)
+ {};
+
+ // Value move constructor
+ ArgumentResults(
+ ValueVector&& positional,
+ ValueFlatMap&& named,
+ SassSeparator separator);
+
+ // Move constructor
+ ArgumentResults(
+ ArgumentResults&& other) noexcept;
+
+ // Move assignment operator
+ ArgumentResults& operator=(
+ ArgumentResults&& other) noexcept;
+
+ // Clear results
+ void clear() {
+ named_.clear();
+ positional_.clear();
+ }
+
+ };
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ class CallableInvocation
+ {
+
+ private:
+
+ // The arguments passed to the callable.
+ ADD_CONSTREF(ArgumentInvocationObj, arguments);
+
+ public:
+
+ // Value constructor
+ CallableInvocation(
+ ArgumentInvocation* arguments) :
+ arguments_(arguments)
+ {}
+
+ };
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+}
+
+#endif
diff --git a/src/ast_containers.hpp b/src/ast_containers.hpp
new file mode 100644
index 0000000000..6722a1b17a
--- /dev/null
+++ b/src/ast_containers.hpp
@@ -0,0 +1,404 @@
+#ifndef SASS_AST_CONTAINERS_H
+#define SASS_AST_CONTAINERS_H
+
+#include "ast_helpers.hpp"
+
+namespace Sass {
+
+ /////////////////////////////////////////////////////////////////////////
+ // Base class/container for AST nodes that should behave like vectors.
+ /////////////////////////////////////////////////////////////////////////
+ template
+ class Vectorized {
+
+ protected:
+
+ // The main underlying container
+ typedef SharedImpl T;
+ typedef Vectorized Klass;
+ sass::vector elements_;
+
+ // Hash is only calculated once and afterwards the value
+ // must not be mutated, which is the case with how sass
+ // works, although we must be a bit careful not to alter
+ // any value that has already been added to a set or map.
+ // Must create a copy if you need to alter such an object.
+ mutable size_t hash_ = 0;
+
+ public:
+
+ // Reserve constructor
+ Vectorized(size_t s = 0)
+ {
+ elements_.reserve(s);
+ }
+
+ // Copy constructor from other Vectorized
+ Vectorized(const Vectorized* vec, bool childless = false)
+ {
+ if (!childless) elements_ = vec->elements_;
+ }
+
+ // Copy constructor from other base vector
+ Vectorized(const sass::vector& vec, bool childless = false)
+ {
+ if (!childless) elements_ = vec;
+ }
+
+ // Move constructor from other base vector
+ Vectorized(sass::vector&& vec, bool childless = false)
+ {
+ if (!childless) elements_ = std::move(vec);
+ }
+
+ // Allow destructor overloading
+ // virtual ~Vectorized() {};
+
+ // Some simple method delegations
+ T& last() { return elements_.back(); }
+ T& first() { return elements_.front(); }
+ const T& last() const { return elements_.back(); }
+ const T& first() const { return elements_.front(); }
+ bool empty() const { return elements_.empty(); }
+ void clear() { return elements_.clear(); }
+ size_t size() const { return elements_.size(); }
+
+ // Check underlying containers for equality
+ // Note: maybe we could gain some speed by checking
+ // the computed hash first, before doing full test?
+ bool operator== (const Vectorized