diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
index 86975970ae..64def14a15 100644
--- a/.github/workflows/build-and-test.yml
+++ b/.github/workflows/build-and-test.yml
@@ -13,37 +13,41 @@ on:
jobs:
linux-and-mac:
+ name: Linux and MacOS build
# if: ${{ false }}
runs-on: ${{ matrix.config.os }}
- name: ${{ matrix.config.os }} BUILD=${{ matrix.config.build }} CC=${{ matrix.config.cc }} CXX=${{ matrix.config.cxx }} AUTOTOOLS=${{ matrix.config.autotools }}
strategy:
- fail-fast: false
+ # fail-fast: false
matrix:
config:
#- {os: ubuntu-16.04, build: 'static', cc: 'gcc-4.4', cxx: 'g++-4.4', autotools: 'no', cppstd: 'gnu++0x'}
#- {os: ubuntu-16.04, build: 'static', cc: 'gcc-4.6', cxx: 'g++-4.6', autotools: 'no', cppstd: 'gnu++0x'}
- - {os: ubuntu-16.04, build: 'static', cc: 'gcc-4.7', cxx: 'g++-4.7', autotools: 'no', cppstd: 'gnu++11'}
- - {os: ubuntu-16.04, build: 'static', cc: 'gcc-4.8', cxx: 'g++-4.8', autotools: 'no', cppstd: 'c++11'}
+ #- {os: ubuntu-16.04, build: 'static', cc: 'gcc-4.7', cxx: 'g++-4.7', autotools: 'no', cppstd: 'gnu++11'}
+ #- {os: ubuntu-16.04, build: 'static', cc: 'gcc-4.8', cxx: 'g++-4.8', autotools: 'no', cppstd: 'c++11'}
- {os: ubuntu-16.04, build: 'static', cc: 'gcc-5', cxx: 'g++-5', autotools: 'no', cppstd: 'c++11'}
- {os: ubuntu-16.04, build: 'static', cc: 'gcc-6', cxx: 'g++-6', autotools: 'no', cppstd: 'c++11'}
- {os: ubuntu-latest, build: 'static', cc: 'gcc-7', cxx: 'g++-7', autotools: 'no', cppstd: 'c++11'}
- - {os: ubuntu-latest, build: 'shared', cc: 'gcc', cxx: 'g++', autotools: 'yes', cppstd: 'c++11'}
- - {os: ubuntu-latest, build: 'static', cc: 'gcc', cxx: 'g++', autotools: 'yes', cppstd: 'c++11'}
+ - {os: ubuntu-latest, build: 'shared', cc: 'gcc', cxx: 'g++', autotools: 'yes', cppstd: 'c++11', cflags: '-g -fsanitize=address'}
+ - {os: ubuntu-latest, build: 'static', cc: 'gcc', cxx: 'g++', autotools: 'yes', cppstd: 'c++11', cflags: '-g -fsanitize=address'}
- {os: ubuntu-latest, build: 'shared', cc: 'gcc', cxx: 'g++', autotools: 'no', cppstd: 'c++11'}
- {os: ubuntu-latest, build: 'static', cc: 'gcc', cxx: 'g++', autotools: 'no', cppstd: 'c++11'}
- - {os: ubuntu-latest, build: 'shared', cc: 'clang', cxx: 'clang++', autotools: 'yes', cppstd: 'c++11'}
- - {os: ubuntu-latest, build: 'static', cc: 'clang', cxx: 'clang++', autotools: 'yes', cppstd: 'c++11'}
- - {os: ubuntu-latest, build: 'shared', cc: 'clang', cxx: 'clang++', autotools: 'no', cppstd: 'c++11'}
- - {os: ubuntu-latest, build: 'static', cc: 'clang', cxx: 'clang++', autotools: 'no', cppstd: 'c++11'}
- - {os: macOS-latest, build: 'shared', cc: 'clang', cxx: 'clang++', autotools: 'yes', cppstd: 'c++11'}
- - {os: macOS-latest, build: 'static', cc: 'clang', cxx: 'clang++', autotools: 'yes', cppstd: 'c++11'}
- - {os: macOS-latest, build: 'shared', cc: 'clang', cxx: 'clang++', autotools: 'no', cppstd: 'c++11'}
- - {os: macOS-latest, build: 'static', cc: 'clang', cxx: 'clang++', autotools: 'no', cppstd: 'c++11'}
+ - {os: ubuntu-latest, build: 'shared', cc: 'clang', cxx: 'clang++', autotools: 'yes', cppstd: 'c++11', cflags: '-g -fsanitize=address'}
+ - {os: ubuntu-latest, build: 'static', cc: 'clang', cxx: 'clang++', autotools: 'yes', cppstd: 'c++11', cflags: '-g -fsanitize=address'}
+ - {os: ubuntu-latest, build: 'shared', cc: 'clang', cxx: 'clang++', autotools: 'no', cppstd: 'c++11', cflags: '-g -fsanitize=address'}
+ - {os: ubuntu-latest, build: 'static', cc: 'clang', cxx: 'clang++', autotools: 'no', cppstd: 'c++11', cflags: '-g -fsanitize=address'}
+ - {os: macOS-latest, build: 'shared', cc: 'clang', cxx: 'clang++', autotools: 'yes', cppstd: 'c++11', cflags: '-g -fsanitize=address'}
+ - {os: macOS-latest, build: 'static', cc: 'clang', cxx: 'clang++', autotools: 'yes', cppstd: 'c++11', cflags: '-g -fsanitize=address'}
+ - {os: macOS-latest, build: 'shared', cc: 'clang', cxx: 'clang++', autotools: 'no', cppstd: 'c++11', cflags: '-g -fsanitize=address'}
+ - {os: macOS-latest, build: 'static', cc: 'clang', cxx: 'clang++', autotools: 'no', cppstd: 'c++11', cflags: '-g -fsanitize=address'}
env:
- ASAN_OPTIONS: detect_odr_violation=0
+ ASAN_OPTIONS: ${{ matrix.config.asan }}
AUTOTOOLS: ${{ matrix.config.autotools }}
+ EXTRA_CFLAGS: ${{ matrix.config.cflags }}
+ EXTRA_CXXFLAGS: ${{ matrix.config.cflags }}
+ EXTRA_LDFLAGS: ${{ matrix.config.cflags }}
+ SASS_LIBSASS_PATH: libsass
COVERAGE: no
BUILD: ${{ matrix.config.build }}
CXX: ${{ matrix.config.cxx }}
@@ -125,20 +129,31 @@ jobs:
env:
MAKE_OPTS: LIBSASS_CPPSTD=${{ matrix.config.cppstd }}
run: ./script/ci-build-libsass
+ - name: Call LibSass make install
+ run: sudo EXTRA_CFLAGS="$EXTRA_CFLAGS" EXTRA_CXXFLAGS="$EXTRA_CXXFLAGS" EXTRA_LDFLAGS="$EXTRA_LDFLAGS" make install
+ - name: Call SassC make install
+ run: sudo EXTRA_CFLAGS="$EXTRA_CFLAGS" EXTRA_CXXFLAGS="$EXTRA_CXXFLAGS" EXTRA_LDFLAGS="$EXTRA_LDFLAGS" make -C sassc install
+ - name: Check sassc help call
+ run: sassc --term-colors --help
windows-msvc:
- runs-on: windows-latest
+ runs-on: ${{ matrix.config.os }}
name: Windows MSVC build
+ # if: ${{ false }}
strategy:
- fail-fast: false
+ # fail-fast: false
matrix:
config:
- - {build: Release, platform: Win64}
- - {build: Debug, platform: Win64}
- - {build: Release, platform: Win32}
- - {build: Debug, platform: Win32}
+ - {os: 'windows-latest', build: Release, platform: Win64, version: 'latest'}
+ - {os: 'windows-latest', build: Debug, platform: Win64, version: 'latest'}
+ - {os: 'windows-latest', build: Release, platform: Win32, version: 'latest'}
+ - {os: 'windows-latest', build: Debug, platform: Win32, version: 'latest'}
+ - {os: 'windows-2016', build: Release, platform: Win64, version: '[15.0,16.0]'}
+ - {os: 'windows-2016', build: Debug, platform: Win64, version: '[15.0,16.0]'}
+ - {os: 'windows-2016', build: Release, platform: Win32, version: '[15.0,16.0]'}
+ - {os: 'windows-2016', build: Debug, platform: Win32, version: '[15.0,16.0]'}
steps:
- name: Change git config to preserve line-endings
@@ -156,13 +171,18 @@ jobs:
run: gem install minitest
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v1.0.2
+ with:
+ vs-version: ${{ matrix.config.version }}
- name: Clone and checkout sassc repository
- run: git clone https://github.com/sass/sassc.git
+ run: git clone https://github.com/mgreter/sassc.git --branch refactor/libsass-4-alpha
- name: Clone and checkout sass-spec repository
- run: git clone https://github.com/sass/sass-spec.git
+ run: git clone https://github.com/mgreter/sass-spec.git --branch refactor/libsass-4-alpha
- name: Compile libsass ${{ matrix.config.build }} build for ${{ matrix.config.platform }}
- run: msbuild /m:4 /p:"Configuration=${{ matrix.config.build }};Platform=${{ matrix.config.platform }}" sassc\win\sassc.sln
+ run: msbuild /m:4 /p:Configuration=${{ matrix.config.build }} /p:Platform=${{ matrix.config.platform }} sassc\win\sassc.sln
+ - name: Check sassc help call
+ run: sassc\bin\sassc.exe --term-colors --help
- name: Execute spec test runner
+ if: matrix.config.build != 'Debug'
run: ruby sass-spec/sass-spec.rb --probe-todo --impl libsass -c sassc/bin/sassc.exe -s sass-spec/spec
windows-mingw:
@@ -170,7 +190,7 @@ jobs:
name: Windows MinGW build
strategy:
- fail-fast: false
+ # fail-fast: false
matrix:
config:
- {build: shared, platform: x64}
@@ -178,6 +198,13 @@ jobs:
- {build: shared, platform: x86}
- {build: static, platform: x86}
+ env:
+ ASAN_OPTIONS: ${{ matrix.config.asan }}
+ EXTRA_CFLAGS: ${{ matrix.config.cflags }}
+ EXTRA_CXXFLAGS: ${{ matrix.config.cflags }}
+ #SASS_LIBSASS_PATH: libsass
+ #COVERAGE: no
+
steps:
- name: Change git config to preserve line-endings
run: |
@@ -197,19 +224,20 @@ jobs:
- name: Install ruby minitest module
run: gem install minitest
- name: Clone and checkout sassc repository
- run: git clone https://github.com/sass/sassc.git
+ run: git clone https://github.com/mgreter/sassc.git --branch refactor/libsass-4-alpha
- name: Clone and checkout sass-spec repository
- run: git clone https://github.com/sass/sass-spec.git
- - name: Add libsass library path to be found
- if: matrix.config.build == 'shared'
- run: echo "/d/a/libsass/libsass/lib" >> $GITHUB_PATH
+ run: git clone https://github.com/mgreter/sass-spec.git --branch refactor/libsass-4-alpha
- name: Compile libsass ${{ matrix.config.build }} build for ${{ matrix.config.platform }}
- run: make ${{ matrix.config.build }} BUILD=${{ matrix.config.build }}
+ run: make -j5 ${{ matrix.config.build }} BUILD=${{ matrix.config.build }} CC=gcc
+ - name: Listening results
+ run: dir lib
- name: Copy library over to pass call test
if: matrix.config.build == 'shared'
- run: copy /a/libsass/libsass/lib/libsass.dll sassc/bin/
+ run: copy lib\libsass.dll sassc\bin
- name: Compile sassc ${{ matrix.config.build }} build for ${{ matrix.config.platform }}
- run: make sassc BUILD=${{ matrix.config.build }}
+ run: make -j5 sassc BUILD=${{ matrix.config.build }} CC=gcc
+ - name: Check sassc help call
+ run: sassc\bin\sassc.exe --term-colors --help
- name: Execute spec test runner
run: ruby sass-spec/sass-spec.rb --probe-todo --impl libsass -c sassc/bin/sassc.exe -s sass-spec/spec
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/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 4b6637f1aa..395828283f 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)))
@@ -71,6 +81,7 @@ else
STATIC_ALL ?= 0
STATIC_LIBGCC ?= 0
STATIC_LIBSTDCPP ?= 0
+ MKDIR += -p
endif
ifndef SASS_LIBSASS_PATH
@@ -85,6 +96,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)
@@ -145,7 +159,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
@@ -178,6 +192,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
@@ -186,6 +201,7 @@ CLEANUPS ?=
CLEANUPS += $(RCOBJECTS)
CLEANUPS += $(COBJECTS)
CLEANUPS += $(OBJECTS)
+CLEANUPS += $(HEADOBJS)
CLEANUPS += $(LIBSASS_LIB)
all: $(BUILD)
@@ -216,18 +232,21 @@ lib/libsass.dylib: $(COBJECTS) $(OBJECTS) | lib
-install_name @rpath/libsass.dylib
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 $@ $<
+ $(CXX) $(LDFLAGS) $(COBJECTS) $(OBJECTS) $(RCOBJECTS) $(LDLIBS) -shared -o $@ \
+ -Wl,--subsystem,windows,--out-implib,lib/libsass.dll.a,--output-def,lib/libsass.dll.def
-%.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)
@@ -253,12 +272,18 @@ $(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/compiler.h \
+ $(DESTDIR)$(PREFIX)/include/sass/enums.h \
+ $(DESTDIR)$(PREFIX)/include/sass/error.h \
+ $(DESTDIR)$(PREFIX)/include/sass/function.h \
+ $(DESTDIR)$(PREFIX)/include/sass/fwdecl.h \
+ $(DESTDIR)$(PREFIX)/include/sass/import.h \
+ $(DESTDIR)$(PREFIX)/include/sass/importer.h \
+ $(DESTDIR)$(PREFIX)/include/sass/traces.h \
$(DESTDIR)$(PREFIX)/include/sass/values.h \
- $(DESTDIR)$(PREFIX)/include/sass/context.h \
- $(DESTDIR)$(PREFIX)/include/sass/functions.h
+ $(DESTDIR)$(PREFIX)/include/sass/variable.h \
+ $(DESTDIR)$(PREFIX)/include/sass/version.h
$(DESTDIR)$(PREFIX)/lib/%.a: lib/%.a \
| $(DESTDIR)$(PREFIX)/lib
@@ -303,13 +328,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)
@@ -317,13 +342,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)
@@ -331,13 +356,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)
@@ -345,13 +370,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..e1e89e8f97 100644
--- a/Makefile.conf
+++ b/Makefile.conf
@@ -4,156 +4,226 @@
# 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/enums.h \
+ sass/error.h \
+ sass/fwdecl.h \
+ sass/getopt.h \
+ sass/import.h \
+ sass/importer.h \
+ sass/function.h \
+ sass/compiler.h \
+ sass/variable.h \
+ sass/traces.h \
sass/values.h \
sass/version.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_imports.hpp \
ast_supports.hpp \
+ ast_callable.hpp \
+ ast_callables.hpp \
+ ast_statements.hpp \
+ ast_expressions.hpp \
ast_values.hpp \
+ modules.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 \
+ settings.hpp \
+ memory.hpp \
+ memory_config.hpp \
+ memory_allocator.hpp \
+ memory_pool.hpp \
+ shared_ptr.hpp \
+ MurmurHash2.hpp \
eval.hpp \
- expand.hpp \
extender.hpp \
extension.hpp \
file.hpp \
+ import.hpp \
+ compiler.hpp \
+ fn_meta.hpp \
+ fn_maps.hpp \
+ fn_math.hpp \
fn_colors.hpp \
fn_lists.hpp \
- fn_maps.hpp \
- fn_miscs.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 \
+ sources.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 \
+ calculation.hpp \
+ css_every.hpp \
+ css_invisible.hpp \
+ sel_any.hpp \
+ sel_bogus.hpp \
+ sel_useless.hpp \
+ sel_invisible.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_error.hpp \
+ capi_traces.hpp \
+ capi_import.hpp \
+ capi_getopt.hpp \
+ capi_importer.hpp \
+ capi_compiler.hpp \
+ capi_variable.hpp \
+ capi_function.hpp \
+ capi_values.hpp \
+ scanner_string.hpp \
source_map.hpp \
+ source_state.hpp \
+ source_span.hpp \
stylesheet.hpp \
- to_value.hpp \
+ preloader.hpp \
units.hpp \
- utf8_string.hpp \
- util.hpp \
- util_string.hpp \
- values.hpp \
- memory/allocator.hpp \
- memory/config.hpp \
- memory/memory_pool.hpp \
- memory/shared_ptr.hpp
+ unicode.hpp \
+ hashing.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 \
+ b64/cencode.hpp \
+ b64/encode.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 \
ast_sel_weave.cpp \
ast_selectors.cpp \
- context.cpp \
+ memory_allocator.cpp \
+ modules.cpp \
constants.cpp \
- fn_utils.cpp \
- fn_miscs.cpp \
+ compiler.cpp \
+ fn_meta.cpp \
fn_maps.cpp \
+ fn_math.cpp \
fn_lists.cpp \
fn_colors.cpp \
- fn_numbers.cpp \
- fn_strings.cpp \
+ fn_texts.cpp \
fn_selectors.cpp \
color_maps.cpp \
environment.cpp \
ast_fwd_decl.cpp \
- bind.cpp \
file.cpp \
- util.cpp \
- util_string.cpp \
+ import.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 \
+ calculation.cpp \
+ css_every.cpp \
+ css_invisible.cpp \
+ sel_any.cpp \
+ sel_bogus.cpp \
+ sel_useless.cpp \
+ sel_invisible.cpp \
eval.cpp \
- eval_selectors.cpp \
- expand.cpp \
- listize.cpp \
+ randomize.cpp \
cssize.cpp \
extender.cpp \
extension.cpp \
stylesheet.cpp \
+ preloader.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_error.cpp \
+ capi_getopt.cpp \
+ capi_traces.cpp \
+ capi_import.cpp \
+ capi_importer.cpp \
+ capi_compiler.cpp \
+ capi_variable.cpp \
+ capi_function.cpp \
+ capi_values.cpp \
+ character.cpp \
+ environment_stack.cpp \
source_map.cpp \
- error_handling.cpp \
- memory/allocator.cpp \
- memory/shared_ptr.cpp \
- utf8_string.cpp \
- base64vlq.cpp
+ source_state.cpp \
+ source_span.cpp \
+ exceptions.cpp \
+ shared_ptr.cpp \
+ unicode.cpp \
+ cencode.cpp
-CSOURCES = \
- cencode.c
+CSOURCES =
diff --git a/Readme.md b/Readme.md
index 1161465b3a..571848c805 100644
--- a/Readme.md
+++ b/Readme.md
@@ -1,3 +1,8 @@
+../../test/test.scss --precision 10
+sass-bench\bolt-bench.scss -I sass-bench
+
+\breeze-gtk\src
+
LibSass - Sass compiler written in C++
======================================
diff --git a/appveyor.yml b/appveyor.yml
index f462207844..df3060e0f7 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
@@ -8,9 +8,9 @@ environment:
- Compiler: msvc
Config: Release
Platform: Win32
- - Compiler: msvc
- Config: Debug
- Platform: Win32
+# - Compiler: msvc
+# Config: Debug
+# Platform: Win32
- Compiler: msvc
Config: Release
Platform: Win64
@@ -32,8 +32,8 @@ cache:
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
install:
- - git clone https://github.com/sass/sassc.git
- - git clone https://github.com/sass/sass-spec.git
+ - git clone https://github.com/mgreter/sassc.git --branch refactor/libsass-4-alpha
+ - git clone https://github.com/mgreter/sass-spec.git --branch refactor/libsass-4-alpha
- 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/README.md b/docs/README.md
index 421393e9dc..e5374cfdac 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,30 +1,24 @@
## LibSass documentation
-LibSass is just a library. To run the code locally (i.e. to compile your
-stylesheets), you need an implementer. SassC is an implementer written in C.
-There are a number of other implementations of LibSass - for example NodeJS.
-We encourage you to write your own port - the whole point of LibSass is that
-we want to bring Sass to many other languages!
+Welcome to LibSass, the C library to compile your awesome sass style-sheets
+to css. LibSass in itself is only a library and doesn't do much on its own
+without an implementor. SassC is such an implementer written in C. There are
+a plethora of other implementations - for example NodeJS, python or perl.
+We encourage you to write your own - the whole point of LibSass is that we
+want to bring Sass to many other languages!
-## LibSass road-map
+## LibSass road-map 2021
-Since ruby-sass was retired in 2019 in favor of dart-sass, we slowly move
-toward full compatibility with the latest Sass specifications, although
-features like the module `@use` system may take a bit longer to add.
+Since ruby-sass was retired in 2019 in favor of dart-sass, we are slowly
+moving toward full compatibility with the latest Sass specifications.
### Implementing LibSass
-If you're interested in implementing LibSass in your own project see the
-[API Documentation](api-doc.md) which now includes implementing your own
-[Sass functions](api-function.md). You may wish to [look at other
+If you're interested in implementing LibSass in your own project, see the
+[API Documentation](api-doc.md) which now include implementing your own
+[Sass functions](api-function.md). Or you may wish to [look at other
implementations](implementations.md) for your language of choice.
-### Contributing to LibSass
-
-| Issue Tracker | Issue Triage | Community Guidelines |
-|-------------------|----------------------------------|-----------------------------|
-| We're always needing help, so check out our issue tracker, help some people out, and read our article on [Contributing](contributing.md)! It's got all the details on what to do! | To help understand the process of triaging bugs, have a look at our [Issue-Triage](triage.md) document. | Oh, and don't forget we always follow [Sass Community Guidelines](https://sass-lang.com/community-guidelines). Be nice and everyone else will be nice too! |
-
### Building LibSass
Please refer to the steps on [Building LibSass](build.md)
@@ -32,3 +26,8 @@ Please refer to the steps on [Building LibSass](build.md)
### Developing LibSass
Please refer to [Developing LibSass](developing.md)
+
+### Community Guidelines
+
+See [Sass Community Guidelines](https://sass-lang.com/community-guidelines).
+Be nice and everyone else will be nice too!
diff --git a/docs/api-basics.md b/docs/api-basics.md
new file mode 100644
index 0000000000..d37c5c4b23
--- /dev/null
+++ b/docs/api-basics.md
@@ -0,0 +1,87 @@
+## API documentation basics
+
+LibSass is C library, written in C++ with a C-API to link against.
+It can either be statically included are linked against a system
+wide installed shared library. The complete C-API surface is implemented
+via functions and by passing around anonymous structures. The implementor
+does not know any implementation detail about the objects passed around.
+
+### C-API headers
+
+You may include specific headers directly, which have been split into
+groups as we saw fit, or you can simply include the main `sass.h` header.
+
+### List of C-API headers
+
+- base.h - Includes and defines basic stuff.
+- fwdecl.h - Forward declares all known anonymous structures.
+- enums.h - Enums for e.g. config options exposed on the C-API.
+- error.h - C-API functions to access `SassError` structs.
+- import.h - C-API functions to access `SassImport` structs.
+- importer.h - C-API functions to access `SassImporter` structs.
+- traces.h - C-API functions to access `SassTrace` structs.
+- values.h - C-API functions to access `SassValue` structs.
+- variable.h - C-API functions to access scoped variables.
+- version.h - Header including hardcoded LibSass version.
+
+## Anonymous structure pointers
+
+LibSass returns and consumes anonymous structure pointers on its C-API.
+Internally those are often directly mapped to an instance of a C++ object.
+Since we don't want implementors to know anything about the implementation
+details, we forward declare named structs (e.g. `SassCompiler`), but never
+provide any implementation for it. LibSass will simply cast a pointer from
+the c++ side to the anonymous struct and relies on the C-API to pass it
+back as expected to the corresponding functions. There the pointer will
+be statically cast back to the actual implementation. Since we provide
+a unique anonymous struct for every internal type, this should be safe as
+compilers should catch the case when arguments mismatch on the C-API side.
+
+### List of anonymous structures
+
+These structs have no real implementation and are only passed around as pointers.
+Internally in LibSass these pointers represent mostly different c++ objects.
+
+- `SassError` - An error object holding further information
+- `SassTrace` - An single stack-trace object holding further information
+- `SassSource` - Imported source with associated import and resolved path.
+- `SassSrcSpan` - Parser state for column, line and source information.
+- `SassCompiler` - Main object to hold state for whole compilation phase.
+- `SassFunction` - Custom function object holding callback and cookie.
+- `SassImport` - Single import for entry point or returned by custom importer.
+- `SassImporter` - Custom importer function to be hooked into our loading.
+- `SassImportList` - Custom importers can return a SassImport list.
+- `SassMapIterator` - Object to support iteration API over map objects.
+
+## Why using c++11 (or gcc4.4 compatibility)
+
+Since LibSass 3.0 we started to use more and more c++11 features. Some just
+crept in, others were utilized deliberately. With LibSass 4.0 I took the
+decision to fully utilize whatever c++11 could offer. The main reason to
+fully embrace c++11 is the move semantics it brings. Earlier we also tried
+to support compilers that only had partial c++11 support (e.g. gnu++0x).
+With LibSass 4.0 we don't really support this target anymore, as any compiler
+not older than 5 years should support the c++11 syntax we use.
+
+Note: currently the LibSass 4.0 release is on going and the final
+target compiler is gcc 4.8, as it should fully support c++11.
+More testing and tuning needs to be done after a 4.0 release!
+
+## Binary distributions and linkage issues
+
+LibSass itself does not have any official binary distribution. The main reason for
+this is because it is nearly impossible to do so reliably for each and every
+thinkable operating system. Since LibSass is written in c++ we e.g. depend on the
+compiler c++ runtime library. On windows this problem is a bit less problematic,
+and there is a [semi-official installer][1] for it. But on Linux this e.g. is also
+depending on the used libc library. Since linux offers a choice here, a binary
+distribution compiled with glibc may not be compatible on a system that uses musl,
+or a compilation with latest glibc may not be compatible with older glibc versions.
+
+By now LibSass is readily available on a lot of linux systems by their internal
+packet managers, so please try to install it that way. Alternatively try to install
+a recent compiler (e.g. gcc or clang) and compile it from source, preferably via the
+autotools way, to ensure correct linkage with tools that link against system wide
+installed LibSass (GNU coding style).
+
+[1]: http://libsass.ocbnet.ch/installer/
diff --git a/docs/api-compiler-example.md b/docs/api-compiler-example.md
new file mode 100644
index 0000000000..e6b497811d
--- /dev/null
+++ b/docs/api-compiler-example.md
@@ -0,0 +1,125 @@
+## Example with data import
+
+```C:data.c
+#include
+#include
+
+int main(int argc, const char* argv[])
+{
+
+ // LibSass will take control of data you pass in
+ // Therefore we need to make a copy of static data
+ char* text = sass_copy_c_string("a{b:c;}");
+ // Normally you'll load data into a buffer from i.e. the disk.
+ // Use `sass_alloc_memory` to get a buffer to pass to LibSass
+ // then fill it with data you load from disk or somewhere else.
+
+ // create compiler object holding config and states
+ struct SassCompiler* compiler = sass_make_compiler();
+ // we've set the input name to "styles" here, which means ...
+ struct SassImport* data = sass_make_content_import(text, "styles");
+ // ... we can't deduct the type automatically from the extension.
+ sass_import_set_syntax(data, SASS_IMPORT_SCSS);
+ // each compiler must have exactly one entry point
+ sass_compiler_set_entry_point(compiler, data);
+ // entry point now passed to compiler, so its reference count was increased
+ // in order to not leak memory we must release our own usage (usage after is UB)
+ sass_delete_import(data); // decrease ref-count
+
+ // Execute all three phases
+ sass_compiler_parse(compiler);
+ sass_compiler_compile(compiler);
+ sass_compiler_render(compiler);
+
+ // Print any warning to console
+ if (sass_compiler_get_warn_string(compiler)) {
+ sass_print_stderr(sass_compiler_get_warn_string(compiler));
+ }
+
+ // Print error message if we have an error
+ if (sass_compiler_get_status(compiler) != 0) {
+ const struct SassError* error = sass_compiler_get_error(compiler);
+ sass_print_stderr(sass_error_get_string(error));
+ }
+
+ // Get result code after all compilation steps
+ int status = sass_compiler_get_status(compiler);
+
+ // Write to output if no errors occurred
+ if (status == 0) {
+
+ // Check if config tells us to write some files
+ bool writeOutput = sass_compiler_has_output_file(compiler);
+ bool writeSrcMap = sass_compiler_has_srcmap_file(compiler);
+ // Paths where to write stuff to (might be `stream://stdout`)
+ const char* outfile = sass_compiler_get_output_path(compiler);
+ const char* mapfile = sass_compiler_get_srcmap_path(compiler);
+ // Get the parts to be added to the output file (or stdout)
+ const char* content = sass_compiler_get_output_string(compiler);
+ const char* footer = sass_compiler_get_footer_string(compiler);
+ const char* srcmap = sass_compiler_get_srcmap_string(compiler);
+
+ // Output all results
+ if (content) puts(content);
+ if (footer) puts(footer);
+
+ }
+
+ // exit status
+ return status;
+
+}
+```
+
+### Compile data.c
+
+```bash
+gcc -c data.c -o data.o
+gcc -o sample data.o -lsass
+echo "foo { margin: 21px * 2; }" > foo.scss
+./sample foo.scss => "foo { margin: 42px }"
+```
+
+## Example for file import
+
+```C:file.c
+#include
+#include
+
+int main(int argc, const char* argv[])
+{
+
+ // create compiler object holding config and states
+ struct SassCompiler* compiler = sass_make_compiler();
+ // set input name with extension so we can deduct type from it
+ struct SassImport* import = sass_make_file_import("foo.scss");
+ // each compiler must have exactly one entry point
+ sass_compiler_set_entry_point(compiler, import);
+ // entry point now passed to compiler, so its reference count was increased
+ // in order to not leak memory we must release our own usage (usage after is UB)
+ sass_delete_import(import); // decrease ref-count
+
+ // Execute compiler and print/write results
+ sass_compiler_execute(compiler, false);
+
+ // Get result code after all compilation steps
+ int status = sass_compiler_get_status(compiler);
+
+ // Clean-up compiler, we're done
+ sass_delete_compiler(compiler);
+
+ // exit status
+ return status;
+
+}
+```
+
+### Compile file.c
+
+```bash
+gcc -c file.c -o file.o
+gcc -o sample file.o -lsass
+echo "foo { margin: 21px * 2; }" > foo.scss
+./sample foo.scss => "foo { margin: 42px }"
+```
+
diff --git a/docs/api-compiler.md b/docs/api-compiler.md
new file mode 100644
index 0000000000..f7a3f179a2
--- /dev/null
+++ b/docs/api-compiler.md
@@ -0,0 +1,233 @@
+## Sass Compiler API
+
+Sass Compiler is the main object to facilitate the Sass compilation process.
+It holds the configuration, the compilation state and the results. It's the
+main object you will interact on the C-API side.
+
+The regular life-cycle of a compiler will mostly look like this:
+- Create new compiler object
+- Set various configuration options
+- Set one compilation entry point
+- Call the parse function
+- Call the compile function
+- Call the render function
+- Process the results
+
+The split between parse, compile and render is done because there
+are cases where we might want to omit certain phases. One example
+would be to only execute the init phase for a watcher to get all
+includes first, before triggering the first compilation.
+
+### Compiler entry point
+
+Every compiler must have one entry point. This can either be a file or
+a data entry point. See [import api][api-import.md] for further details.
+
+### Writing output files
+
+Implementors may write output files on their own or you can tell
+LibSass to write them to the configured locations. The functions
+`sass_compiler_write_output` and `sass_compiler_write_srcmap` should
+act according to the configuration and the produced results.
+
+### Logger configuration
+
+LibSass supports error reporting with ANSI colors on windows and unix. It can
+also make use of Unicode compatible terminals. There is some basic auto-detection
+you can trigger by calling `sass_compiler_autodetect_logger_capabilities`. You
+can still overload the detected settings afterwards. Additionally LibSass will
+try to break running-text into the available columns and shorten stack-traces.
+
+### Example code
+
+See [sass compiler code example](api-compiler-example.md).
+
+### Basic Usage
+
+```C
+#include
+```
+
+### Sass Compiler API
+
+```C
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+// Create a new LibSass compiler context
+struct SassCompiler* sass_make_compiler();
+
+// Release all memory allocated with the compiler
+void sass_delete_compiler(struct SassCompiler* compiler);
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+// Parse the entry point and potentially all imports within.
+void sass_compiler_parse(struct SassCompiler* compiler);
+
+// Evaluate the parsed entry point and store resulting ast-tree.
+void sass_compiler_compile(struct SassCompiler* compiler);
+
+// Render the evaluated ast-tree to get the final output string.
+void sass_compiler_render(struct SassCompiler* compiler);
+
+// Write or print the output to the console or the configured output path
+void sass_compiler_write_output(struct SassCompiler* compiler);
+
+// Write source-map to configured path if options are set accordingly
+void sass_compiler_write_srcmap(struct SassCompiler* compiler);
+
+// Execute all compiler steps and write/print results
+int sass_compiler_execute(struct SassCompiler* compiler, bool quiet);
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+// Add additional include paths where LibSass will look for includes.
+// Note: the passed in `paths` can be path separated (`;` on windows, `:` otherwise).
+void sass_compiler_add_include_paths(struct SassCompiler* compiler, const char* paths);
+
+// Load dynamic loadable plugins from `paths`. Plugins are only supported on certain OSs and
+// are still in experimental state. This will look for `*.dll`, `*.so` or `*.dynlib` files.
+// It then tries to load the found libraries and does a few checks to see if the library
+// is actually a LibSass plugin. We then call its init hook if the library is compatible.
+// Note: the passed in `paths` can be path separated (`;` on windows, `:` otherwise).
+void sass_compiler_load_plugins(struct SassCompiler* compiler, const char* paths);
+
+// Add a custom header importer that will always be executed before any other
+// compilations takes place. Useful to prepend a shared copyright header or to
+// provide global variables or functions. This feature is still in experimental state.
+// Note: With the adaption of Sass Modules this might be completely replaced in the future.
+void sass_compiler_add_custom_header(struct SassCompiler* compiler, struct SassImporter* header);
+
+// Add a custom importer that will be executed when a sass `@import` rule is found.
+// This is useful to e.g. rewrite import locations or to load content from remote.
+// For more please check https://github.com/sass/libsass/blob/master/docs/api-importer.md
+// Note: The importer will not be called for regular css `@import url()` rules.
+void sass_compiler_add_custom_importer(struct SassCompiler* compiler, struct SassImporter* importer);
+
+// Add a custom function that will be executed when the corresponding function call is
+// requested from any sass code. This is useful to provide custom functions in your code.
+// For more please check https://github.com/sass/libsass/blob/master/docs/api-function.md
+void sass_compiler_add_custom_function(struct SassCompiler* compiler, struct SassFunction* function);
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+// Setter for output style (see `enum SassOutputStyle` for possible options).
+void sass_compiler_set_output_style(struct SassCompiler* compiler, enum SassOutputStyle output_style);
+
+// Try to detect and set logger options for terminal colors, unicode and columns.
+void sass_compiler_autodetect_logger_capabilities(struct SassCompiler* compiler);
+
+// Setter for enabling/disabling logging with ANSI colors.
+void sass_compiler_set_logger_colors(struct SassCompiler* compiler, bool enable);
+
+// Setter for enabling/disabling logging with unicode text.
+void sass_compiler_set_logger_unicode(struct SassCompiler* compiler, bool enable);
+
+// Getter for number precision (how floating point numbers are truncated).
+int sass_compiler_get_precision(struct SassCompiler* compiler);
+
+// Setter for number precision (how floating point numbers are truncated).
+void sass_compiler_set_precision(struct SassCompiler* compiler, int precision);
+
+// Getter for compiler entry point (which file or data to parse first).
+struct SassImport* sass_compiler_get_entry_point(struct SassCompiler* compiler);
+
+// Setter for compiler entry point (which file or data to parse first).
+void sass_compiler_set_entry_point(struct SassCompiler* compiler, struct SassImport* import);
+
+// Getter for compiler output path (where to store the result)
+// Note: LibSass does not write the file, implementers should write to this path.
+const char* sass_compiler_get_output_path(struct SassCompiler* compiler);
+
+// Setter for compiler output path (where to store the result)
+// Note: LibSass does not write the file, implementers should write to this path.
+void sass_compiler_set_output_path(struct SassCompiler* compiler, const char* output_path);
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+// Getter for warnings that occurred during any step.
+const char* sass_compiler_get_warn_string(struct SassCompiler* compiler);
+
+// Getter for output after parsing, compilation and rendering.
+const char* sass_compiler_get_output_string(struct SassCompiler* compiler);
+
+// Getter for footer string containing optional source-map (embedded or link).
+const char* sass_compiler_get_footer_string(struct SassCompiler* compiler);
+
+// Getter for string containing the optional source-mapping.
+const char* sass_compiler_get_srcmap_string(struct SassCompiler* compiler);
+
+// Check if implementor is expected to write a output file
+bool sass_compiler_has_output_file(struct SassCompiler* compiler);
+
+// Check if implementor is expected to write a source-map file
+bool sass_compiler_has_srcmap_file(struct SassCompiler* compiler);
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+// Setter for source-map mode (how to embed or not embed the source-map).
+void sass_compiler_set_srcmap_mode(struct SassCompiler* compiler, enum SassSrcMapMode mode);
+
+// Setter for source-map path (where to store the source-mapping).
+// Note: if path is not explicitly given, we will deduct one from output path.
+// Note: LibSass does not write the file, implementers should write to this path.
+void sass_compiler_set_srcmap_path(struct SassCompiler* compiler, const char* path);
+
+// Getter for source-map path (where to store the source-mapping).
+// Note: if path is not explicitly given, we will deduct one from output path.
+// Note: the value will only be deducted after the main render phase is completed.
+// Note: LibSass does not write the file, implementers should write to this path.
+const char* sass_compiler_get_srcmap_path(struct SassCompiler* compiler);
+
+// Setter for source-map root (simply passed to the resulting srcmap info).
+// Note: if not given, no root attribute will be added to the srcmap info object.
+void sass_compiler_set_srcmap_root(struct SassCompiler* compiler, const char* root);
+
+// Setter for source-map file-url option (renders urls in srcmap as `file://` urls)
+void sass_compiler_set_srcmap_file_urls(struct SassCompiler* compiler, bool enable);
+
+// Setter for source-map embed-contents option (includes full sources in the srcmap info)
+void sass_compiler_set_srcmap_embed_contents(struct SassCompiler* compiler, bool enable);
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+// Getter to return the number of all included files.
+size_t sass_compiler_get_included_files_count(struct SassCompiler* compiler);
+
+// Getter to return path to the included file at position `n`.
+const char* sass_compiler_get_included_file_path(struct SassCompiler* compiler, size_t n);
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+// Getter for current import context. Use `SassImport` functions to query the state.
+const struct SassImport* sass_compiler_get_last_import(struct SassCompiler* compiler);
+
+// Returns pointer to error object associated with compiler.
+// Will be valid until the associated compiler is destroyed.
+const struct SassError* sass_compiler_get_error(struct SassCompiler* compiler);
+
+// Returns status code for compiler (0 meaning success, anything else is an error)
+int sass_compiler_get_status(struct SassCompiler* compiler);
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+// Resolve a file relative to last import or include paths in the sass option struct.
+char* sass_compiler_find_file(const char* path, struct SassCompiler* compiler);
+
+// Resolve an include relative to last import or include paths in the sass option struct.
+// This will do a lookup as LibSass would do internally (partials, different extensions).
+// ToDo: Check if we should add `includeIndex` option to check for directory index files!?
+char* sass_compiler_find_include(const char* path, struct SassCompiler* compiler);
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+```
diff --git a/docs/api-context-example.md b/docs/api-context-example.md
deleted file mode 100644
index 97585a8b37..0000000000
--- a/docs/api-context-example.md
+++ /dev/null
@@ -1,94 +0,0 @@
-## Example for `data_context`
-
-```C:data.c
-#include
-#include "sass/context.h"
-
-int main( int argc, const char* argv[] )
-{
-
- // LibSass will take control of data you pass in
- // Therefore we need to make a copy of static data
- char* text = sass_copy_c_string("a{b:c;}");
- // Normally you'll load data into a buffer from i.e. the disk.
- // Use `sass_alloc_memory` to get a buffer to pass to LibSass
- // then fill it with data you load from disk or somewhere else.
-
- // create the data context and get all related structs
- struct Sass_Data_Context* data_ctx = sass_make_data_context(text);
- struct Sass_Context* ctx = sass_data_context_get_context(data_ctx);
- struct Sass_Options* ctx_opt = sass_context_get_options(ctx);
-
- // configure some options ...
- sass_option_set_precision(ctx_opt, 10);
-
- // context is set up, call the compile step now
- int status = sass_compile_data_context(data_ctx);
-
- // print the result or the error to the stdout
- if (status == 0) puts(sass_context_get_output_string(ctx));
- else puts(sass_context_get_error_message(ctx));
-
- // release allocated memory
- sass_delete_data_context(data_ctx);
-
- // exit status
- return status;
-
-}
-```
-
-### Compile data.c
-
-```bash
-gcc -c data.c -o data.o
-gcc -o sample data.o -lsass
-echo "foo { margin: 21px * 2; }" > foo.scss
-./sample foo.scss => "foo { margin: 42px }"
-```
-
-## Example for `file_context`
-
-```C:file.c
-#include
-#include "sass/context.h"
-
-int main( int argc, const char* argv[] )
-{
-
- // get the input file from first argument or use default
- const char* input = argc > 1 ? argv[1] : "styles.scss";
-
- // create the file context and get all related structs
- struct Sass_File_Context* file_ctx = sass_make_file_context(input);
- struct Sass_Context* ctx = sass_file_context_get_context(file_ctx);
- struct Sass_Options* ctx_opt = sass_context_get_options(ctx);
-
- // configure some options ...
- sass_option_set_precision(ctx_opt, 10);
-
- // context is set up, call the compile step now
- int status = sass_compile_file_context(file_ctx);
-
- // print the result or the error to the stdout
- if (status == 0) puts(sass_context_get_output_string(ctx));
- else puts(sass_context_get_error_message(ctx));
-
- // release allocated memory
- sass_delete_file_context(file_ctx);
-
- // exit status
- return status;
-
-}
-```
-
-### Compile file.c
-
-```bash
-gcc -c file.c -o file.o
-gcc -o sample file.o -lsass
-echo "foo { margin: 21px * 2; }" > foo.scss
-./sample foo.scss => "foo { margin: 42px }"
-```
-
diff --git a/docs/api-context-internal.md b/docs/api-context-internal.md
deleted file mode 100644
index 901b277c1f..0000000000
--- a/docs/api-context-internal.md
+++ /dev/null
@@ -1,163 +0,0 @@
-```C
-// Input behaviours
-enum Sass_Input_Style {
- SASS_CONTEXT_NULL,
- SASS_CONTEXT_FILE,
- SASS_CONTEXT_DATA,
- SASS_CONTEXT_FOLDER
-};
-
-// sass config options structure
-struct Sass_Inspect_Options {
-
- // Output style for the generated css code
- // A value from above SASS_STYLE_* constants
- enum Sass_Output_Style output_style;
-
- // Precision for fractional numbers
- int precision;
-
-};
-
-// sass config options structure
-struct Sass_Output_Options : Sass_Inspect_Options {
-
- // String to be used for indentation
- const char* indent;
- // String to be used to for line feeds
- const char* linefeed;
-
- // Emit comments in the generated CSS indicating
- // the corresponding source line.
- bool source_comments;
-
-};
-
-// sass config options structure
-struct Sass_Options : Sass_Output_Options {
-
- // embed sourceMappingUrl as data uri
- bool source_map_embed;
-
- // embed include contents in maps
- bool source_map_contents;
-
- // create file urls for sources
- bool source_map_file_urls;
-
- // Disable sourceMappingUrl in css output
- bool omit_source_map_url;
-
- // Treat source_string as sass (as opposed to scss)
- bool is_indented_syntax_src;
-
- // The input path is used for source map
- // generation. It can be used to define
- // something with string compilation or to
- // overload the input file path. It is
- // set to "stdin" for data contexts and
- // to the input file on file contexts.
- char* input_path;
-
- // The output path is used for source map
- // generation. LibSass will not write to
- // this file, it is just used to create
- // information in source-maps etc.
- char* output_path;
-
- // Colon-separated list of paths
- // Semicolon-separated on Windows
- // Maybe use array interface instead?
- char* include_path;
- char* plugin_path;
-
- // Include paths (linked string list)
- struct string_list* include_paths;
- // Plugin paths (linked string list)
- struct string_list* plugin_paths;
-
- // Path to source map file
- // Enables source map generation
- // Used to create sourceMappingUrl
- char* source_map_file;
-
- // Directly inserted in source maps
- char* source_map_root;
-
- // Custom functions that can be called from sccs code
- Sass_Function_List c_functions;
-
- // Callback to overload imports
- Sass_Importer_List c_importers;
-
- // List of custom headers
- Sass_Importer_List c_headers;
-
-};
-
-// base for all contexts
-struct Sass_Context : Sass_Options
-{
-
- // store context type info
- enum Sass_Input_Style type;
-
- // generated output data
- char* output_string;
-
- // generated source map json
- char* source_map_string;
-
- // error status
- int error_status;
- char* error_json;
- char* error_text;
- char* error_message;
- // error position
- char* error_file;
- size_t error_line;
- size_t error_column;
- char* error_src;
-
- // report imported files
- char** included_files;
-
-};
-
-// struct for file compilation
-struct Sass_File_Context : Sass_Context {
-
- // no additional fields required
- // input_path is already on options
-
-};
-
-// struct for data compilation
-struct Sass_Data_Context : Sass_Context {
-
- // provided source string
- char* source_string;
- char* srcmap_string;
-
-};
-
-// Compiler states
-enum Sass_Compiler_State {
- SASS_COMPILER_CREATED,
- SASS_COMPILER_PARSED,
- SASS_COMPILER_EXECUTED
-};
-
-// link c and cpp context
-struct Sass_Compiler {
- // progress status
- Sass_Compiler_State state;
- // original c context
- Sass_Context* c_ctx;
- // Sass::Context
- Sass::Context* cpp_ctx;
- // Sass::Block
- Sass::Block_Obj root;
-};
-```
-
diff --git a/docs/api-context.md b/docs/api-context.md
index e101da3082..c071db8800 100644
--- a/docs/api-context.md
+++ b/docs/api-context.md
@@ -1,298 +1,2 @@
-Sass Contexts come in two flavors:
-
-- `Sass_File_Context`
-- `Sass_Data_Context`
-
-### Basic Usage
-
-```C
-#include "sass/context.h"
-```
-
-***Sass_Options***
-
-```C
-// Precision for fractional numbers
-int precision;
-```
-```C
-// Output style for the generated css code
-// A value from above SASS_STYLE_* constants
-int output_style;
-```
-```C
-// Emit comments in the generated CSS indicating
-// the corresponding source line.
-bool source_comments;
-```
-```C
-// embed sourceMappingUrl as data uri
-bool source_map_embed;
-```
-```C
-// embed include contents in maps
-bool source_map_contents;
-```
-```C
-// create file urls for sources
-bool source_map_file_urls;
-```
-```C
-// Disable sourceMappingUrl in css output
-bool omit_source_map_url;
-```
-```C
-// Treat source_string as sass (as opposed to scss)
-bool is_indented_syntax_src;
-```
-```C
-// The input path is used for source map
-// generating. It can be used to define
-// something with string compilation or to
-// overload the input file path. It is
-// set to "stdin" for data contexts and
-// to the input file on file contexts.
-char* input_path;
-```
-```C
-// The output path is used for source map
-// generating. LibSass will not write to
-// this file, it is just used to create
-// information in source-maps etc.
-char* output_path;
-```
-```C
-// String to be used for indentation
-const char* indent;
-```
-```C
-// String to be used to for line feeds
-const char* linefeed;
-```
-```C
-// Colon-separated list of paths
-// Semicolon-separated on Windows
-char* include_path;
-char* plugin_path;
-```
-```C
-// Additional include paths
-// Must be null delimited
-char** include_paths;
-char** plugin_paths;
-```
-```C
-// Path to source map file
-// Enables the source map generating
-// Used to create sourceMappingUrl
-char* source_map_file;
-```
-```C
-// Directly inserted in source maps
-char* source_map_root;
-```
-```C
-// Custom functions that can be called from Sass code
-Sass_C_Function_List c_functions;
-```
-```C
-// Callback to overload imports
-Sass_C_Import_Callback importer;
-```
-
-***Sass_Context***
-
-```C
-// store context type info
-enum Sass_Input_Style type;
-````
-```C
-// generated output data
-char* output_string;
-```
-```C
-// generated source map json
-char* source_map_string;
-```
-```C
-// error status
-int error_status;
-char* error_json;
-char* error_text;
-char* error_message;
-// error position
-char* error_file;
-size_t error_line;
-size_t error_column;
-char* error_src;
-```
-```C
-// report imported files
-char** included_files;
-```
-
-***Sass_File_Context***
-
-```C
-// no additional fields required
-// input_path is already on options
-```
-
-***Sass_Data_Context***
-
-```C
-// provided source string
-char* source_string;
-```
-
-### Sass Context API
-
-```C
-// Forward declaration
-struct Sass_Compiler;
-
-// Forward declaration
-struct Sass_Options;
-struct Sass_Context; // : Sass_Options
-struct Sass_File_Context; // : Sass_Context
-struct Sass_Data_Context; // : Sass_Context
-
-// Create and initialize an option struct
-struct Sass_Options* sass_make_options (void);
-// Create and initialize a specific context
-struct Sass_File_Context* sass_make_file_context (const char* input_path);
-struct Sass_Data_Context* sass_make_data_context (char* source_string);
-
-// Call the compilation step for the specific context
-int sass_compile_file_context (struct Sass_File_Context* ctx);
-int sass_compile_data_context (struct Sass_Data_Context* ctx);
-
-// Create a sass compiler instance for more control
-struct Sass_Compiler* sass_make_file_compiler (struct Sass_File_Context* file_ctx);
-struct Sass_Compiler* 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
-int sass_compiler_parse (struct Sass_Compiler* compiler);
-int sass_compiler_execute (struct Sass_Compiler* compiler);
-
-// Release all memory allocated with the compiler
-// This does _not_ include any contexts or options
-void sass_delete_compiler (struct Sass_Compiler* compiler);
-void sass_delete_options(struct Sass_Options* options);
-
-// Release all memory allocated and also ourself
-void sass_delete_file_context (struct Sass_File_Context* ctx);
-void sass_delete_data_context (struct Sass_Data_Context* ctx);
-
-// Getters for Context from specific implementation
-struct Sass_Context* sass_file_context_get_context (struct Sass_File_Context* file_ctx);
-struct Sass_Context* sass_data_context_get_context (struct Sass_Data_Context* data_ctx);
-
-// Getters for Context_Options from Sass_Context
-struct Sass_Options* sass_context_get_options (struct Sass_Context* ctx);
-struct Sass_Options* sass_file_context_get_options (struct Sass_File_Context* file_ctx);
-struct Sass_Options* sass_data_context_get_options (struct Sass_Data_Context* data_ctx);
-void sass_file_context_set_options (struct Sass_File_Context* file_ctx, struct Sass_Options* opt);
-void sass_data_context_set_options (struct Sass_Data_Context* data_ctx, struct Sass_Options* opt);
-
-// Getters for Sass_Context values
-const char* sass_context_get_output_string (struct Sass_Context* ctx);
-int sass_context_get_error_status (struct Sass_Context* ctx);
-const char* sass_context_get_error_json (struct Sass_Context* ctx);
-const char* sass_context_get_error_text (struct Sass_Context* ctx);
-const char* sass_context_get_error_message (struct Sass_Context* ctx);
-const char* sass_context_get_error_file (struct Sass_Context* ctx);
-const char* sass_context_get_error_src (struct Sass_Context* ctx);
-size_t sass_context_get_error_line (struct Sass_Context* ctx);
-size_t sass_context_get_error_column (struct Sass_Context* ctx);
-const char* sass_context_get_source_map_string (struct Sass_Context* ctx);
-char** sass_context_get_included_files (struct Sass_Context* ctx);
-
-// Getters for Sass_Compiler options (query import stack)
-size_t sass_compiler_get_import_stack_size(struct Sass_Compiler* compiler);
-Sass_Import_Entry sass_compiler_get_last_import(struct Sass_Compiler* compiler);
-Sass_Import_Entry sass_compiler_get_import_entry(struct Sass_Compiler* compiler, size_t idx);
-// Getters for Sass_Compiler options (query function stack)
-size_t sass_compiler_get_callee_stack_size(struct Sass_Compiler* compiler);
-Sass_Callee_Entry sass_compiler_get_last_callee(struct Sass_Compiler* compiler);
-Sass_Callee_Entry sass_compiler_get_callee_entry(struct Sass_Compiler* compiler, size_t idx);
-
-// Take ownership of memory (value on context is set to 0)
-char* sass_context_take_error_json (struct Sass_Context* ctx);
-char* sass_context_take_error_text (struct Sass_Context* ctx);
-char* sass_context_take_error_message (struct Sass_Context* ctx);
-char* sass_context_take_error_file (struct Sass_Context* ctx);
-char* sass_context_take_error_src (struct Sass_Context* ctx);
-char* sass_context_take_output_string (struct Sass_Context* ctx);
-char* sass_context_take_source_map_string (struct Sass_Context* ctx);
-```
-
-### Sass Options API
-
-```C
-// Getters for Context_Option values
-int sass_option_get_precision (struct Sass_Options* options);
-enum Sass_Output_Style sass_option_get_output_style (struct Sass_Options* options);
-bool sass_option_get_source_comments (struct Sass_Options* options);
-bool sass_option_get_source_map_embed (struct Sass_Options* options);
-bool sass_option_get_source_map_contents (struct Sass_Options* options);
-bool sass_option_get_source_map_file_urls (struct Sass_Options* options);
-bool sass_option_get_omit_source_map_url (struct Sass_Options* options);
-bool sass_option_get_is_indented_syntax_src (struct Sass_Options* options);
-const char* sass_option_get_indent (struct Sass_Options* options);
-const char* sass_option_get_linefeed (struct Sass_Options* options);
-const char* sass_option_get_input_path (struct Sass_Options* options);
-const char* sass_option_get_output_path (struct Sass_Options* options);
-const char* sass_option_get_source_map_file (struct Sass_Options* options);
-const char* sass_option_get_source_map_root (struct Sass_Options* options);
-Sass_C_Function_List sass_option_get_c_functions (struct Sass_Options* options);
-Sass_C_Import_Callback sass_option_get_importer (struct Sass_Options* options);
-
-// Getters for Context_Option include path array
-size_t sass_option_get_include_path_size(struct Sass_Options* options);
-const char* sass_option_get_include_path(struct Sass_Options* options, size_t i);
-// Plugin paths to load dynamic libraries work the same
-size_t sass_option_get_plugin_path_size(struct Sass_Options* options);
-const char* sass_option_get_plugin_path(struct Sass_Options* options, size_t i);
-
-// Setters for Context_Option values
-void sass_option_set_precision (struct Sass_Options* options, int precision);
-void sass_option_set_output_style (struct Sass_Options* options, enum Sass_Output_Style output_style);
-void sass_option_set_source_comments (struct Sass_Options* options, bool source_comments);
-void sass_option_set_source_map_embed (struct Sass_Options* options, bool source_map_embed);
-void sass_option_set_source_map_contents (struct Sass_Options* options, bool source_map_contents);
-void sass_option_set_source_map_file_urls (struct Sass_Options* options, bool source_map_file_urls);
-void sass_option_set_omit_source_map_url (struct Sass_Options* options, bool omit_source_map_url);
-void sass_option_set_is_indented_syntax_src (struct Sass_Options* options, bool is_indented_syntax_src);
-void sass_option_set_indent (struct Sass_Options* options, const char* indent);
-void sass_option_set_linefeed (struct Sass_Options* options, const char* linefeed);
-void sass_option_set_input_path (struct Sass_Options* options, const char* input_path);
-void sass_option_set_output_path (struct Sass_Options* options, const char* output_path);
-void sass_option_set_plugin_path (struct Sass_Options* options, const char* plugin_path);
-void sass_option_set_include_path (struct Sass_Options* options, const char* include_path);
-void sass_option_set_source_map_file (struct Sass_Options* options, const char* source_map_file);
-void sass_option_set_source_map_root (struct Sass_Options* options, const char* source_map_root);
-void sass_option_set_c_functions (struct Sass_Options* options, Sass_C_Function_List c_functions);
-void sass_option_set_importer (struct Sass_Options* options, Sass_C_Import_Callback importer);
-
-// Push function for paths (no manipulation support for now)
-void sass_option_push_plugin_path (struct Sass_Options* options, const char* path);
-void sass_option_push_include_path (struct Sass_Options* options, const char* path);
-
-// Resolve a file via the given include paths in the sass option struct
-// find_file looks for the exact file name while find_include does a regular sass include
-char* sass_find_file (const char* path, struct Sass_Options* opt);
-char* sass_find_include (const char* path, struct Sass_Options* opt);
-
-// Resolve a file relative to last import or include paths in the sass option struct
-// find_file looks for the exact file name while find_include does a regular sass include
-char* sass_compiler_find_file (const char* path, struct Sass_Compiler* compiler);
-char* sass_compiler_find_include (const char* path, struct Sass_Compiler* compiler);
-```
-
-### More links
-
-- [Sass Context Example](api-context-example.md)
-- [Sass Context Internal](api-context-internal.md)
-
+Context was moved to compiler.
+- [See compiler documentation](api-compiler.md)
diff --git a/docs/api-doc.md b/docs/api-doc.md
index 5e8ad7962c..461e73bc42 100644
--- a/docs/api-doc.md
+++ b/docs/api-doc.md
@@ -1,29 +1,41 @@
## Introduction
-LibSass wouldn't be much good without a way to interface with it. These
-interface documentations describe the various functions and data structures
-available to implementers. They are split up over three major components, which
-have all their own source files (plus some common functionality).
-
-- [Sass Context](api-context.md) - Trigger and handle the main Sass compilation
-- [Sass Value](api-value.md) - Exchange values and its format with LibSass
-- [Sass Function](api-function.md) - Get invoked by LibSass for function statments
-- [Sass Importer](api-importer.md) - Get invoked by LibSass for @import statments
+LibSass C-API is designed as a functional API; every access on the C-API is a
+function call. This has a few drawbacks, but a lot of desirable characteristics.
+The most important one is that it reduces the API surface to simple function calls.
+Implementors do not need to know how internal structures look, so we are free
+to adjust them as we see fit, as long as the functional API stays the same.
+
+Under the hood, LibSass uses advanced C++ code (c++11 being the current target), so
+you will need a modern compiler and also link against c++ runtime libraries. This poses
+some issues in regard of portability and deployment of precompiled binary distributions.
+
+The API has been split into a few categories which come with their own documentation:
+
+- [Sass Basics](api-basics.md) - Further details and information about the C-API
+- [Sass Compiler](api-compiler.md) - Trigger and handle the main Sass compilation
+- [Sass Imports](api-import.md) - Imports to be loaded and parsed by LibSass
+- [Sass Values](api-value.md) - Exchange Sass values between LibSass and implementors
+- [Sass Functions](api-function.md) - Get invoked by LibSass for function statements
+- [Sass Importers](api-importer.md) - Get invoked by LibSass for @import statements
+- [Sass Variables](api-variable.md) - Query or update existing scope variables
+- [Sass Traces](api-traces.md) - Access to traces for debug information
+- [Sass Error](api-error.md) - Access to errors for debug information
### Basic usage
First you will need to include the header file!
-This will automatically load all other headers too!
+This will automatically load all LibSass headers!
```C
-#include "sass/context.h"
+#include
```
## Basic C Example
```C
#include
-#include "sass/context.h"
+#include
int main() {
puts(libsass_version());
@@ -31,147 +43,148 @@ int main() {
}
```
+### Compile and link against LibSass
+
```bash
gcc -Wall version.c -lsass -o version && ./version
```
-## More C Examples
+## More code examples
-- [Sample code for Sass Context](api-context-example.md)
-- [Sample code for Sass Value](api-value-example.md)
+- [Sample code for Sass Compiler](api-compiler-example.md)
- [Sample code for Sass Function](api-function-example.md)
- [Sample code for Sass Importer](api-importer-example.md)
+- [Sample code for Sass Value](api-value-example.md)
-## Compiling your code
-
-The most important is your sass file (or string of sass code). With this, you
-will want to start a LibSass compiler. Here is some pseudocode describing the
-process. The compiler has two different modes: direct input as a string with
-`Sass_Data_Context` or LibSass will do file reading for you by using
-`Sass_File_Context`. See the code for a list of options available
-[Sass_Options](https://github.com/sass/libsass/blob/36feef0/include/sass/interface.h#L18)
-
-The general rule is if the API takes `const char*` it will make a copy,
-but where the API is `char*` it will take over memory ownership, so make sure to pass
-in memory that is allocated via `sass_copy_c_string` or `sass_alloc_memory`.
-
-**Building a file compiler**
-
- context = sass_make_file_context("file.scss")
- options = sass_file_context_get_options(context)
- sass_option_set_precision(options, 1)
- sass_option_set_source_comments(options, true)
-
- sass_file_context_set_options(context, options)
-
- compiler = sass_make_file_compiler(sass_context)
- sass_compiler_parse(compiler)
- sass_compiler_execute(compiler)
-
- output = sass_context_get_output_string(context)
- // Retrieve errors during compilation
- error_status = sass_context_get_error_status(context)
- json_error = sass_context_get_error_json(context)
- // Release memory dedicated to the C compiler
- sass_delete_compiler(compiler)
-
-**Building a data compiler**
-
- // LibSass takes over memory owenership, make sure to allocate
- // a buffer via `sass_alloc_memory` or `sass_copy_c_string`.
- buffer = sass_copy_c_string("div { a { color: blue; } }")
-
- context = sass_make_data_context(buffer)
- options = sass_data_context_get_options(context)
- sass_option_set_precision(options, 1)
- sass_option_set_source_comments(options, true)
-
- sass_data_context_set_options(context, options)
-
- compiler = sass_make_data_compiler(context)
- sass_compiler_parse(compiler)
- sass_compiler_execute(compiler)
-
- output = sass_context_get_output_string(context)
- // div a { color: blue; }
- // Retrieve errors during compilation
- error_status = sass_context_get_error_status(context)
- json_error = sass_context_get_error_json(context)
- // Release memory dedicated to the C compiler
- sass_delete_compiler(compiler)
-
-## Sass Context Internals
-
-Everything is stored in structs:
-
-```C
-struct Sass_Options;
-struct Sass_Context : Sass_Options;
-struct Sass_File_context : Sass_Context;
-struct Sass_Data_context : Sass_Context;
-```
-
-This mirrors very well how `libsass` uses these structures.
-
-- `Sass_Options` holds everything you feed in before the compilation. It also hosts
-`input_path` and `output_path` options, because they are used to generate/calculate
-relative links in source-maps. The `input_path` is shared with `Sass_File_Context`.
-- `Sass_Context` holds all the data returned by the compilation step.
-- `Sass_File_Context` is a specific implementation that requires no additional fields
-- `Sass_Data_Context` is a specific implementation that adds the `input_source` field
-
-Structs can be down-casted to access `context` or `options`!
+## Compiler entry points
+
+LibSass parsing starts with an entry point, which can either be a
+file or some text you provide directly. Relative includes are
+resolved against the current (virtual) working directory. Entry
+points must be of type `struct SassImport*` and can be created
+via different constructor functions:
+
+- `sass_make_file_import("styles.scss"); // loads the file`
+- `sass_make_stdin_import("styles.scss"); // reads from stdin`
+- `sass_make_content_import(text, "styles.scss"); // uses text`
+- `sass_make_import(imp_path, abs_path, source, srcmap, format);`
+
+Remember that `SassImport` must be freed via `sass_delete_import`.
+
+**Building a compiler**
+
+ // Create the main compiler object
+ struct SassCompiler* compiler = sass_make_compiler();
+ // Check terminal capabilities (useful for CLI tools)
+ sass_compiler_autodetect_logger_capabilities(compiler);
+ // Create a file-import entry point (without input file-name)
+ struct SassImport* import = sass_make_content_import("foo{bar:baz}", 0);
+ // Set import syntax since input has no file extension
+ sass_import_set_syntax(import, SASS_IMPORT_SCSS);
+ // Tell compiler which entry point to load
+ sass_compiler_set_entry_point(compiler, import);
+ // We are done with this (ref-counted) import
+ sass_delete_import(import);
+ // Execute compiler and print/write results
+ sass_compiler_execute(compiler, false);
+ // Get result code after all compilation steps
+ int status = sass_compiler_get_status(compiler);
+ // Clean-up compiler, we're done
+ sass_delete_compiler(compiler);
+ // exit status
+ return status;
## Memory handling and life-cycles
-We keep memory around for as long as the main [context](api-context.md) object
-is not destroyed (`sass_delete_context`). LibSass will create copies of most
-inputs/options beside the main sass code. You need to allocate and fill that
-buffer before passing it to LibSass. You may also overtake memory management
-from libsass for certain return values (i.e. `sass_context_take_output_string`).
-Make sure to free it via `sass_free_memory`.
+The C-API mandates that you have one delete/free call for every make call. Internally
+LibSass sometimes utilizes reference counting, but you still need to call the appropriate
+`sass_delete` function for every object you own. APIs that return a `char*` also need
+the returned memory to be freed by `sass_free_c_string`. A few APIs also allow
+implementors to take over ownership of some data. Otherwise this data is attached
+to the life-time of the main Compiler object. Although reference counted objects
+will stay alive, even after you've called `sass_delete_compiler`.
```C
-// to allocate buffer to be filled
+// 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.
void* sass_alloc_memory(size_t size);
-// to allocate a buffer from existing string
+
+// 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.
char* sass_copy_c_string(const char* str);
-// to free overtaken memory when done
+
+// Deallocate libsass heap memory
void sass_free_memory(void* ptr);
+void sass_free_c_string(char* ptr);
```
## Miscellaneous API functions
```C
-// Some convenient string helper function
-char* sass_string_unquote (const char* str);
-char* sass_string_quote (const char* str, const char quote_mark);
+// Change the virtual current working directory
+void sass_chdir(const char* path);
-// Get compiled libsass version
+// Prints message to stderr with color for windows
+void sass_print_stdout(const char* message);
+void sass_print_stderr(const char* message);
+
+// Get compiled LibSass version
const char* libsass_version(void);
// Implemented sass language version
-// Hardcoded version 3.4 for time being
+// Hardcoded version 3.9 for time being
const char* libsass_language_version(void);
```
-## Common Pitfalls
+## Miscellaneous API enums
-**input_path**
-
-The `input_path` is part of `Sass_Options`, but it also is the main option for
-`Sass_File_Context`. It is also used to generate relative file links in source-
-maps. Therefore it is pretty useful to pass this information if you have a
-`Sass_Data_Context` and know the original path.
-
-**output_path**
+```C
+// Different render styles
+enum SassOutputStyle {
+ SASS_STYLE_NESTED,
+ SASS_STYLE_EXPANDED,
+ SASS_STYLE_COMPACT,
+ SASS_STYLE_COMPRESSED,
+ // only used internally!
+ SASS_STYLE_TO_CSS
+};
+
+// Type of parser to use
+enum SassImportSyntax {
+ SASS_IMPORT_AUTO,
+ SASS_IMPORT_SCSS,
+ SASS_IMPORT_SASS,
+ SASS_IMPORT_CSS,
+};
+
+// Config how to produce source-map
+enum SassSrcMapMode {
+ // Don't render any source-mapping.
+ SASS_SRCMAP_NONE,
+ // Only render the `srcmap` string.
+ // The `footer` will be `NULL`.
+ SASS_SRCMAP_CREATE,
+ // Write srcmap link into `footer`
+ SASS_SRCMAP_EMBED_LINK,
+ // Embed srcmap into `footer`
+ SASS_SRCMAP_EMBED_JSON,
+};
+
+// State of the compiler object
+enum SassCompilerState {
+ SASS_COMPILER_CREATED,
+ SASS_COMPILER_PARSED,
+ SASS_COMPILER_COMPILED,
+ SASS_COMPILER_RENDERED,
+ SASS_COMPILER_DESTROYED
+};
+```
-Be aware that `libsass` does not write the output file itself. This option
-merely exists to give `libsass` the proper information to generate links in
-source-maps. The file has to be written to the disk by the
-binding/implementation. If the `output_path` is omitted, `libsass` tries to
-extrapolate one from the `input_path` by replacing (or adding) the file ending
-with `.css`.
+## Common Pitfalls
## Error Codes
@@ -199,26 +212,12 @@ have all features implemented!
2. [Go Example](https://godoc.org/github.com/wellington/go-libsass#example-Compiler--Stdin)
3. [Node Example](https://github.com/sass/node-sass/blob/master/src/binding.cpp)
-## ABI forward compatibility
-
-We use a functional API to make dynamic linking more robust and future
-compatible. The API is not yet 100% stable, so we do not yet guarantee
-[ABI](https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html) forward
-compatibility.
-
## Plugins (experimental)
-LibSass can load plugins from directories. Just define `plugin_path` on context
-options to load all plugins from the directories. To implement plugins, please
-consult the following example implementations.
+LibSass can [load plugins](dev-plugins.md) from directories. Just define `plugin_path`
+on context options to load all plugins from the directories. To implement plugins,
+please consult the following example implementations.
- https://github.com/mgreter/libsass-glob
- https://github.com/mgreter/libsass-math
- https://github.com/mgreter/libsass-digest
-
-## Internal Structs
-
-- [Sass Context Internals](api-context-internal.md)
-- [Sass Value Internals](api-value-internal.md)
-- [Sass Function Internals](api-function-internal.md)
-- [Sass Importer Internals](api-importer-internal.md)
diff --git a/docs/api-error.md b/docs/api-error.md
new file mode 100644
index 0000000000..c1cbfdd479
--- /dev/null
+++ b/docs/api-error.md
@@ -0,0 +1,60 @@
+## LibSass C-API for errors
+
+API to get additional information for errors occurring during custom functions.
+Error object are not reference counted and are coupled to the compiler life-cycle.
+You can also use them to inspect errors after the compiler failed at any phase.
+
+### Basic Usage
+
+```C
+#include
+```
+
+## Sass Function API
+
+```C
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+// Error related getters (use after compiler was rendered)
+int sass_error_get_status(const struct SassError* error);
+
+// Getter for plain error message (use after compiler was rendered).
+const char* sass_error_get_string(const struct SassError* error);
+
+// Getter for error status as css (In order to show error in browser).
+// Memory returned by this function must be freed via `sass_free_c_string`.
+char* sass_error_get_css(const struct SassError* error);
+
+// Getter for error status as json object (Useful to pass to downstream).
+// Memory returned by this function must be freed via `sass_free_c_string`.
+char* sass_error_get_json(const struct SassError* error);
+
+// Getter for formatted error message. According to logger style this
+// may be in unicode and may contain ANSI escape codes for colors.
+const char* sass_error_get_formatted(const struct SassError* error);
+
+// Getter for line position where error occurred (starts from 1).
+size_t sass_error_get_line(const struct SassError* error);
+
+// Getter for column position where error occurred (starts from 1).
+size_t sass_error_get_column(const struct SassError* error);
+
+// Getter for source content referenced in line and column.
+const char* sass_error_get_content(const struct SassError* error);
+
+// Getter for path where the error occurred.
+const char* sass_error_get_path(const struct SassError* error);
+
+// Getter for number of traces attached to error object.
+size_t sass_error_count_traces(const struct SassError* error);
+
+// Getter for last trace (or nullptr if none are available).
+const struct SassTrace* sass_error_last_trace(const struct SassError* error);
+
+// Getter for nth trace (or nullptr if `n` is invalid).
+const struct SassTrace* sass_error_get_trace(const struct SassError* error, size_t n);
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+```
diff --git a/docs/api-function-example.md b/docs/api-function-example.md
index 38608e1a27..f77c1b03fa 100644
--- a/docs/api-function-example.md
+++ b/docs/api-function-example.md
@@ -1,58 +1,58 @@
## Example main.c
```C
-#include
-#include
-#include "sass/context.h"
+#include
+#include
+#include
+#include
-union Sass_Value* call_fn_foo(const union Sass_Value* s_args, Sass_Function_Entry cb, struct Sass_Compiler* comp)
+struct Cookie {
+ double number;
+};
+
+// Note: some compilers allow to directly use `struct Cookie*` instead of `void*` for the cookie ptr.
+struct SassValue* call_fn_foo(struct SassValue* s_args, struct SassCompiler* compiler, void* cookie)
{
- // get context/option struct associated with this compiler
- struct Sass_Context* ctx = sass_compiler_get_context(comp);
- struct Sass_Options* opts = sass_compiler_get_options(comp);
- // get information about previous importer entry from the stack
- Sass_Import_Entry import = sass_compiler_get_last_import(comp);
- const char* prev_abs_path = sass_import_get_abs_path(import);
- const char* prev_imp_path = sass_import_get_imp_path(import);
- // get the cookie from function descriptor
- void* cookie = sass_function_get_cookie(cb);
- // we actually abuse the void* to store an "int"
- return sass_make_number((intptr_t)cookie, "px");
+ // Statically cast to type we passed the cookie
+ struct Cookie* casted = (struct Cookie*)cookie;
+ // Now we can access whatever we put into the cookie
+ return sass_make_number(casted->number, "px");
}
-int main( int argc, const char* argv[] )
+int main(int argc, const char* argv[])
{
- // get the input file from first argument or use default
+ // Get the input file from first argument or use default
const char* input = argc > 1 ? argv[1] : "styles.scss";
- // create the file context and get all related structs
- struct Sass_File_Context* file_ctx = sass_make_file_context(input);
- struct Sass_Context* ctx = sass_file_context_get_context(file_ctx);
- struct Sass_Options* ctx_opt = sass_context_get_options(ctx);
+ // Create the main compiler object instance
+ struct SassCompiler* compiler = sass_make_compiler();
+
+ // Cookie structure to attach to function
+ // Allows you to pass anything you want
+ struct Cookie cookie = { 42 };
- // allocate a custom function caller
- Sass_Function_Entry fn_foo =
- sass_make_function("foo()", call_fn_foo, (void*)42);
+ // This may fail and produce an error if
+ // the passed signature cannot be parsed.
+ sass_compiler_add_custom_function(compiler,
+ sass_make_function("foo()", call_fn_foo, (void*)&cookie));
- // create list of all custom functions
- Sass_Function_List fn_list = sass_make_function_list(1);
- sass_function_set_list_entry(fn_list, 0, fn_foo);
- sass_option_set_c_functions(ctx_opt, fn_list);
+ // Create import, set as entry point and release our usage
+ struct SassImport* import = sass_make_file_import(input);
+ sass_compiler_set_entry_point(compiler, import);
+ sass_delete_import(import);
- // context is set up, call the compile step now
- int status = sass_compile_file_context(file_ctx);
+ // Execute compiler and print/write results
+ sass_compiler_execute(compiler, false);
- // print the result or the error to the stdout
- if (status == 0) puts(sass_context_get_output_string(ctx));
- else puts(sass_context_get_error_message(ctx));
+ // Get result code after all compilation steps
+ int status = sass_compiler_get_status(compiler);
- // release allocated memory
- sass_delete_file_context(file_ctx);
+ // Clean-up compiler, we're done
+ sass_delete_compiler(compiler);
// exit status
return status;
-
}
```
@@ -60,7 +60,7 @@ int main( int argc, const char* argv[] )
```bash
gcc -c main.c -o main.o
-gcc -o sample main.o -lsass
+g++ -o sample main.o -lsass
echo "foo { margin: foo(); }" > foo.scss
./sample foo.scss => "foo { margin: 42px }"
```
diff --git a/docs/api-function-internal.md b/docs/api-function-internal.md
deleted file mode 100644
index 69d81d04d1..0000000000
--- a/docs/api-function-internal.md
+++ /dev/null
@@ -1,8 +0,0 @@
-```C
-// Struct to hold custom function callback
-struct Sass_Function {
- const char* signature;
- Sass_Function_Fn function;
- void* cookie;
-};
-```
diff --git a/docs/api-function.md b/docs/api-function.md
index 8d9d97ca4e..55ab30e41f 100644
--- a/docs/api-function.md
+++ b/docs/api-function.md
@@ -1,4 +1,11 @@
-Sass functions are used to define new custom functions callable by Sass code. They are also used to overload debug or error statements. You can also define a fallback function, which is called for every unknown function found in the Sass code. Functions get passed zero or more `Sass_Values` (a `Sass_List` value) and they must also return a `Sass_Value`. Return a `Sass_Error` if you want to signal an error.
+## LibSass custom functions C-API
+
+Sass functions are used to define custom functions callable by Sass code.
+They are also used to overload `@debug`, `@warn` or `@error` rules. Additionally you
+can define a fallback function, which is called for every unknown function found in
+your Sass code. Functions get passed zero or more `SassValues` (a `SassList` value)
+and they must also return a `SassValue`. Any custom function may also return
+a `SassError` value to signal an error during execution.
## Special signatures
@@ -7,68 +14,52 @@ Sass functions are used to define new custom functions callable by Sass code. Th
- `@error` - Overload error statements
- `@debug` - Overload debug statements
-Note: The fallback implementation will be given the name of the called function as the first argument, before all the original function arguments. These features are pretty new and should be considered experimental.
+Note: The fallback implementation will be given the name of the called function
+as the first argument, before all the original function arguments. These features
+are pretty new and should be considered experimental.
+
+### Example code
+
+See [sass function code example](api-function-example.md).
### Basic Usage
```C
-#include "sass/functions.h"
+#include
```
## Sass Function API
```C
-// Forward declaration
-struct Sass_Compiler;
-struct Sass_Function;
-
-// 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);
-
-// Creators for sass function list and function descriptors
-Sass_Function_List sass_make_function_list (size_t length);
-Sass_Function_Entry sass_make_function (const char* signature, Sass_Function_Fn cb, void* cookie);
-// In case you need to free them yourself
-void sass_delete_function (Sass_Function_Entry entry);
-void sass_delete_function_list (Sass_Function_List list);
-
-// Setters and getters for callbacks on function lists
-Sass_Function_Entry sass_function_get_list_entry(Sass_Function_List list, size_t pos);
-void sass_function_set_list_entry(Sass_Function_List list, size_t pos, Sass_Function_Entry cb);
-
-// Setters to insert an entry into the import list (you may also use [] access directly)
-// Since we are dealing with pointers they should have a guaranteed and fixed size
-void sass_import_set_list_entry (Sass_Import_List list, size_t idx, Sass_Import_Entry entry);
-Sass_Import_Entry sass_import_get_list_entry (Sass_Import_List list, size_t idx);
-
-// Getters for custom function descriptors
-const char* sass_function_get_signature (Sass_Function_Entry cb);
-Sass_Function_Fn sass_function_get_function (Sass_Function_Entry cb);
-void* sass_function_get_cookie (Sass_Function_Entry cb);
-
-// Getters for callee entry
-const char* sass_callee_get_name (Sass_Callee_Entry);
-const char* sass_callee_get_path (Sass_Callee_Entry);
-size_t sass_callee_get_line (Sass_Callee_Entry);
-size_t sass_callee_get_column (Sass_Callee_Entry);
-enum Sass_Callee_Type sass_callee_get_type (Sass_Callee_Entry);
-Sass_Env_Frame sass_callee_get_env (Sass_Callee_Entry);
-
-// Getters and Setters for environments (lexical, local and global)
-union Sass_Value* sass_env_get_lexical (Sass_Env_Frame, const char*);
-void sass_env_set_lexical (Sass_Env_Frame, const char*, union Sass_Value*);
-union Sass_Value* sass_env_get_local (Sass_Env_Frame, const char*);
-void sass_env_set_local (Sass_Env_Frame, const char*, union Sass_Value*);
-union Sass_Value* sass_env_get_global (Sass_Env_Frame, const char*);
-void sass_env_set_global (Sass_Env_Frame, const char*, union Sass_Value*);
-```
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+// Type definition for custom functions
+typedef struct SassValue* (*SassFunctionLambda)(
+ struct SassValue*, struct SassCompiler* compiler, void* cookie);
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
-### More links
+// Create custom function (with arbitrary data pointer called `cookie`)
+// The pointer is often used to store the callback into the actual binding.
+struct SassFunction* sass_make_function (const char* signature, SassFunctionLambda lambda, void* cookie);
-- [Sass Function Example](api-function-example.md)
-- [Sass Function Internal](api-function-internal.md)
+// Deallocate custom function and release memory
+void sass_delete_function (struct SassFunction* entry);
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+// Getter for custom function signature.
+const char* sass_function_get_signature (struct SassFunction* function);
+
+// Getter for custom function lambda.
+SassFunctionLambda sass_function_get_lambda (struct SassFunction* function);
+
+// Getter for custom function data cookie.
+void* sass_function_get_cookie (struct SassFunction* function);
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+```
diff --git a/docs/api-import.md b/docs/api-import.md
new file mode 100644
index 0000000000..c1fce7cf69
--- /dev/null
+++ b/docs/api-import.md
@@ -0,0 +1,99 @@
+
+## LibSass import C-API
+
+Imports on the C-API side can either be used as compilation entry points or
+imports returned from custom importers/headers. They represent a loadable
+resource with text to be parsed. These object are reference-counted and
+must always be freed by the allocator. To improve usage with `SassImportList`
+there is a convenience method `sass_import_list_emplace` that will transfer
+the ownership of the import to the list object.
+
+### Imports and source-maps
+
+Source-maps embedded in imports are not automatically parsed out. Ideally we
+would want to automatically load associated source-maps for inputs. Currently
+LibSass does not make use of any upstream source-maps. The API has been designed
+with that case in mind, but implementation is not done yet. Everything still
+works, but additional source-maps may end up as superfluous comments.
+
+### Basic Usage
+
+```C
+#include
+```
+
+### Sass Import API
+
+```C
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+// Create import entry by reading from `stdin`.
+struct SassImport* sass_make_stdin_import(const char* imp_path);
+
+// Create import entry to load the passed input path.
+struct SassImport* sass_make_file_import(const char* imp_path);
+
+// Create import entry for the passed data with optional path.
+// Note: we take ownership of the passed `content` memory.
+struct SassImport* sass_make_content_import(char* content, const char* imp_path);
+
+// Create single import entry returned by the custom importer inside the list.
+// Note: source/srcmap can be empty to let LibSass do the file resolving.
+// Note: we take ownership of the passed `source` and `srcmap` memory.
+struct SassImport* sass_make_import(const char* imp_path, const char* abs_base,
+ char* source, char* srcmap, enum SassImportSyntax format);
+
+// Just in case we have some stray import structs
+void sass_delete_import(struct SassImport* import);
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+// Getter for specific import format for the given import (force css/sass/scss or set to auto)
+enum SassImportSyntax sass_import_get_type(const struct SassImport* import);
+
+// Setter for specific import format for the given import (force css/sass/scss or set to auto)
+void sass_import_set_syntax(struct SassImport* import, enum SassImportSyntax syntax);
+
+// Getter for original import path (as seen when parsed)
+const char* sass_import_get_imp_path(const struct SassImport* import);
+
+// Getter for resolve absolute path (after being resolved)
+const char* sass_import_get_abs_path(const struct SassImport* import);
+
+// Getter for import error message (used by custom importers).
+// If error is not `nullptr`, the import must be considered as failed.
+const char* sass_import_get_error_message(struct SassImport* import);
+
+// Setter for import error message (used by custom importers).
+// If error is not `nullptr`, the import must be considered as failed.
+void sass_import_set_error_message(struct SassImport* import, const char* msg);
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+// Create new list container for imports.
+struct SassImportList* sass_make_import_list();
+
+// Release memory of list container and all children.
+void sass_delete_import_list(struct SassImportList* list);
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+// Return number of items currently in the list.
+size_t sass_import_list_size(struct SassImportList* list);
+
+// Remove and return first item in the list (as in a fifo queue).
+struct SassImport* sass_import_list_shift(struct SassImportList* list);
+
+// Append an additional import to the list container.
+void sass_import_list_push(struct SassImportList* list, struct SassImport* import);
+
+// Append an additional import to the list container and takes ownership of the import.
+void sass_import_list_emplace(struct SassImportList* list, struct SassImport* import);
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+```
diff --git a/docs/api-importer-example.md b/docs/api-importer-example.md
index d83bf26098..bd96d43328 100644
--- a/docs/api-importer-example.md
+++ b/docs/api-importer-example.md
@@ -3,50 +3,41 @@
```C
#include
#include
-#include "sass/context.h"
+#include "sass/compiler.h"
+#include "sass/importer.h"
-Sass_Import_List sass_importer(const char* path, Sass_Importer_Entry cb, struct Sass_Compiler* comp)
+struct SassImportList* sass_importer(SassImporterLambda lambda, double priority, void* cookie)
{
// get the cookie from importer descriptor
- void* cookie = sass_importer_get_cookie(cb);
- Sass_Import_List list = sass_make_import_list(2);
+ struct SassImportList* list = sass_make_import_list();
char* local = sass_copy_c_string("local { color: green; }");
char* remote = sass_copy_c_string("remote { color: red; }");
- list[0] = sass_make_import_entry("/tmp/styles.scss", local, 0);
- list[1] = sass_make_import_entry("http://www.example.com", remote, 0);
+ sass_import_list_emplace(list, sass_make_content_import(local, "/tmp/styles.scss"));
+ sass_import_list_emplace(list, sass_make_content_import(remote, "http://www.example.com"));
return list;
}
-int main( int argc, const char* argv[] )
+int main(int argc, const char* argv[])
{
-
- // get the input file from first argument or use default
- const char* input = argc > 1 ? argv[1] : "styles.scss";
-
+ // create compiler object holding config and states
+ struct SassCompiler* compiler = sass_make_compiler();
// create the file context and get all related structs
- struct Sass_File_Context* file_ctx = sass_make_file_context(input);
- struct Sass_Context* ctx = sass_file_context_get_context(file_ctx);
- struct Sass_Options* ctx_opt = sass_context_get_options(ctx);
+ struct SassImport* import = sass_make_content_import("@import 'foobar';", 0);
+ // each compiler must have exactly one entry point
+ sass_compiler_set_entry_point(compiler, import);
+ // entry point now passed to compiler, so its reference count was increased
+ // in order to not leak memory we must release our own usage (usage after is UB)
+ sass_delete_import(import); // decrease ref-count
// allocate custom importer
- Sass_Importer_Entry c_imp =
+ struct SassImporter* importer =
sass_make_importer(sass_importer, 0, 0);
// create list for all custom importers
- Sass_Importer_List imp_list = sass_make_importer_list(1);
- // put only the importer on to the list
- sass_importer_set_list_entry(imp_list, 0, c_imp);
- // register list on to the context options
- sass_option_set_c_importers(ctx_opt, imp_list);
+ sass_compiler_add_custom_importer(compiler, importer);
// context is set up, call the compile step now
- int status = sass_compile_file_context(file_ctx);
-
- // print the result or the error to the stdout
- if (status == 0) puts(sass_context_get_output_string(ctx));
- else puts(sass_context_get_error_message(ctx));
-
+ int status = sass_compiler_execute(compiler, false);
// release allocated memory
- sass_delete_file_context(file_ctx);
-
+ sass_delete_compiler(compiler);
// exit status
return status;
@@ -56,8 +47,8 @@ int main( int argc, const char* argv[] )
Compile importer.c
```bash
-gcc -c importer.c -o importer.o
-gcc -o importer importer.o -lsass
+gcc -c importer.c -o importer.o -Iinclude
+g++ -o importer importer.o -lsass -Llib
echo "@import 'foobar';" > importer.scss
./importer importer.scss
```
@@ -65,48 +56,41 @@ echo "@import 'foobar';" > importer.scss
## Importer Behavior Examples
```C
-Sass_Import_List importer(const char* path, Sass_Importer_Entry cb, struct Sass_Compiler* comp) {
- // let LibSass handle the import request
+struct SassImportList* importer(SassImporterLambda lambda, double priority, void* cookie) {
+ // Skip this importer and try next in queue
return NULL;
}
-Sass_Import_List importer(const char* path, Sass_Importer_Entry cb, struct Sass_Compiler* comp) {
- // let LibSass handle the request
- // swallows »@import "http://…"« pass-through
- // (arguably a bug)
- Sass_Import_List list = sass_make_import_list(1);
- list[0] = sass_make_import_entry(path, 0, 0);
+struct SassImportList* importer(SassImporterLambda lambda, double priority, void* cookie) {
+ // Let LibSass load the file identified by the importer
+ // No further importers are consulted
+ struct SassImportList* list = sass_make_import_list();
+ sass_import_list_emplace(list, sass_make_file_import(path));
return list;
}
-Sass_Import_List importer(const char* path, Sass_Importer_Entry cb, struct Sass_Compiler* comp) {
- // return an error to halt execution
- Sass_Import_List list = sass_make_import_list(1);
+struct SassImportList* importer(SassImporterLambda lambda, double priority, void* cookie) {
+ // Return an error to halt execution
+ struct SassImportList* list = sass_make_import_list();
const char* message = "some error message";
- list[0] = sass_make_import_entry(path, 0, 0);
- sass_import_set_error(list[0], sass_copy_c_string(message), 0, 0);
+ struct SassImport* import = sass_make_file_import(path);
+ sass_import_set_error_message(import, sass_copy_c_string(message));
+ sass_import_list_emplace(list, import);
return list;
}
-Sass_Import_List importer(const char* path, Sass_Importer_Entry cb, struct Sass_Compiler* comp) {
- // let LibSass load the file identifed by the importer
- Sass_Import_List list = sass_make_import_list(1);
- list[0] = sass_make_import_entry("/tmp/file.scss", 0, 0);
+struct SassImportList* importer(SassImporterLambda lambda, double priority, void* cookie) {
+ // Let LibSass load the file identified by the importer
+ struct SassImportList* list = sass_make_import_list();
+ sass_import_list_emplace(list, sass_make_file_import(path));
return list;
}
-Sass_Import_List importer(const char* path, Sass_Importer_Entry cb, struct Sass_Compiler* comp) {
- // completely hide the import
- // (arguably a bug)
- Sass_Import_List list = sass_make_import_list(0);
+struct SassImportList* importer(SassImporterLambda lambda, double priority, void* cookie) {
+ // Completely hide the import
+ // No further importers are consulted
+ struct SassImportList* list = sass_make_import_list();
return list;
}
-Sass_Import_List importer(const char* path, Sass_Importer_Entry cb, struct Sass_Compiler* comp) {
- // completely hide the import
- // (arguably a bug)
- Sass_Import_List list = sass_make_import_list(1);
- list[0] = sass_make_import_entry(0, 0, 0);
- return list;
-}
```
diff --git a/docs/api-importer-internal.md b/docs/api-importer-internal.md
deleted file mode 100644
index 63d70fe757..0000000000
--- a/docs/api-importer-internal.md
+++ /dev/null
@@ -1,20 +0,0 @@
-```C
-// External import entry
-struct Sass_Import {
- char* imp_path; // path as found in the import statement
- char *abs_path; // path after importer has resolved it
- char* source;
- char* srcmap;
- // error handling
- char* error;
- size_t line;
- size_t column;
-};
-
-// Struct to hold importer callback
-struct Sass_Importer {
- Sass_Importer_Fn importer;
- double priority;
- void* cookie;
-};
-```
diff --git a/docs/api-importer.md b/docs/api-importer.md
index b6265002ee..adb4968683 100644
--- a/docs/api-importer.md
+++ b/docs/api-importer.md
@@ -1,86 +1,98 @@
-By using custom importers, Sass stylesheets can be implemented in any possible way, such as by being loaded via a remote server. Please note: this feature is experimental and is implemented differently than importers in Ruby Sass. Imports must be relative to the parent import context and therefore we need to pass this information to the importer callback. This is currently done by passing the complete import string/path of the previous import context.
-
-## Return Imports
-
-You actually have to return a list of imports, since some importers may want to import multiple files from one import statement (ie. a glob/star importer). The memory you pass with source and srcmap is taken over by LibSass and freed automatically when the import is done. You are also allowed to return `0` instead of a list, which will tell LibSass to handle the import by itself (as if no custom importer was in use).
+## LibSass custom importer C-API
+
+Note: currently custom importers are not yet implemented for `@use` and friends!
+
+The custom importer C-API allows implementors to decide how `@import` and similar
+rules (e.g. `@use`) are handled. Custom importers will we called once we try to
+resolve an import rule. Without any custom importer, LibSass will try to resolve
+the import by looking into all include directories. Custom importers will be invoked
+before this happens, if any are registered. LibSass passes the current path that
+should be imported and the resolved path to the parent import, in order for the
+custom importer to resolve relative imports to the parent style-sheet.
+
+The custom importer must return a pointer to a `SassImportList`, with which it can
+represent three different states. It can return a `nullptr`, which will let LibSass
+execute the next custom importer. It can return an empty `SassImportList`, which will
+mean that the import is consumed, but nothing is really imported. Last it can return
+one or more entries in the `SassImportList`. That list consists of `SassImport` entries,
+which can either be just rewritten paths, or also already have fully loaded content.
+
+### C-API for `SassImportList`
+
+You have to return a list of imports, since some importers may want to import multiple
+files from one import statement (ie. a glob/star importer). The memory you pass with
+source and srcmap is taken over by LibSass and freed automatically when the import is
+done. You are also allowed to return `0` or `nullptr` instead of a list, which will
+tell LibSass to handle the import by itself (as if no custom importer was in use).
+The C-API for `SassImportList` is designed like a FiFo queue (first in, first out).
+The C-API only allows to push or shift items from the list.
```C
-Sass_Import_Entry* rv = sass_make_import_list(1);
-rv[0] = sass_make_import(rel, abs, source, srcmap);
+struct SassImportList* imports = sass_make_import_list();
+sass_import_list_push(imports, sass_import_list_emplace(rel, abs, source, srcmap));
+struct SassImport* import = sass_import_list_shift(imports);
```
-Every import will then be included in LibSass. You are allowed to only return a file path without any loaded source. This way you can ie. implement rewrite rules for import paths and leave the loading part for LibSass.
+Every import will then be included in LibSass. You are allowed to only return a file path
+without any loaded source. This way you can ie. implement rewrite rules for import paths
+and leave the loading part for LibSass.
+
+Please note that LibSass doesn't use the srcmap parameter yet. It has been added to not
+deprecate the C-API once support has been implemented. It will be used to re-map the
+actual sourcemap with the provided ones.
+
+### Difference to official Sass implementation
-Please note that LibSass doesn't use the srcmap parameter yet. It has been added to not deprecate the C-API once support has been implemented. It will be used to re-map the actual sourcemap with the provided ones.
+According to the official dart-sass implementation, we should not call custom importers for
+e.g. css imports, but LibSass will always try to query registered custom importers for every
+import it encounters. In order for custom importers to stay 100% within the Sass specifications,
+it should ignore any imports whose URLs end in .css or begin with http:// or https://, or imports
+that have media queries, should always be treated as plain CSS and never passed to custom importers.
+For further details check https://github.com/sass/libsass/issues/2957 and linked issues.
+
+### Example code
+
+See [sass importer code example](api-importer-example.md).
### Basic Usage
```C
-#include "sass/functions.h"
+#include
```
## Sass Importer API
```C
-// Forward declaration
-struct Sass_Import;
-
-// Forward declaration
-struct Sass_C_Import_Descriptor;
-
-// Typedef defining the custom importer callback
-typedef struct Sass_C_Import_Descriptor (*Sass_C_Import_Callback);
-// Typedef defining the importer c function prototype
-typedef Sass_Import_Entry* (*Sass_C_Import_Fn) (const char* url, const char* prev, void* cookie);
-
-// Creators for custom importer callback (with some additional pointer)
-// The pointer is mostly used to store the callback into the actual function
-Sass_C_Import_Callback sass_make_importer (Sass_C_Import_Fn, void* cookie);
-
-// Getters for import function descriptors
-Sass_C_Import_Fn sass_import_get_function (Sass_C_Import_Callback fn);
-void* sass_import_get_cookie (Sass_C_Import_Callback fn);
-
-// Deallocator for associated memory
-void sass_delete_importer (Sass_C_Import_Callback fn);
-
-// Creator for sass custom importer return argument list
-Sass_Import_Entry* sass_make_import_list (size_t length);
-// Creator for a single import entry returned by the custom importer inside the list
-Sass_Import_Entry sass_make_import_entry (const char* path, char* source, char* srcmap);
-Sass_Import_Entry sass_make_import (const char* rel, const char* abs, char* source, char* srcmap);
-
-// set error message to abort import and to print out a message (path from existing object is used in output)
-Sass_Import_Entry sass_import_set_error(Sass_Import_Entry import, const char* message, size_t line, size_t col);
-
-// Setters to insert an entry into the import list (you may also use [] access directly)
-// Since we are dealing with pointers they should have a guaranteed and fixed size
-void sass_import_set_list_entry (Sass_Import_Entry* list, size_t idx, Sass_Import_Entry entry);
-Sass_Import_Entry sass_import_get_list_entry (Sass_Import_Entry* list, size_t idx);
-
-// Getters for import entry
-const char* sass_import_get_imp_path (Sass_Import_Entry);
-const char* sass_import_get_abs_path (Sass_Import_Entry);
-const char* sass_import_get_source (Sass_Import_Entry);
-const char* sass_import_get_srcmap (Sass_Import_Entry);
-// Explicit functions to take ownership of these items
-// The property on our struct will be reset to NULL
-char* sass_import_take_source (Sass_Import_Entry);
-char* sass_import_take_srcmap (Sass_Import_Entry);
-
-// Getters for import error entries
-size_t sass_import_get_error_line (Sass_Import_Entry);
-size_t sass_import_get_error_column (Sass_Import_Entry);
-const char* sass_import_get_error_message (Sass_Import_Entry);
-
-// Deallocator for associated memory (incl. entries)
-void sass_delete_import_list (Sass_Import_Entry*);
-// Just in case we have some stray import structs
-void sass_delete_import (Sass_Import_Entry);
-```
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
-### More links
+// Type definitions for importer functions
+typedef struct SassImportList* (*SassImporterLambda)(
+ const char* url, struct SassImporter* cb, struct SassCompiler* compiler);
-- [Sass Importer Example](api-importer-example.md)
-- [Sass Importer Internal](api-importer-internal.md)
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+// Create custom importer (with arbitrary data pointer called `cookie`)
+// The pointer is often used to store the callback into the actual binding.
+struct SassImporter* sass_make_importer(
+ SassImporterLambda lambda, double priority, void* cookie);
+
+// Deallocate the importer and release memory
+void sass_delete_importer(struct SassImporter* cb);
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+// Getter for importer lambda function (the one being actually invoked)
+SassImporterLambda sass_importer_get_lambda(struct SassImporter* cb);
+
+// Getter for importer priority (lowest priority is invoked first)
+double sass_importer_get_priority(struct SassImporter* cb);
+
+// Getter for arbitrary cookie (used by implementers to store stuff)
+void* sass_importer_get_cookie(struct SassImporter* cb);
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+```
diff --git a/docs/api-traces.md b/docs/api-traces.md
new file mode 100644
index 0000000000..4d460c3072
--- /dev/null
+++ b/docs/api-traces.md
@@ -0,0 +1,78 @@
+## LibSass C-API for stack traces
+
+API for fetching additional information about the current import/call stack.
+This is useful for custom importers, custom functions or in case of errors.
+
+### Basic Usage
+
+```C
+#include
+```
+
+### Sass stack trace related APIs
+
+```C
+/////////////////////////////////////////////////////////////////////////
+// Implementation related to struct SassTrace
+/////////////////////////////////////////////////////////////////////////
+
+// Getter for name of this trace (normally the function name or empty).
+const char* sass_trace_get_name(struct SassTrace* trace);
+
+// Getter to check if trace is from a function call (otherwise import).
+bool sass_trace_was_fncall(struct SassTrace* trace);
+
+// Getter for the SourceSpan (aka ParserState) for further details
+const struct SassSrcSpan* sass_trace_get_srcspan(struct SassTrace* trace);
+
+/////////////////////////////////////////////////////////////////////////
+// Implementation related to struct SassSrcSpan
+/////////////////////////////////////////////////////////////////////////
+
+// Getter for line position of trace (starting from 0)
+size_t sass_srcspan_get_src_ln(struct SassSrcSpan* pstate);
+
+// Getter for column position of trace (starting from 0)
+size_t sass_srcspan_get_src_col(struct SassSrcSpan* pstate);
+
+// Getter for line position of trace (starting from 1)
+size_t sass_srcspan_get_src_line(struct SassSrcSpan* pstate);
+
+// Getter for column position of trace (starting from 1)
+size_t sass_srcspan_get_src_column(struct SassSrcSpan* pstate);
+
+// Getter for line span of trace (starting from 0)
+size_t sass_srcspan_get_span_ln(struct SassSrcSpan* pstate);
+
+// Getter for column span of trace (starting from 0)
+size_t sass_srcspan_get_span_col(struct SassSrcSpan* pstate);
+
+// Getter for attached source of trace for further details
+struct SassSource* sass_srcspan_get_source(struct SassSrcSpan* pstate);
+
+/////////////////////////////////////////////////////////////////////////
+// Implementation related to struct SassSource
+/////////////////////////////////////////////////////////////////////////
+
+// Getter for absolute path this source was loaded from. This path should
+// always be absolute but there is no real hard requirement for it. Custom
+// importers may use different pattern for paths. LibSass tries to support
+// regular win/nix paths and urls. But we it also try to be agnostic here,
+// so anything a custom importer returns will be returned here.
+const char* sass_source_get_abs_path(struct SassSource* source);
+
+// Getter for import path this source was loaded from. This path should
+// be as it was found when the import was parsed. This is merely useful
+// for debugging purposes, but we keep it around anyway.
+const char* sass_source_get_imp_path(struct SassSource* source);
+
+// Getter for the loaded content attached to the source.
+const char* sass_source_get_content(struct SassSource* source);
+
+// Getter for the loaded srcmap attached to the source.
+// Note: not used yet, only here for future improvements.
+const char* sass_source_get_srcmap(struct SassSource* source);
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+```
diff --git a/docs/api-value-example.md b/docs/api-value-example.md
index 2d332110aa..e5414f3168 100644
--- a/docs/api-value-example.md
+++ b/docs/api-value-example.md
@@ -3,17 +3,17 @@
```C
#include
#include
-#include "sass/values.h"
+#include
int main( int argc, const char* argv[] )
{
// create two new sass values to be added
- union Sass_Value* string = sass_make_string("String");
- union Sass_Value* number = sass_make_number(42, "nits");
+ struct SassValue* string = sass_make_string("prefix", false);
+ struct SassValue* number = sass_make_number(42, "nits");
// invoke the add operation which returns a new sass value
- union Sass_Value* total = sass_value_op(ADD, string, number);
+ struct SassValue* total = sass_value_op(ADD, string, number);
// no further use for the two operands
sass_delete_value(string);
@@ -25,7 +25,7 @@ int main( int argc, const char* argv[] )
puts(sass_string_get_value(total));
// invoke stringification (uncompressed with precision of 5)
- union Sass_Value* result = sass_value_stringify(total, false, 5);
+ struct SassValue* result = sass_value_stringify(total, false, 5);
// no further use for the sum
sass_delete_value(total);
@@ -49,7 +49,7 @@ int main( int argc, const char* argv[] )
## Compile operation.c
```bash
-gcc -c operation.c -o operation.o
-gcc -o operation operation.o -lsass
-./operation # => String42nits
+gcc -c operation.c -o operation.o -Iinclude
+g++ -o operation operation.o -lsass -Llib
+./operation # => prefix42nits
```
diff --git a/docs/api-value-internal.md b/docs/api-value-internal.md
deleted file mode 100644
index fed4022560..0000000000
--- a/docs/api-value-internal.md
+++ /dev/null
@@ -1,76 +0,0 @@
-```C
-struct Sass_Unknown {
- enum Sass_Tag tag;
-};
-
-struct Sass_Boolean {
- enum Sass_Tag tag;
- bool value;
-};
-
-struct Sass_Number {
- enum Sass_Tag tag;
- double value;
- char* unit;
-};
-
-struct Sass_Color {
- enum Sass_Tag tag;
- double r;
- double g;
- double b;
- double a;
-};
-
-struct Sass_String {
- enum Sass_Tag tag;
- char* value;
-};
-
-struct Sass_List {
- enum Sass_Tag tag;
- enum Sass_Separator separator;
- size_t length;
- // null terminated "array"
- union Sass_Value** values;
-};
-
-struct Sass_Map {
- enum Sass_Tag tag;
- size_t length;
- struct Sass_MapPair* pairs;
-};
-
-struct Sass_Null {
- enum Sass_Tag tag;
-};
-
-struct Sass_Error {
- enum Sass_Tag tag;
- char* message;
-};
-
-struct Sass_Warning {
- enum Sass_Tag tag;
- char* message;
-};
-
-union Sass_Value {
- struct Sass_Unknown unknown;
- struct Sass_Boolean boolean;
- struct Sass_Number number;
- struct Sass_Color color;
- struct Sass_String string;
- struct Sass_List list;
- struct Sass_Map map;
- struct Sass_Null null;
- struct Sass_Error error;
- struct Sass_Warning warning;
-};
-
-struct Sass_MapPair {
- union Sass_Value* key;
- union Sass_Value* value;
-};
-```
-
diff --git a/docs/api-value.md b/docs/api-value.md
index d78625875f..aaac22a0e6 100644
--- a/docs/api-value.md
+++ b/docs/api-value.md
@@ -1,21 +1,67 @@
-`Sass_Values` are used to pass values and their types between the implementer
-and LibSass. Sass knows various different value types (including nested arrays
+## LibSass C-API for sass values
+
+`SassValue` is the base type to exchange sass values between implementors and
+LibSass. Sass knows various different value types (including nested arrays
and hash-maps). If you implement a binding to another programming language, you
-have to find a way to [marshal][1] (convert) `Sass_Values` between the target
-language and C. `Sass_Values` are currently only used by custom functions, but
-it should also be possible to use them without a compiler context.
+have to find a way to [marshal][1] (convert) a `SassValue` between the target
+language and C. `SassValue` is currently only used by custom functions, but
+it should also be able to use them without any explicit compiler.
[1]: https://en.wikipedia.org/wiki/Marshalling_%28computer_science%29
+### Handling of containers
+
+There are two `SassValue` types (list and map) that act as containers for
+nested `SassValue` objects. They have different implementations to iterate
+over the existing values. The `SassList` acts like any regular array, so you
+can get the size and access every item by offset. The `SassMap` has a specific
+iterator you need to allocate first in order to iterate over it via `next`.
+You also have to make sure to release the memory associated with the iterator.
+
+#### Iterating over `SassList`
+
+```C
+for (int i = 0; i < sass_list_get_size(list); i += 1) {
+ struct SassValue* child = sass_list_at(list, i);
+}
+```
+
+#### Iterating over `SassMap`
+
+```C
+struct SassMapIterator* it sass_map_make_iterator(map);
+while (!sass_map_iterator_exhausted(it)) {
+ struct SassValue* key = sass_map_iterator_get_key(it);
+ struct SassValue* val = sass_map_iterator_get_value(it);
+ sass_map_iterator_next(it);
+}
+sass_map_delete_iterator(it);
+```
+
+### Errors and warnings
+
+Custom functions may fail for any reason and in order to communicate this state
+back to LibSass, any custom function can return a `SassError`, which is a special
+type of `SassValue`, solely existing for this purpose. If a custom function returns
+this special type, it will throw an error further down.
+
+Note: `SassWarning` is currently handled in the same way, but warning should ultimately
+be a C-API function on its own, as we might want to emit multiple warnings, but still
+return a successful return state (we only can have one error, but many warnings).
+
+### Example code
+
+See [sass value code example](api-value-example.md).
+
### Basic Usage
```C
-#include "sass/values.h"
+#include
```
```C
-// Type for Sass values
-enum Sass_Tag {
+// Type of Sass values
+enum SassValueType {
SASS_BOOLEAN,
SASS_NUMBER,
SASS_COLOR,
@@ -24,131 +70,137 @@ enum Sass_Tag {
SASS_MAP,
SASS_NULL,
SASS_ERROR,
- SASS_WARNING
+ SASS_WARNING,
+ SASS_FUNCTION
};
-// 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
};
```
### Sass Value API
```C
-// Forward declaration
-union Sass_Value;
-
// Creator functions for all value types
-union Sass_Value* sass_make_null (void);
-union Sass_Value* sass_make_boolean (bool val);
-union Sass_Value* sass_make_string (const char* val);
-union Sass_Value* sass_make_qstring (const char* val);
-union Sass_Value* sass_make_number (double val, const char* unit);
-union Sass_Value* sass_make_color (double r, double g, double b, double a);
-union Sass_Value* sass_make_list (size_t len, enum Sass_Separator sep, bool is_bracketed);
-union Sass_Value* sass_make_map (size_t len);
-union Sass_Value* sass_make_error (const char* msg);
-union Sass_Value* sass_make_warning (const char* msg);
+struct SassValue* sass_make_null(void);
+struct SassValue* sass_make_boolean(bool val);
+struct SassValue* sass_make_string(const char* val, bool is_quoted);
+struct SassValue* sass_make_number(double val, const char* unit);
+struct SassValue* sass_make_color(double r, double g, double b, double a);
+struct SassValue* sass_make_list(enum SassSeparator sep, bool is_bracketed);
+struct SassValue* sass_make_map(void);
+struct SassValue* sass_make_error(const char* msg);
+struct SassValue* sass_make_warning(const char* msg);
// Generic destructor function for all types
-// Will release memory of all associated Sass_Values
+// Will release memory of all associated SassValue children
// Means we will delete recursively for lists and maps
-void sass_delete_value (union Sass_Value* val);
+void sass_delete_value(struct SassValue* val);
// Make a deep cloned copy of the given sass value
-union Sass_Value* sass_clone_value (const union Sass_Value* val);
-
-// Stringify a Sass_Values and also return the result as a Sass_Value (of type STRING)
-union Sass_Value* sass_value_stringify (const union Sass_Value* a, bool compressed, int precision);
+struct SassValue* sass_clone_value(struct SassValue* val);
// Execute an operation for two Sass_Values and return the result as a Sass_Value too
-union Sass_Value* sass_value_op (enum Sass_OP op, const union Sass_Value* a, const union Sass_Value* b);
+struct SassValue* 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)
+struct SassValue* 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!
-enum Sass_Tag sass_value_get_tag (const union Sass_Value* v);
+enum SassValueType sass_value_get_tag(struct SassValue* v);
// Check value to be of a specific type
// Can also be used before accessing properties!
-bool sass_value_is_null (const union Sass_Value* v);
-bool sass_value_is_number (const union Sass_Value* v);
-bool sass_value_is_string (const union Sass_Value* v);
-bool sass_value_is_boolean (const union Sass_Value* v);
-bool sass_value_is_color (const union Sass_Value* v);
-bool sass_value_is_list (const union Sass_Value* v);
-bool sass_value_is_map (const union Sass_Value* v);
-bool sass_value_is_error (const union Sass_Value* v);
-bool sass_value_is_warning (const union Sass_Value* v);
+bool sass_value_is_null(struct SassValue* v);
+bool sass_value_is_number(struct SassValue* v);
+bool sass_value_is_string(struct SassValue* v);
+bool sass_value_is_boolean(struct SassValue* v);
+bool sass_value_is_color(struct SassValue* v);
+bool sass_value_is_list(struct SassValue* v);
+bool sass_value_is_map(struct SassValue* v);
+bool sass_value_is_error(struct SassValue* v);
+bool sass_value_is_warning(struct SassValue* v);
// Getters and setters for Sass_Number
-double sass_number_get_value (const union Sass_Value* v);
-void sass_number_set_value (union Sass_Value* v, double value);
-const char* sass_number_get_unit (const union Sass_Value* v);
-void sass_number_set_unit (union Sass_Value* v, char* unit);
+double sass_number_get_value(struct SassValue* v);
+void sass_number_set_value(struct SassValue* v, double value);
+const char* sass_number_get_unit(struct SassValue* v);
+void sass_number_set_unit(struct SassValue* v, const char* unit);
+void sass_number_normalize(struct SassValue* v); // What does it do?
+void sass_number_reduce(struct SassValue* v);
// Getters and setters for Sass_String
-const char* sass_string_get_value (const union Sass_Value* v);
-void sass_string_set_value (union Sass_Value* v, char* value);
-bool sass_string_is_quoted(const union Sass_Value* v);
-void sass_string_set_quoted(union Sass_Value* v, bool quoted);
+const char* sass_string_get_value(struct SassValue* v);
+void sass_string_set_value(struct SassValue* v, char* value);
+bool sass_string_is_quoted(struct SassValue* v);
+void sass_string_set_quoted(struct SassValue* v, bool quoted);
// Getters and setters for Sass_Boolean
-bool sass_boolean_get_value (const union Sass_Value* v);
-void sass_boolean_set_value (union Sass_Value* v, bool value);
+bool sass_boolean_get_value(struct SassValue* v);
+void sass_boolean_set_value(struct SassValue* v, bool value);
// Getters and setters for Sass_Color
-double sass_color_get_r (const union Sass_Value* v);
-void sass_color_set_r (union Sass_Value* v, double r);
-double sass_color_get_g (const union Sass_Value* v);
-void sass_color_set_g (union Sass_Value* v, double g);
-double sass_color_get_b (const union Sass_Value* v);
-void sass_color_set_b (union Sass_Value* v, double b);
-double sass_color_get_a (const union Sass_Value* v);
-void sass_color_set_a (union Sass_Value* v, double a);
-
-// Getter for the number of items in list
-size_t sass_list_get_length (const union Sass_Value* v);
+double sass_color_get_r(struct SassValue* v);
+void sass_color_set_r(struct SassValue* v, double r);
+double sass_color_get_g(struct SassValue* v);
+void sass_color_set_g(struct SassValue* v, double g);
+double sass_color_get_b(struct SassValue* v);
+void sass_color_set_b(struct SassValue* v, double b);
+double sass_color_get_a(struct SassValue* v);
+void sass_color_set_a(struct SassValue* v, double a);
+
+size_t sass_list_get_size(struct SassValue* list);
+void sass_list_push(struct SassValue* list, struct SassValue* value);
+struct SassValue* sass_list_at(struct SassValue* list, size_t i);
+struct SassValue* sass_list_pop(struct SassValue* list, struct SassValue* value);
+struct SassValue* sass_list_shift(struct SassValue* list, struct SassValue* value);
+
// Getters and setters for Sass_List
-enum Sass_Separator sass_list_get_separator (const union Sass_Value* v);
-void sass_list_set_separator (union Sass_Value* v, enum Sass_Separator value);
-bool sass_list_get_is_bracketed (const union Sass_Value* v);
-void sass_list_set_is_bracketed (union Sass_Value* v, bool value);
+enum SassSeparator sass_list_get_separator(struct SassValue* v);
+void sass_list_set_separator(struct SassValue* v, enum SassSeparator separator);
+bool sass_list_get_is_bracketed(struct SassValue* v);
+void sass_list_set_is_bracketed(struct SassValue* v, bool value);
// Getters and setters for Sass_List values
-union Sass_Value* sass_list_get_value (const union Sass_Value* v, size_t i);
-void sass_list_set_value (union Sass_Value* v, size_t i, union Sass_Value* value);
+struct SassValue* sass_list_get_value(struct SassValue* v, size_t i);
+void sass_list_set_value(struct SassValue* v, size_t i, struct SassValue* value);
+
+void sass_map_set(struct SassValue* m, struct SassValue* k, struct SassValue* v);
+struct SassMapIterator* sass_map_make_iterator(struct SassValue* map);
+void sass_map_delete_iterator(struct SassMapIterator* it);
+bool sass_map_iterator_exhausted(struct SassMapIterator* it);
+struct SassValue* sass_map_iterator_get_key(struct SassMapIterator* it);
+struct SassValue* sass_map_iterator_get_value(struct SassMapIterator* it);
+void sass_map_iterator_next(struct SassMapIterator* it);
-// Getter for the number of items in map
-size_t sass_map_get_length (const union Sass_Value* v);
-// Getters and setters for Sass_Map keys and values
-union Sass_Value* sass_map_get_key (const union Sass_Value* v, size_t i);
-void sass_map_set_key (union Sass_Value* v, size_t i, union Sass_Value*);
-union Sass_Value* sass_map_get_value (const union Sass_Value* v, size_t i);
-void sass_map_set_value (union Sass_Value* v, size_t i, union Sass_Value*);
+void sass_map_set(struct SassValue* m, struct SassValue* k, struct SassValue* v);
+struct SassValue* sass_map_get(struct SassValue* m, struct SassValue* k);
// Getters and setters for Sass_Error
-char* sass_error_get_message (const union Sass_Value* v);
-void sass_error_set_message (union Sass_Value* v, char* msg);
+const char* sass_error_get_message(struct SassValue* v);
+void sass_error_set_message(struct SassValue* v, const char* msg);
// Getters and setters for Sass_Warning
-char* sass_warning_get_message (const union Sass_Value* v);
-void sass_warning_set_message (union Sass_Value* v, char* msg);
+const char* sass_warning_get_message(struct SassValue* v);
+void sass_warning_set_message(struct SassValue* v, const char* msg);
```
### More links
- [Sass Value Example](api-value-example.md)
-- [Sass Value Internal](api-value-internal.md)
diff --git a/docs/api-variable.md b/docs/api-variable.md
new file mode 100644
index 0000000000..7a81c6a8a0
--- /dev/null
+++ b/docs/api-variable.md
@@ -0,0 +1,40 @@
+## LibSass C-API for variables
+
+This API allows custom functions to access and modify existing variables.
+It is not possible to create new variables with this API, as variables are
+optimized in a way that declarations are hard baked once parsing is done.
+Therefore we can't add new variables during runtime. This API allows to
+query and set already existing variables. To define new variables you must
+use an API that is executed during the parsing phase (see plugins).
+
+### Basic Usage
+
+```C
+#include
+```
+
+### Sass run-time variable API
+
+```C
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+// Getter for lexical variable (lexical to scope where function is called).
+// Note: C-API function can only access existing variables and not create new ones!
+struct SassValue* sass_env_get_lexical (struct SassCompiler* compiler, const char* name);
+
+// Setter for lexical variable (lexical to scope where function is called).
+// Note: C-API function can only access existing variables and not create new ones!
+void sass_env_set_lexical(struct SassCompiler* compiler, const char* name, struct SassValue* value);
+
+// Getter for local variable (local only to scope where function is called).
+// Note: C-API function can only access existing variables and not create new ones!
+struct SassValue* sass_env_get_global (struct SassCompiler* compiler, const char* name);
+
+// Setter for local variable (local only to scope where function is called).
+// Note: C-API function can only access existing variables and not create new ones!
+void sass_env_set_global(struct SassCompiler* compiler, const char* name, struct SassValue* value);
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+```
diff --git a/docs/build-on-gentoo.md b/docs/build-on-gentoo.md
deleted file mode 100644
index 1e71492d1a..0000000000
--- a/docs/build-on-gentoo.md
+++ /dev/null
@@ -1,55 +0,0 @@
-Here are two ebuilds to compile LibSass and sassc on gentoo linux. If you do not know how to use these ebuilds, you should probably read the gentoo wiki page about [portage overlays](http://wiki.gentoo.org/wiki/Overlay).
-
-## www-misc/libsass/libsass-9999.ebuild
-```ebuild
-EAPI=4
-
-inherit eutils git-2 autotools
-
-DESCRIPTION="A C/C++ implementation of a Sass compiler."
-HOMEPAGE="https://sass-lang.com/"
-EGIT_PROJECT='libsass'
-EGIT_REPO_URI="https://github.com/sass/libsass.git"
-LICENSE="MIT"
-SLOT="0"
-KEYWORDS=""
-IUSE=""
-DEPEND=""
-RDEPEND="${DEPEND}"
-DEPEND="${DEPEND}"
-
-pkg_pretend() {
- # older gcc is not supported
- local major=$(gcc-major-version)
- local minor=$(gcc-minor-version)
- [[ "${MERGE_TYPE}" != "binary" && ( $major > 4 || ( $major == 4 && $minor < 5 ) ) ]] && \
- die "Sorry, but gcc earlier than 4.5 will not work for LibSass."
-}
-
-src_prepare() {
- eautoreconf
-}
-```
-
-## www-misc/sassc/sassc-9999.ebuild
-```ebuild
-EAPI=4
-
-inherit eutils git-2 autotools
-
-DESCRIPTION="Command Line Tool for LibSass."
-HOMEPAGE="https://sass-lang.com/"
-EGIT_PROJECT='sassc'
-EGIT_REPO_URI="https://github.com/sass/sassc.git"
-LICENSE="MIT"
-SLOT="0"
-KEYWORDS=""
-IUSE=""
-DEPEND="www-misc/libsass"
-RDEPEND="${DEPEND}"
-DEPEND="${DEPEND}"
-
-src_prepare() {
- eautoreconf
-}
-```
diff --git a/docs/build-on-windows.md b/docs/build-on-windows.md
index 458131909b..6aa762ad50 100644
--- a/docs/build-on-windows.md
+++ b/docs/build-on-windows.md
@@ -1,7 +1,7 @@
-We support builds via MingGW and via Visual Studio Community 2013.
+We support builds via MinGW and via Visual Studio Community 2013.
Both should be considered experimental (MinGW was better tested)!
-## Building via MingGW (makefiles)
+## Building via MinGW (makefiles)
First grab the latest [MinGW for windows][1] installer. Once it is installed, you can click on continue or open the Installation Manager via `bin\mingw-get.exe`.
@@ -24,7 +24,7 @@ As mentioned in the [MinGW Getting Started](http://www.mingw.org/wiki/Getting_St
C:\MinGW /mingw
```
-### Starting a "MingGW" console
+### Starting a "MinGW" console
Create a batch file with this content:
```bat
@@ -50,7 +50,8 @@ git clone https://github.com/sass/sass-spec.git libsass/sass-spec
### Decide for static or shared library
-`libsass` can be built and linked as a `static` or as a `shared` library. The default is `static`. To change it you can set the `BUILD` environment variable:
+`libsass` can be built and linked as a `static` or as a `shared` library.
+The default is `static`. To change it you can set the `BUILD` environment variable:
```bat
set BUILD="shared"
@@ -72,7 +73,7 @@ libsass.a libsass.dll libsass.so
mingw32-make -C libsass test_build
```
-## Building via MingGW 64bit (makefiles)
+## Building via MinGW 64bit (makefiles)
Building libass to dll on window 64bit.
+ downloads [MinGW64 for windows7 64bit](http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/4.9.2/threads-win32/seh/x86_64-4.9.2-release-win32-seh-rt_v3-rev0.7z/download) , and unzip to "C:\mingw64".
@@ -94,7 +95,7 @@ cmd
``` bash
lib/libsass.dll: $(COBJECTS) $(OBJECTS) $(RCOBJECTS)
$(MKDIR) lib
- $(CXX) -shared $(LDFLAGS) -o $@ $(COBJECTS) $(OBJECTS) $(RCOBJECTS) $(LDLIBS) -s -static -Wl,--subsystem,windows,--out-implib,lib/libsass.a
+ $(CXX) -shared $(LDFLAGS) -o $@ $(COBJECTS) $(OBJECTS) $(RCOBJECTS) $(LDLIBS) -s -static -Wl,--subsystem,windows,--out-implib,lib/libsass.dll.a
```
+ Compile the library
diff --git a/docs/build-shared-library.md b/docs/build-shared-library.md
index 3c143b46ae..83b91c10a8 100644
--- a/docs/build-shared-library.md
+++ b/docs/build-shared-library.md
@@ -1,9 +1,17 @@
-This page is mostly intended for people that want to build a system library that gets distributed via RPMs or other means. This is currently in a experimental phase, as we currently do not really guarantee any ABI forward compatibility. The C API was rewritten to make this possible in the future, but we want to wait some more time till we can call this final and stable.
+This page is mostly intended for people that want to build a system library that
+gets distributed via RPMs or other means. This is currently in a experimental
+phase, as we currently do not really guarantee any ABI forward compatibility.
+The C API was rewritten to make this possible in the future, but we want to
+wait some more time till we can call this final and stable.
Building via autotools
--
-You want to build a system library only via autotools, since it will create the proper `libtool` files to make it loadable on multiple systems. We hope this works correctly, but nobody of the `libsass` core team has much knowledge in this area. Therefore we are open for comments or improvements by people that have more experience in that matter (like package maintainers from various linux distributions).
+You want to build a system library only via autotools, since it will create the
+proper `libtool` files to make it loadable on multiple systems. We hope this works
+correctly, but nobody of the `libsass` core team has much knowledge in this area.
+Therefore we are open for comments or improvements by people that have more experience
+in that matter (like package maintainers from various linux distributions).
```bash
apt-get install autoconf libtool
@@ -23,13 +31,21 @@ This should install these files
```bash
# $ ls -la /usr/lib/libsass.*
/usr/lib/libsass.la
-/usr/lib/libsass.so -> libsass.so.0.0.9
-/usr/lib/libsass.so.0 -> libsass.so.0.0.9
-/usr/lib/libsass.so.0.0.9
+/usr/lib/libsass.so -> libsass.so.2.0.0
+/usr/lib/libsass.so.0 -> libsass.so.2.0.0
+/usr/lib/libsass.so.2.0.0
# $ 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/base.h
+/usr/include/sass/compiler.h
+/usr/include/sass/enums.h
+/usr/include/sass/error.h
+/usr/include/sass/function.h
+/usr/include/sass/fwdecl.h
+/usr/include/sass/import.h
+/usr/include/sass/importer.h
+/usr/include/sass/traces.h
/usr/include/sass/values.h
+/usr/include/sass/variable.h
+/usr/include/sass/version.h
```
diff --git a/docs/build-with-autotools.md b/docs/build-with-autotools.md
index a48ed18aa2..bc1e3f7a67 100644
--- a/docs/build-with-autotools.md
+++ b/docs/build-with-autotools.md
@@ -1,4 +1,5 @@
### Get the sources
+
```bash
# using git is preferred
git clone https://github.com/sass/libsass.git
@@ -9,7 +10,8 @@ git clone https://github.com/sass/sass-spec.git libsass/sass-spec
### Prerequisites
-In order to run autotools you need a few tools installed on your system.
+In order to run autotools you need a few items installed on your system.
+
```bash
yum install automake libtool # RedHat Linux
emerge -a automake libtool # Gentoo Linux
@@ -18,6 +20,7 @@ pkgin install automake libtool # SmartOS
### Create configure script
+
```bash
cd libsass
autoreconf --force --install
@@ -25,6 +28,7 @@ cd ..
```
### Create custom makefiles
+
```bash
cd libsass
./configure \
@@ -35,18 +39,25 @@ cd ..
```
### Build the library
+
```bash
make -C libsass -j5
```
### Install the library
-The library will be installed to the location given as `prefix` to `configure`. This is standard behavior for autotools and not `libsass` specific.
+
+The library will be installed to the location given as `prefix` to `configure`.
+This is standard behavior for autotools and not `libsass` specific.
+
```bash
make -C libsass -j5 install
```
### Configure options
-The `configure` script is created by autotools. To get an overview of available options you can call `./configure --help`. When you execute this script, it will create specific makefiles, which you then use via the regular make command.
+
+The `configure` script is created by autotools. To get an overview of available
+options you can call `./configure --help`. When you execute this script, it will
+create specific makefiles, which you then use via the regular make command.
There are some `libsass` specific options:
diff --git a/docs/build-with-makefiles.md b/docs/build-with-makefiles.md
index 7ae2e33d62..70167e5719 100644
--- a/docs/build-with-makefiles.md
+++ b/docs/build-with-makefiles.md
@@ -1,4 +1,5 @@
### Get the sources
+
```bash
# using git is preferred
git clone https://github.com/sass/libsass.git
@@ -9,7 +10,8 @@ git clone https://github.com/sass/sass-spec.git libsass/sass-spec
### Decide for static or shared library
-`libsass` can be built and linked as a `static` or as a `shared` library. The default is `static`. To change it you can set the `BUILD` environment variable:
+`libsass` can be built and linked as a `static` or as a `shared` library. The
+default is `static`. To change it you can set the `BUILD` environment variable:
```bash
export BUILD="shared"
@@ -38,6 +40,7 @@ We recommend to use [autotools to install](build-with-autotools.md) libsass onto
system, since that brings all the benefits of using libtools as the main install method.
If you still want to install libsass via the makefile, you need to make sure that gnu
`install` utility (or compatible) is installed on your system.
+
```bash
yum install coreutils # RedHat Linux
emerge -a coreutils # Gentoo Linux
@@ -49,7 +52,6 @@ You can set the install location by setting `PREFIX`
PREFIX="/opt/local" make install
```
-
### Compling sassc
```bash
@@ -62,7 +64,7 @@ make -C libsass -j5 sassc
### Run the spec test-suite
```bash
-# needs ruby available
-# also gem install minitest
+# needs ruby available, plus
+# $ gem install hrx minitest
make -C libsass -j5 test_build
```
diff --git a/docs/build-with-mingw.md b/docs/build-with-mingw.md
index 416507f3c6..86da86934e 100644
--- a/docs/build-with-mingw.md
+++ b/docs/build-with-mingw.md
@@ -1,27 +1,36 @@
-## Building LibSass with MingGW (makefiles)
+## Building LibSass with MinGW (makefiles)
-First grab the latest [MinGW for windows][1] installer. Once it is installed, you can click on continue or open the Installation Manager via `bin\mingw-get.exe`.
+First grab the latest [MinGW for windows][1] installer. Once it is installed, you can click
+on continue or open the Installation Manager via `bin\mingw-get.exe`. Alternatively you may
+install MinGW via [Chocolatey][5] or use the [MSYS2][6] or [Cygwin][7] compiler toolchain.
+There should be plenty of information on the internet to setup a C++ tool-chain on windows.
-You need to have the following components installed:
+If you use the MinGW You need to have the following components installed:

-Next we need to install [git for windows][2]. You probably want to check the option to add it to the global path, but you do not need to install the unix tools.
+Next we need to install [git for windows][2]. You probably want to check the option to add
+it to the global path, but you do not need to install the unix tools.
-If you want to run the spec test-suite you also need [ruby][3] and a few gems available. Grab the [latest installer][3] and make sure to add it the global path. Then install the missing gems:
+If you want to run the spec test-suite you also need [ruby][3] and a few gems available. Grab the
+[latest installer][3] and make sure to add it the global path. Then install the missing gems:
```bash
+gem install hrx
gem install minitest
```
+Note: the information below might be outdated by now (2021).
+
### Mount the mingw root directory
-As mentioned in the [MinGW Getting Started](http://www.mingw.org/wiki/Getting_Started#toc5) guide, you should edit `C:\MinGW\msys\1.0\etc\fstab` to contain the following line:
+As mentioned in the [MinGW Getting Started](http://www.mingw.org/wiki/Getting_Started#toc5) guide,
+you should edit `C:\MinGW\msys\1.0\etc\fstab` to contain the following line:
```
C:\MinGW /mingw
```
-### Starting a "MingGW" console
+### Starting a "MinGW" console
Create a batch file with this content:
```bat
@@ -69,10 +78,10 @@ libsass.a libsass.dll libsass.so
mingw32-make -C libsass test_build
```
-## Building via MingGW 64bit (makefiles)
+## Building via MinGW 64bit (makefiles)
Building libass to dll on window 64bit.
-Download [MinGW64 for windows7 64bit](http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/4.9.2/threads-win32/seh/x86_64-4.9.2-release-win32-seh-rt_v3-rev0.7z/download) and unzip to "C:\mingw64".
+Download [MinGW64 for windows7 64bit][4] and unzip to "C:\mingw64".
Create a batch file with this content:
@@ -91,7 +100,7 @@ By default, mingw64 dll will depends on "mingwm10.
``` bash
lib/libsass.dll: $(COBJECTS) $(OBJECTS) $(RCOBJECTS)
$(MKDIR) lib
- $(CXX) -shared $(LDFLAGS) -o $@ $(COBJECTS) $(OBJECTS) $(RCOBJECTS) $(LDLIBS) -s -static -Wl,--subsystem,windows,--out-implib,lib/libsass.a
+ $(CXX) -shared $(LDFLAGS) -o $@ $(COBJECTS) $(OBJECTS) $(RCOBJECTS) $(LDLIBS) -s -static -Wl,--subsystem,windows,--out-implib,lib/libsass.dll.a
```
Compile the library
@@ -105,3 +114,7 @@ By the way, if you are using java jna, [JNAerator](http://jnaerator.googlecode.c
[1]: http://sourceforge.net/projects/mingw/files/latest/download?source=files
[2]: https://msysgit.github.io/
[3]: http://rubyinstaller.org/
+[4]: http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/4.9.2/threads-win32/seh/x86_64-4.9.2-release-win32-seh-rt_v3-rev0.7z/download
+[5]: https://community.chocolatey.org/packages/mingw
+[6]: https://www.msys2.org/
+[7]: https://www.cygwin.com/
diff --git a/docs/build-with-visual-studio.md b/docs/build-with-visual-studio.md
index 275b917b82..af6a8d09d4 100644
--- a/docs/build-with-visual-studio.md
+++ b/docs/build-with-visual-studio.md
@@ -1,90 +1,57 @@
## Building LibSass with Visual Studio
-### Requirements:
+The minimum requirement to build LibSass with Visual Studio is currently
+version 15.0 (Visual Studio 2017). Simply download and install [Visual
+Studio from Microsoft](https://visualstudio.microsoft.com/downloads/).
+The Community Edition is even free for open-source projects.
-The minimum requirement to build LibSass with Visual Studio is "Visual Studio 2013 Express for Desktop".
+Additionally, it is recommended to have `git` installed and available
+via `PATH` env-variable, in order to deduce the `libsass` version info.
+If `git` is not available, the LibSass version will be set to `[NA]`.
-Additionally, it is recommended to have `git` installed and available in `PATH`, so to deduce the `libsass` version information. For instance, if GitHub for Windows (https://windows.github.com/) is installed, the `PATH` will have an entry resembling: `X:\Users\\AppData\Local\GitHub\PortableGit_\cmd\` (where `X` is the drive letter of system drive). If `git` is not available, inquiring the LibSass version will result in `[NA]`.
+Once installed simply load `win/libsass.sln` file into Visual Studio.
+Then build (Ctrl+Shift+B) any configuration you'd like.
-### Build Steps:
+[1]: https://visualstudio.microsoft.com/downloads/
-#### From Visual Studio:
+### Building on command prompt
-On opening the `win\libsass.sln` solution and build (Ctrl+Shift+B) to build `libsass.dll`.
+In order to build with MSVC on the command line, you either need to bring
+`msbuild.exe` into the common `PATH` folders or reference it via absolute path.
+The easiest way is to open the `VS201X Tools Command Prompt`, which should be
+a shortcuts installed alongside with Visual Studio.
-To Build LibSass as a static Library, it is recommended to set an environment variable `LIBSASS_STATIC_LIB` before launching the project:
-
-```cmd
-cd path\to\libsass
-SET LIBSASS_STATIC_LIB=1
-::
-:: or in PowerShell:
-:: $env:LIBSASS_STATIC_LIB=1
-::
-win\libsass.sln
-```
-
-Visual Studio will form the filtered source tree as shown below:
-
-
-
-`Header Files` contains the .h and .hpp files, while `Source Files` covers `.c` and `.cpp`. The other used headers/sources will appear under `External Dependencies`.
-
-If there is a LibSass code file appearing under External Dependencies, it can be changed by altering the `win\libsass.vcxproj.filters` file or dragging in Solution Explorer.
-
-#### From Command Prompt:
-
-Notice that in the following commands:
+It is normally located at `"%ProgramFiles(x86)%\MSBuild\15.0\Bin\MSBuild"`
* If the platform is 32-bit Windows, replace `ProgramFiles(x86)` with `ProgramFiles`.
-* To build with Visual Studio 2015, replace `12.0` with `14.0` in the aforementioned command.
+* To build with Visual Studio 2019, replace `15.0` with `16.0` in the commands.
-Open a command prompt:
+Once the command is available you can build any configuration you need:
-To build dynamic/shared library (`libsass.dll`):
-
-```cmd
-:: debug build:
-"%ProgramFiles(x86)%\MSBuild\12.0\Bin\MSBuild" win\libsass.sln
-
-:: release build:
-"%ProgramFiles(x86)%\MSBuild\12.0\Bin\MSBuild" win\libsass.sln ^
-/p:Configuration=Release
-```
-
-To build static library (`libsass.lib`):
-
-```cmd
-:: debug build:
-"%ProgramFiles(x86)%\MSBuild\12.0\Bin\MSBuild" win\libsass.sln ^
-/p:LIBSASS_STATIC_LIB=1
-
-:: release build:
-"%ProgramFiles(x86)%\MSBuild\12.0\Bin\MSBuild" win\libsass.sln ^
-/p:LIBSASS_STATIC_LIB=1 /p:Configuration=Release
+```bash
+MSBuild win\libsass.sln /p:Platform="x64" /p:Configuration="Release Shared" -t:Clean;Build
+MSBuild win\libsass.sln /p:Platform="x86" /p:Configuration="Debug Static" -t:Clean;Build
```
-#### From PowerShell:
+The results can be found inside the `build` directory.
-To build dynamic/shared library (`libsass.dll`):
+### Training LibSass for better performance
-```powershell
-# debug build:
-&"${env:ProgramFiles(x86)}\MSBuild\12.0\Bin\MSBuild" win\libsass.sln
+Visual Studio offers the possibility to train code via Profile Guided Optimizations.
+In order to achieve this we need to first create an "instrumented" build. This build
+will then generate statistics when being executed. Once enough data is generated,
+the code is linked once more to create the final optimized version. You can expect
+to get around 10% to 15% free performance.
-# release build:
-&"${env:ProgramFiles(x86)}\MSBuild\12.0\Bin\MSBuild" win\libsass.sln `
-/p:Configuration=Release
+```bash
+# Build an instrumented version to gather statistics for later optimization
+MSBuild libsass.sln /p:Platform="x64" /p:Configuration="Release Shared" /p:PGO="Instrument"
+# Run the trainer against some heavy sass benchmark code
+# You may need to change into a different directory
+..\build\x86\Release\Shared\trainer bench.scss 1>nul
+# Build the final optimized version with the gathered profile statistics
+MSBuild libsass.sln /p:Platform="x64" /p:Configuration="Release Shared" /p:PGO="Instrument"
```
-To build static library (`libsass.lib`):
+See [train.bat](win/train.bat) for a full example.
-```powershell
-# build:
-&"${env:ProgramFiles(x86)}\MSBuild\12.0\Bin\MSBuild" win\libsass.sln `
-/p:LIBSASS_STATIC_LIB=1
-
-# release build:
-&"${env:ProgramFiles(x86)}\MSBuild\12.0\Bin\MSBuild" win\libsass.sln `
-/p:LIBSASS_STATIC_LIB=1 /p:Configuration=Release
-```
diff --git a/docs/build.md b/docs/build.md
index 138ff1d8a4..fbbf437646 100644
--- a/docs/build.md
+++ b/docs/build.md
@@ -1,22 +1,39 @@
-`libsass` is only a library and does not do much on its own. You need an implementation that you can use from the [command line][6]. Or some [bindings|Implementations][9] to use it within your favorite programming language. You should be able to get [`sassc`][6] running by following the instructions in this guide.
+## Building libsass from source
-Before starting, see [setup dev environment](setup-environment.md).
+LibSass is only a library and does not do much on its own, you'll need an additional
+piece to tell LibSass what to do actually, called the implementor. The most basic
+implementor is [`sassc`][6], as a basic command line interface (CLI). LibSass can
+either be compiled as a static or shared library, and provides a [functional API][12]
+to its consumer. Therefore it can be utilized to drive all kind of different
+applications (CLI utility, bindings to other languages or even in browsers).
-Building on different Operating Systems
---
+This guide will try to follow you through the steps to get [`sassc`][6] running.
-We try to keep the code as OS independent and standard compliant as possible. Reading files from the file-system has some OS depending code, but will ultimately fall back to a posix compatible implementation. We do use some `C++11` features, but are so far only committed to use `unordered_map`. This means you will need a pretty recent compiler on most systems (gcc 4.5 seems to be the minimum).
+You need a working C++ compiler (e.g. gcc 4.8 or newer). If you are new to C++,
+please consult the internet how to get a working compiler toolchain running on your
+operating system, or see our guide to [setup dev environment](setup-environment.md).
+
+## Building on different Operating Systems
+
+We try to keep the LibSass as OS independent and standard compliant as possible.
+Reading files from the file-system has some OS depending code, but will ultimately
+fall back to a posix compatible implementation. We do use newer `C++11` features,
+meaning you will need a recent compiler (gcc 4.7 being the current minimum).
### Building on Linux (and other *nix flavors)
-Linux is the main target for `libsass` and we support two ways to build `libsass` here. The old plain makefiles should still work on most systems (including MinGW), while the autotools build is preferred if you want to create a [system library] (experimental).
+Linux is the main target for `libsass` and we support two ways to build `libsass` here.
+The old plain makefiles should still work on most systems (including MinGW), while the
+autotools build is preferred if you want to create a [system library].
- [Building with makefiles][1]
- [Building with autotools][2]
-### Building on Windows (experimental)
+### Building on Windows (mileage may vary)
-Windows build support was added very recently and should be considered experimental. Credits go to @darrenkopp and @am11 for their work on getting `libsass` and `sassc` to compile with visual studio!
+On windows you can either compile LibSass via MSVC or a posix compatible toolchain
+like MinGW, MSYS2 or Cygwin. It should always compile fine with the latest compiler
+toolchain provided by [Strawberry perl](https://strawberryperl.com/).
- [Building with MinGW][3]
- [Building with Visual Studio][11]
@@ -29,26 +46,12 @@ Works the same as on linux, but you can also install LibSass via `homebrew`.
### Building a system library (experimental)
-Since `libsass` is a library, it makes sense to install it as a shared library on your system. On linux this means creating a `.so` library via autotools. This should work pretty well already, but we are not yet committed to keep the ABI 100% stable. This should be the case once we increase the version number for the library to 1.0.0 or higher. On Windows you should be able get a `dll` by creating a shared build with MinGW. There is currently no target in the MSVC project files to do this.
+Since `libsass` is a library, it makes sense to install it as a system-wide shared
+library. On linux this means creating versioned `.so` library via autotools.
- [Building shared system library][4]
-### Building from vcpkg
-
-The libsass port in [vcpkg][12] is kept up to date by Microsoft team members and community contributors. You can download and install libsass using the vcpkg dependency manager:
-
-```bash
-git clone https://github.com/Microsoft/vcpkg.git
-cd vcpkg
-./bootstrap-vcpkg.sh # ./bootstrap-vcpkg.bat for Windows
-./vcpkg integrate install
-./vcpkg install libsass
-```
-
-If the version is out of date, please [create an issue or pull request][12] on the vcpkg repository.
-
-Compiling with clang instead of gcc
---
+#### Compiling with clang instead of gcc
To use clang you just need to set the appropriate environment variables:
@@ -57,29 +60,37 @@ export CC=/usr/bin/clang
export CXX=/usr/bin/clang++
```
-Running the spec test-suite
---
+#### Running the spec test-suite
+
+We constantly and automatically test `libsass` against the official [spec test-suite][5].
+To do this we need to have a test-runner (which is written in ruby) and a command-line
+tool ([`sassc`][6]) to run the tests. Therefore we need to additionally compile `sassc`.
+To do this, the build files of all three projects need to work together.
-We constantly and automatically test `libsass` against the official [spec test-suite][5]. To do this we need to have a test-runner (which is written in ruby) and a command-line tool ([`sassc`][6]) to run the tests. Therefore we need to additionally compile `sassc`. To do this, the build files of all three projects need to work together. This may not have the same quality for all build flavors. You definitely need to have ruby (2.1?) installed (version 1.9 seems to cause problems at least on windows). You also need some gems installed:
+You also need some ruby gems installed:
```bash
ruby -v
+gem install hrx
gem install minitest
# should be optional
gem install minitap
```
-Including the LibSass version
---
+#### Including the LibSass version
-There is a function in `libsass` to query the current version. This has to be defined at compile time. We use a C macro for this, which can be defined by calling `g++ -DLIBSASS_VERSION="\"x.y.z.\""`. The two quotes are necessary, since it needs to end up as a valid C string. Normally you do not need to do anything if you use the makefiles or autotools. They will try to fetch the version via git directly. If you only have the sources without the git repo, you can pass the version as an environment variable to `make` or `configure`:
+There is a function in `libsass` to query the current version. This has to be defined at compile time.
+We use a C macro for this, which can be defined by calling e.g. `g++ -DLIBSASS_VERSION="\"x.y.z.\""`.
+The two quotes are necessary, since it needs to end up as a valid C string. Normally you do not
+need to do anything if you use the makefiles or autotools. They will try to fetch the version
+either via an optional VERSION file or via git directly. If you only have the sources without
+the git repo, you can also pass the version as an environment variable to `make` or `configure`:
```
export LIBSASS_VERSION="x.y.z."
```
-Continuous Integration
---
+#### Continuous Integration
We use two CI services to automatically test all commits against the latest [spec test-suite][5].
@@ -88,15 +99,10 @@ We use two CI services to automatically test all commits against the latest [spe
- [LibSass on AppVeyor (windows)][8]
[](https://ci.appveyor.com/project/sass/libsass/branch/master)
-Why not using CMake?
---
-
-There were some efforts to get `libsass` to compile with CMake, which should make it easier to create build files for linux and windows. Unfortunately this was not completed. But we are certainly open for PRs!
-
-Miscellaneous
---
+#### Why not using CMake (or any other tool)?
-- [Ebuilds for Gentoo Linux](build-on-gentoo.md)
+There were some efforts to get `libsass` to compile with CMake, which should make it easier to
+create build files for linux and windows. Unfortunately this was not completed. But we are certainly open for PRs!
[1]: build-with-makefiles.md
[2]: build-with-autotools.md
@@ -109,4 +115,4 @@ Miscellaneous
[9]: implementations.md
[10]: build-on-darwin.md
[11]: build-with-visual-studio.md
-[12]: https://github.com/Microsoft/vcpkg
+[12]: api-doc.md
diff --git a/docs/contributing.md b/docs/contributing.md
deleted file mode 100644
index 4a2d470ef1..0000000000
--- a/docs/contributing.md
+++ /dev/null
@@ -1,17 +0,0 @@
-First of all, welcome! Thanks for even reading this page. If you're here, you're probably wondering what you can do to help make the LibSass project even more awesome. And, even having that feeling means you are awesome!
-
-## I'm a programmer
-
-Awesome! We need your help. The best thing to do is go find issues that are tagged with both "bug" and "test written". We do spec driven development here and these issues have a test that's written already in the sass-spec project. Go find the test by going to sass-spec/spec/LibSass-todo-issues/issue_XXX/ where XXX is the issue number. Write the code, and compile, and then issue a pull request referencing the issue. We'll quickly verify it and get it merged in!
-
-To get your dev environment setup, check out our article on [Setup-Dev-Environment](setup-environment.md).
-
-## I'm not a backend programmer
-
-COOL! We also need your help. Doing [Issue-Triage](triage.md) is a big deal and something we need constant help with. That means helping to verify issues, write tests for them, and make sure they are getting fixed. It's being part of the smiling face of the project.
-
-Also, we need help with the Sass-Spec project itself. Just people to organize, refactor, and understand the tests in there.
-
-## I don't know what a computer is?
-
-Hmm.... well, it's the thing you are looking at right now. Ummm... check out training courses! Then, come back and join us!
diff --git a/docs/custom-functions-internal.md b/docs/custom-functions-internal.md
deleted file mode 100644
index 86784333b4..0000000000
--- a/docs/custom-functions-internal.md
+++ /dev/null
@@ -1,122 +0,0 @@
-# Developer Documentation
-
-Custom functions are internally represented by `struct Sass_C_Function_Descriptor`.
-
-## Sass_C_Function_Descriptor
-
-```C
-struct Sass_C_Function_Descriptor {
- const char* signature;
- Sass_C_Function function;
- void* cookie;
-};
-```
-
-- `signature`: The function declaration, like `foo($bar, $baz:1)`
-- `function`: Reference to the C function callback
-- `cookie`: any pointer you want to attach
-
-### signature
-
-The signature defines how the function can be invoked. It also declares which arguments are required and which are optional. Required arguments will be enforced by LibSass and a Sass error is thrown in the event a call as missing an argument. Optional arguments only need to be present when you want to overwrite the default value.
-
- foo($bar, $baz: 2)
-
-In this example, `$bar` is required and will error if not passed. `$baz` is optional and the default value of it is 2. A call like `foo(10)` is therefore equal to `foo(10, 2)`, while `foo()` will produce an error.
-
-### function
-
-The callback function needs to be of the following form:
-
-```C
-union Sass_Value* call_sass_function(
- const union Sass_Value* s_args,
- void* cookie
-) {
- return sass_clone_value(s_args);
-}
-```
-
-### cookie
-
-The cookie can hold any pointer you want. In the `perl-libsass` implementation it holds the structure with the reference of the actual registered callback into the perl interpreter. Before that call `perl-libsass` will convert all `Sass_Values` to corresponding perl data types (so they can be used natively inside the perl interpreter). The callback can also return a `Sass_Value`. In `perl-libsass` the actual function returns a perl value, which has to be converted before `libsass` can work with it again!
-
-## Sass_Values
-
-```C
-// allocate memory (copies passed strings)
-union Sass_Value* sass_make_null (void);
-union Sass_Value* sass_make_boolean (bool val);
-union Sass_Value* sass_make_string (const char* val);
-union Sass_Value* sass_make_qstring (const char* val);
-union Sass_Value* sass_make_number (double val, const char* unit);
-union Sass_Value* sass_make_color (double r, double g, double b, double a);
-union Sass_Value* sass_make_list (size_t len, enum Sass_Separator sep, bool is_bracketed);
-union Sass_Value* sass_make_map (size_t len);
-union Sass_Value* sass_make_error (const char* msg);
-union Sass_Value* sass_make_warning (const char* msg);
-
-// Make a deep cloned copy of the given sass value
-union Sass_Value* sass_clone_value (const union Sass_Value* val);
-
-// deallocate memory (incl. all copied memory)
-void sass_delete_value (const union Sass_Value* val);
-```
-
-## Example main.c
-
-```C
-#include
-#include
-#include "sass/context.h"
-
-union Sass_Value* call_fn_foo(const union Sass_Value* s_args, void* cookie)
-{
- // we actually abuse the void* to store an "int"
- return sass_make_number((size_t)cookie, "px");
-}
-
-int main( int argc, const char* argv[] )
-{
-
- // get the input file from first argument or use default
- const char* input = argc > 1 ? argv[1] : "styles.scss";
-
- // create the file context and get all related structs
- struct Sass_File_Context* file_ctx = sass_make_file_context(input);
- struct Sass_Context* ctx = sass_file_context_get_context(file_ctx);
- struct Sass_Options* ctx_opt = sass_context_get_options(ctx);
-
- // allocate a custom function caller
- Sass_C_Function_Callback fn_foo =
- sass_make_function("foo()", call_fn_foo, (void*)42);
-
- // create list of all custom functions
- Sass_C_Function_List fn_list = sass_make_function_list(1);
- sass_function_set_list_entry(fn_list, 0, fn_foo);
- sass_option_set_c_functions(ctx_opt, fn_list);
-
- // context is set up, call the compile step now
- int status = sass_compile_file_context(file_ctx);
-
- // print the result or the error to the stdout
- if (status == 0) puts(sass_context_get_output_string(ctx));
- else puts(sass_context_get_error_message(ctx));
-
- // release allocated memory
- sass_delete_file_context(file_ctx);
-
- // exit status
- return status;
-
-}
-```
-
-## Compile main.c
-
-```bash
-gcc -c main.c -o main.o
-gcc -o sample main.o -lsass
-echo "foo { margin: foo(); }" > foo.scss
-./sample foo.scss => "foo { margin: 42px }"
-```
diff --git a/docs/allocator.md b/docs/dev-allocator.md
similarity index 100%
rename from docs/allocator.md
rename to docs/dev-allocator.md
diff --git a/docs/dev-ast-memory.md b/docs/dev-ast-memory.md
index af872a89d0..1b1c944237 100644
--- a/docs/dev-ast-memory.md
+++ b/docs/dev-ast-memory.md
@@ -5,7 +5,6 @@ by Boost or C++11. Implementation is a bit less modular since
it was not needed. Various compile time debug options are
available if you need to debug memory life-cycles.
-
## Memory Classes
### SharedObj
@@ -64,7 +63,6 @@ when the reference counted object goes out of scope, it will not
free the attached memory. You are now again in charge of freeing
the memory (just assign it to a reference counted object again).
-
## Circular references
Reference counted memory implementations are prone to circular references.
@@ -80,7 +78,6 @@ complete object clones to these members. If you know the objects lifetime
is longer than the reference you create, you can also just store the raw
pointer. Once needed this could be solved with weak pointers.
-
## Addressing the invalid covariant return types problems
If you are not familiar with the mentioned problem, you may want
@@ -220,4 +217,4 @@ profound advantages:
As said above, this is not thread safe currently. But we don't need
this ATM anyway. And I guess we probably never will share AST Nodes
-across different threads.
\ No newline at end of file
+across different threads.
diff --git a/docs/dev-env-stacks.md b/docs/dev-env-stacks.md
new file mode 100644
index 0000000000..cb1fecec03
--- /dev/null
+++ b/docs/dev-env-stacks.md
@@ -0,0 +1,223 @@
+# How LibSass handles variables, functions and mixins
+
+This document is intended for developers of LibSass only and are of no use
+for implementers. It documents how variable stacks are implemented.
+
+## Foreword
+
+LibSass uses an optimized stack approach similar to how C compilers have always
+done it, by using a growable stack where we can push and pop items. Unfortunately
+Sass has proven to be a bit more dynamic than static optimizers like, therefore we
+had to adopt the principle a little to accommodate the edge-cases due to this.
+
+There are three different kind of entities on the stack during runtime, namely
+variables, functions and mixins. Each has its own dedicated stack to optimize
+the lookups. In this doc we will often only cover one case, but it should be
+applicable to any other stack object (with some small differences). Variables
+are the most complicated ones, as functions and mixins can only be declared
+on the root scope, so loops or functions don't need to be considered for them.
+
+Also for regular sass code and style-rules we wouldn't need this setup, but
+it becomes essential to correctly support mixins and functions, since those
+can be called recursively. It is also vital for loops, like `@for` or `@each`.
+
+## Overview
+
+The whole process is split into two main phases. In order to correctly support
+`@import` we had to introduce the preloader phase, where all `@use`, `@forward` and
+`@import` rules are loaded first, before any evaluation happens. This ensures that
+we know all entities before the evaluation phase in order to correctly setup
+all stack frames before populating them.
+
+### Parser/EnvFrame phase
+
+During parsing every potential scope block creates an `EnvFrame`, which is
+stored at the corresponding ast-node (e.g. on a `StyleRule`). The `EnvFrame`
+is designed as a RAII stack object. It adds itself to the frame-stack on
+creation and removes itself once it goes out of scope. Additionally it
+creates an `EnvRefs` instance on the heap, which is later used by the
+compile/evaluation phase.
+
+### Compiler/EnvScope phase
+
+The `EnvScope` is similar to the `EnvFrame`, as it is also designed to be a RAII
+stack object. On creation it will increase the stack for each entity and update
+the corresponding offset pointers and reverts it when it goes out of scope.
+
+### EnvRefs heap object
+
+The `EnvRefs` object is the main object holding all the information about a
+block scope. It mainly holds three (flat) maps, one for every entity type.
+These maps are used to resolve a name to an integer offset. Whenever a new
+entity (e.g. variable assignment), the item is added to the map if it does
+not already exist there and the offset is simply increased (size of the map).
+
+### EnvRoot object
+
+The `EnvRoot` is the main object where entities are stored. It mainly holds
+two stack vectors for every entity type. The actual stack vector and an
+additional vector holding the previous stack size (or offset position).
+Further it holds on to all created `EnvRefs` and all built-in entities.
+
+### Frame offset pointers
+
+Every `EnvRefs` object get a unique number, increasing from 0 (which is
+reserved for the root scope block). The `EnvRoot` objects has a vector
+containing all `EnvRefs` which should correspond to that index offset.
+
+## Basic example
+
+Let's assume we have the following scss code:
+
+```scss
+$a: a;
+b {
+ $a: b;
+}
+```
+
+### Parsing phase
+
+The parser will first initialize the `EnvRoot` with the root `EnvRefs`.
+First it will parse the top variable assignment, which will create a new
+entry in the variable map of the `EnvRefs` heap object.
+
+It will then parse the `StyleRule` and create a `EnvFrame` (which will also
+create and register a new `EnvRefs` heap object). It will then parse the inner
+assignment and create a new entry in the new `EnvRefs` of the `StyleRule`.
+
+### Evaluation phase
+
+First the compiler will create an `EnvScope` stack object, which will increase
+the stack size of `EnvRoot` accordingly. In this case it will increase the size
+of `varStack` by one to accommodate the single local variable. Note that the
+variable object itself is still undefined at this point, but the slot on the
+stack exists now. The `EnvScope` will also remember that it has to decrease
+that stack vector by one, once it goes out of scope.
+
+On the assignment the compiler knows that variable `$a` can be found at the
+local offset `0` (as stored within the `EnvRefs` map). Now it only needs to
+add the current `EnvRefs` position on the `varStack` to get the absolute
+address of the requested variable.
+
+
+
+ when it sees `b`, it will
+create and assign a new `EnvFrame` with the `StyleRule`. Each `EnvRefs`
+will have one Variable `$a` with the offset `0`. On runtime the compiler will
+first evaluate the top assignment rule, thus assigning the string `a` to the
+variable at offset `0` at the current active scope (root). Then it evaluates
+the ruleset and creates a new `EnvScope`, which will push new instances onto
+the env-stack for all previously parsed entities (one variable in this case).
+
+We now have two variables on the actual env-scope with the inner still undefined.
+
+
+This will allocate two independent variables on the stack. For easier reference
+we can think of them as variable 0 and variable 1. So let's see what happens if
+we introduce some VariableExpressions:
+
+```scss
+$a: 1;
+b {
+ a0: $a;
+ $a: 2;
+ a1: $a;
+}
+c {
+ a: $a;
+}
+```
+
+As you may have guesses, the `a0` expression will reference variable 0 and the
+`a1` expression will reference variable 1, while the last one will reference
+variable 0 again. Given this easy example this might seem overengineered, but
+let's see what happens if we introduce a loop:
+
+```scss
+$a: 1;
+b {
+ @for $x from 1 through 2 {
+ a0: $a;
+ $a: 2;
+ a1: $a;
+ }
+}
+c {
+ a: $a;
+}
+```
+
+Here I want to concentrate on `a0`. In most programing languages, `a0: $a` would
+always point to variable 0, but in Sass this is more dynamic. It will actually
+reference variable 0 on the first run, and variable 1 on consecutive runs.
+
+## What is an EnvFrame and EnvRef
+
+Whenever we encounter a new scope while parsing, we will create a new EnvFrame.
+Every EnvFrame (often also just called idxs) knows the variables, functions and
+mixins that are declared within that scope. Each entity is simply referenced by
+it's integer offset (first variable, second variable and so on). Each frame is
+stored as long as the context/compiler lives. In order to find functions, each
+frame keeps a hash-map to get the local offset for an entity name (e.g. varIdxs).
+An EnvRef is just a struct with the env-frame address and the local entity offset.
+
+## Where are entities actually stored during runtime
+
+The `EnvRoot` has a growable stack for each entity type. Whenever we evaluate
+a lexical scope, we will push the entities to the stack to bring them live.
+By doing this, we also update the current pointer for the given env-frame to
+point to the correct position within that stack. Let's see how this works:
+
+```scss
+$a: 1;
+@function recursive($abort) {
+ $a: $a + 1;
+ @if ($abort) {
+ @return $a;
+ }
+ @else {
+ @return recursive(true);
+ }
+}
+a {
+ b: recursive(false);
+}
+```
+
+Here we call the recursive function twice, so the `$a` inside must be independent.
+The stack allocation would look the following in this case:
+
+- Entering root scope
+ - pushing one variable on the runtime var stack.
+- Entering for scope for the first time
+ - updating varFramePtr to 1 since there is already one variable.
+ - pushing another variable on the runtime var stack
+- Entering for scope for the second time
+ - updating varFramePtr to 2 since there are now two variable.
+ - pushing another variable on the runtime var stack
+- Exiting second for scope and restoring old state
+- Exiting first for scope and restoring old state
+- Exiting root scope
+
+So in the second for loop run, when we have to resolve the variable expression for `$a`,
+we first get the base frame pointer (often called stack frame pointer in C). Then we only
+need to add the local offset to get to the current frame instance of the variable. Once we
+exit a scope, we simply need to pop those entities off the stack and reset the frame pointer.
+
+## How ambiguous/dynamic lookup is done in loops
+
+Unfortunately we are not able to fully statically optimize the variable lookups (as explained
+earlier, due to the full dynamic nature of Sass). IMO we can do it for functions and mixins,
+as they always have to be declared and defined at the same time. But variables can also just
+be declared and defined later. So in order to optimize this situation we will first fetch and
+cache all possible variable declarations (vector of VarRef). Then on evaluation we simply need
+to check and return the first entity that was actually defined (assigned to).
+
+## Afterword
+
+I hope this example somehow clarifies how variable stacks are implemented in LibSass. This
+optimization can easily bring 50% or more performance in contrast to always do the dynamic
+lookup via the also available hash-maps. They are needed anyway for meta functions, like
+`function-exists`. It is also not possible to (easily) create new variables once the parsing
+is done, so the C-API doesn't allow to create new variables during runtime.
diff --git a/docs/dev-filewatcher.md b/docs/dev-filewatcher.md
new file mode 100644
index 0000000000..18218934f4
--- /dev/null
+++ b/docs/dev-filewatcher.md
@@ -0,0 +1,19 @@
+## LibSass and file-watchers
+
+Currently and in the foreseeable future LibSass will not support any file-watching mode.
+Such a feature was always intended to be implemented by downstream consumers. In order
+to support this feature, LibSass compilation phase is split into different phases.
+
+LibSass supports to query all files included in a specific compilation. With the help
+of this list, consumers can setup file-watching for all involved files. But note that
+this list can change on any change, as the user may add or remove imports. This has to
+be checked by consumers between different compilations. Normally the flow would look
+something like this:
+
+- Setup compiler with entry point
+- Get initial list of relevant files
+- Optionally compile it when starting-up
+- On any change in any of the given files
+ - Recompile the entry point and write result
+ - Get the involved file-list of the entry-point
+ - Re-initialize watcher if relevant files changed
diff --git a/docs/dev-plugins.md b/docs/dev-plugins.md
new file mode 100644
index 0000000000..8a647c19fa
--- /dev/null
+++ b/docs/dev-plugins.md
@@ -0,0 +1,53 @@
+# LibSass plugins
+
+Plugins are shared object files (.so on *nix and .dll on win) that can be
+loaded by LibSass on runtime. Each plugin must have a main entry point
+`libsass_init_plugin(struct SassCompiler* compiler)`. There you can add
+new variables, custom functions or do anything you want with the compiler.
+
+## plugin.cpp
+
+```C++
+#include
+#include
+#include
+#include
+
+struct SassValue* ADDCALL call_fn_foo(struct SassValue* s_args, struct SassCompiler* comp, void* cookie)
+{
+ // we actually abuse the void* to store an "int"
+ return sass_make_number((intptr_t)cookie, "px");
+}
+
+extern "C" const char* ADDCALL libsass_get_version() {
+ return libsass_version();
+}
+
+// entry point for libsass to request custom functions from plugin
+extern "C" void ADDCALL libsass_init_plugin(struct SassCompiler* compiler)
+{
+
+ // Add constants via custom headers
+ sass_compiler_add_custom_function(compiler,
+ sass_make_function("foo()", call_fn_foo, (void*)42));
+}
+```
+
+To compile the plugin you need to have LibSass already built as a shared library
+(to link against it). The commands below expect the shared library in the `lib`
+sub-directory (`-Llib`). The plugin and the main LibSass process should "consume"
+the same shared LibSass library on runtime. It will probably also work if they
+use different LibSass versions. In this case we check if the major versions are
+compatible (i.e. 3.1.3 and 3.1.1 would be considered compatible).
+
+## Compile with gcc on linux
+
+```bash
+g++ -O2 -shared plugin.cpp -o plugin.so -fPIC -Llib -lsass
+```
+
+## Compile with mingw on windows
+
+```bash
+g++ -O2 -shared plugin.cpp -o plugin.dll -Llib -lsass
+```
diff --git a/docs/dev-unicode.md b/docs/dev-unicode.md
new file mode 100644
index 0000000000..6eb929fa5f
--- /dev/null
+++ b/docs/dev-unicode.md
@@ -0,0 +1,86 @@
+## LibSass and Unicode
+
+Note: this was written quite a long time ago, and while most of the information
+here is still valid, some items have evolved a bit in the meantime. The main
+show-stopper for LibSass to fully support unicode and e.g Latin1 files as input
+is the lack of unicode conversion tables (e.g. libiconv).
+
+LibSass currently expects all input to be utf8 encoded (and outputs only utf8),
+if you actually have any unicode characters at all. We do not support conversion
+between encodings, even if you declare it with a `@charset` rule. The text below
+was originally posted as an [issue](https://github.com/sass/libsass/issues/381)
+on the LibSass tracker. Since then the status is outdated as LibSass now expects
+your input to be utf8/ascii compatible, as it has been proven that reading ANSI
+(e.g. single byte encodings) as utf8 can lead to unexpected behavior, which can
+in the worst case lead to buffer overruns/segfaults. Therefore LibSass now checks
+your input to be valid utf8 encoded!
+
+### [Declaring character encodings in CSS](http://www.w3.org/International/questions/qa-css-charset.en)
+
+This [explains](http://www.w3.org/International/questions/qa-css-charset.en) how
+the character encoding of a css file is determined. Since we are only dealing with
+local files, we never have a HTTP header. So the precedence should be 'charset' rule,
+byte-order mark (BOM) or auto-detection (finally falling back to system default/UTF-8).
+This may not sound too hard to implement, but what about import rules? The CSS specs do
+not forbid the mixing of different encodings! I [solved that](https://github.com/mgreter/webmerge/) by
+converting all files to UTF-8 internally. On writing there is an option to tell the tool
+what encoding it should be (UTF-8 by default). One can also define if it should write a
+BOM or not and if it should add the charset declaration. A similar issue also popped up
+on the [drupal issue tracker](https://www.drupal.org/project/drupal/issues/1833356).
+
+Since my [tool]((https://github.com/mgreter/webmerge/)) is written in perl, I have a lot of
+utilities at hand to deal with different unicode charsets. I'm pretty sure that most OSS
+uses [ICU](http://site.icu-project.org/) or [libiconv](https://www.gnu.org/software/libiconv/) to
+convert between different encodings. But I have now idea how easy/hard this would be to
+integrate platform independent (it seems doable). ANSII (single byte encoding) to utf8
+is basically just a conversion table (for every supported code-page).
+
+### Current status on LibSass unicode support
+
+LibSass should/is fully UTF (and therefore plain ASCII) compatible.
+
+~~Currently LibSass seems to handle the common UTF-8 case pretty well. I believe it should correctly
+support all ASCII compatible encodings (like UTF-8 or Latin-1). If all includes use the same encoding,
+the output should be correct (in the same encoding). It should also handle unicode chars in [selectors,
+variable names and other identifiers](https://github.com/hcatlin/libsass/issues/244#issuecomment-34681227).
+This is true for all ASCII compatible encodings. So the main incompatible encodings (I'm aware of) are
+UTF-16/UTF-32 (which could be converted to UTF-8 with libiconv).~~
+
+LibSass 3.5 will enforce that your input is either plain ASCII (chars below 127) or utf8. It does not handle
+anything else, but therefore ensures that the output is in a valid form. Before version 3.5 you were able to
+mix different code-pages, which yielded unexpected behavior.
+
+### Current encoding auto detection
+
+LibSass currently reads all kind of BOMs and will error out if it finds something it doesn't know how to
+handle! It seems that it throws away the optional UTF-8 BOM (if any is found). IMO it would be nice if
+users could configure that (also if a charset rule should be added to the output). But it does not really
+take any `@charset` into account, it always assumes your input is utf8 and ignores any given `@charset`!
+
+### What is currently not supported
+
+- Using non ASCII compatible encodings (like UTF-16, Latin-1 etc.)
+- Using non ASCII characters in different encodings in different includes
+
+### What is missing to support the above cases
+
+- A way to convert between encodings (like libiconv/ICU)
+- Sniffing the charset inside the file (source is available)
+- Handling the conversion on import (and export)
+- Optional: Make output encoding configurable
+- Optional: Add optional/mandatory BOM (configurable)
+
+### Low priority feature
+
+I guess the current implementation should handle more than 99% of all real world use cases.
+A) Unicode characters are still seldom seen (as they can be written escaped)
+~~B) It will still work if it's UTF-8 or in any of the most common known western ISO codepages.
+Although I'm not sure how this applies to asian and other "exotic" codepages!~~
+
+I guess the biggest Problem is to have libiconv/ICU (or some other) library as a dependency. Since it contains
+a lot of rules for the conversions, I see it as the only way to handle this correctly. Once that is sorted out
+it should be pretty much straight forward to implement the missing pieces (in parser.cpp - Parser::parse should
+return encoding and add Parser::sniff_charset, then convert the source byte stream to UTF-8).
+
+I hope the statements above all hold true. Unicode is really not the easiest topic to wrap your head around. But
+since I did all the above recently in Perl, I wanted to document it here. Feel free to extend or criticize.
diff --git a/docs/dev-var-scoping.md b/docs/dev-var-scoping.md
new file mode 100644
index 0000000000..bed3762f90
--- /dev/null
+++ b/docs/dev-var-scoping.md
@@ -0,0 +1,57 @@
+# Sass variable scoping
+
+Variable scoping in Sass has some quirks which I'll try to
+explain in this document. This partially also applies to
+functions and mixins, as they are scope objects like variables
+too. But they can only be defined on the root scope, so their
+logic is not that complicated as variables.
+
+## Variable declarations in Sass
+
+Sass doesn't have explicit variable declarations. Variables
+are declared whenever an assignment to a variable happens. It
+is then local to the scope block the assignment was in. E.g.
+every ruleset (opened via `{` in scss) is a new scope block.
+
+On the surface this makes variable scoping quite simple, as
+declarations always happen with the definition of the variable.
+Under the hood it has some quirks, mainly in combination with loops.
+
+## Block scopes and (semi) transparent loops
+
+Consider the following example:
+
+```scss
+$a: 0;
+@for $i from 1 through 3 {
+ @debug $a;
+ $a: $i;
+}
+@debug $a
+```
+
+The first `@debug` calls should be easy to guess (0,1,2). But the
+last `@debug` is a bit trickier. In this case the `@for` loop is
+transparent and the assignment inside it is made to the outer
+variable on the root scope and will be reported as `3`.
+
+Now lets wrap the loop into a ruleset scope:
+
+```scss
+$b: 0;
+a {
+ @for $i from 1 through 3 {
+ @debug $b;
+ $b: $i;
+ }
+ @debug $b
+}
+```
+
+Again, the inner `@debug` calls are simply 0,1 and 2 and the
+tricky question is again what the last `@debug` call will yield?
+You might have guess it will report `3` again, but that is not
+correct, as Sass will report `0` here.
+
+Conclusion: Loops like `@for`, `@each` and `@while` are transparent
+only on the root-scope, but not on any inner scopes.
diff --git a/docs/developing.md b/docs/developing.md
index cb94253c8c..3351030180 100644
--- a/docs/developing.md
+++ b/docs/developing.md
@@ -2,10 +2,10 @@
So far this is only a loose collection of developer relevant docs:
+- [C-API documentation](api-doc.md)
- [Building LibSass](build.md)
+- [LibSass Plugins](dev-plugins.md)
- [Profiling LibSass](dev-profiling.md)
-- [C-API documentation](api-doc.md)
-- [LibSass and Unicode](unicode.md)
-- [SourceMap internals](source-map-internals.md)
-- [Custom memory allocator](allocator.md)
+- [LibSass and Unicode](dev-unicode.md)
+- [Custom memory allocator](dev-allocator.md)
- [Smart pointer implementation](dev-ast-memory.md)
diff --git a/docs/implementations-3.md b/docs/implementations-3.md
new file mode 100644
index 0000000000..95febc1444
--- /dev/null
+++ b/docs/implementations-3.md
@@ -0,0 +1,68 @@
+There are several implementations of `libsass` for a variety of languages. Here are just a few of them. Note, some implementations may or may not be up to date. We have not verified whether they work.
+
+### C
+* [sassc](https://github.com/hcatlin/sassc)
+
+### Crystal
+* [sass.cr](https://github.com/straight-shoota/sass.cr)
+
+### Elixir
+* [sass.ex](https://github.com/scottdavis/sass.ex)
+* [sass_compiler](https://github.com/Youimmi/sass_compiler)
+
+### Go
+* [go-libsass](https://github.com/wellington/go-libsass)
+* [go_sass](https://github.com/suapapa/go_sass)
+* [go-sass](https://github.com/SamWhited/go-sass)
+
+### Haskell
+* [hLibsass](https://github.com/jakubfijalkowski/hlibsass)
+* [hSass](https://github.com/jakubfijalkowski/hsass)
+
+### Java
+* [libsass-maven-plugin](https://github.com/warmuuh/libsass-maven-plugin)
+* [jsass](https://github.com/bit3/jsass)
+
+### JavaScript
+* [sass.js](https://github.com/medialize/sass.js)
+
+### Lua
+* [lua-sass](https://github.com/craigbarnes/lua-sass)
+
+### .NET
+* [libsass-net](https://github.com/darrenkopp/libsass-net)
+* [NSass](https://github.com/TBAPI-0KA/NSass)
+* [Sass.Net](https://github.com/andyalm/Sass.Net)
+* [SharpScss](https://github.com/xoofx/SharpScss)
+* [LibSassHost](https://github.com/Taritsyn/LibSassHost)
+
+### Nim
+
+* [sass](https://github.com/dom96/sass)
+* [nim-sass](https://github.com/zacharycarter/nim-sass)
+
+### node.js
+* [node-sass](https://github.com/sass/node-sass)
+
+### Perl
+* [CSS::Sass](https://github.com/caldwell/CSS-Sass)
+* [Text::Sass::XS](https://github.com/ysasaki/Text-Sass-XS)
+
+### PHP
+* [sassphp](https://github.com/sensational/sassphp)
+* [php-sass](https://github.com/lesstif/php-sass)
+
+### Python
+* [libsass-python](https://github.com/dahlia/libsass-python)
+* [SassPython](https://github.com/marianoguerra/SassPython)
+* [pylibsass](https://github.com/rsenk330/pylibsass)
+* [python-scss](https://github.com/pistolero/python-scss)
+
+### Ruby
+* [sassruby](https://github.com/hcatlin/sassruby)
+
+### Scala
+* [Sass-Scala](https://github.com/kkung/Sass-Scala)
+
+### Tcl
+* [tclsass](https://github.com/flightaware/tclsass)
diff --git a/docs/implementations.md b/docs/implementations.md
index 95febc1444..009d49c112 100644
--- a/docs/implementations.md
+++ b/docs/implementations.md
@@ -1,68 +1,13 @@
-There are several implementations of `libsass` for a variety of languages. Here are just a few of them. Note, some implementations may or may not be up to date. We have not verified whether they work.
+# LibSass implementations
-### C
-* [sassc](https://github.com/hcatlin/sassc)
-
-### Crystal
-* [sass.cr](https://github.com/straight-shoota/sass.cr)
-
-### Elixir
-* [sass.ex](https://github.com/scottdavis/sass.ex)
-* [sass_compiler](https://github.com/Youimmi/sass_compiler)
-
-### Go
-* [go-libsass](https://github.com/wellington/go-libsass)
-* [go_sass](https://github.com/suapapa/go_sass)
-* [go-sass](https://github.com/SamWhited/go-sass)
-
-### Haskell
-* [hLibsass](https://github.com/jakubfijalkowski/hlibsass)
-* [hSass](https://github.com/jakubfijalkowski/hsass)
-
-### Java
-* [libsass-maven-plugin](https://github.com/warmuuh/libsass-maven-plugin)
-* [jsass](https://github.com/bit3/jsass)
-
-### JavaScript
-* [sass.js](https://github.com/medialize/sass.js)
-
-### Lua
-* [lua-sass](https://github.com/craigbarnes/lua-sass)
+There are several implementations of `libsass` for a variety of languages.
+Here list of implementations compatible with the latest LibSass version.
+There is also an [older list with implementation][1] for the previous 3 branch.
-### .NET
-* [libsass-net](https://github.com/darrenkopp/libsass-net)
-* [NSass](https://github.com/TBAPI-0KA/NSass)
-* [Sass.Net](https://github.com/andyalm/Sass.Net)
-* [SharpScss](https://github.com/xoofx/SharpScss)
-* [LibSassHost](https://github.com/Taritsyn/LibSassHost)
-
-### Nim
-
-* [sass](https://github.com/dom96/sass)
-* [nim-sass](https://github.com/zacharycarter/nim-sass)
-
-### node.js
-* [node-sass](https://github.com/sass/node-sass)
+### C
+* [sassc](https://github.com/sass/sassc)
### Perl
* [CSS::Sass](https://github.com/caldwell/CSS-Sass)
-* [Text::Sass::XS](https://github.com/ysasaki/Text-Sass-XS)
-
-### PHP
-* [sassphp](https://github.com/sensational/sassphp)
-* [php-sass](https://github.com/lesstif/php-sass)
-
-### Python
-* [libsass-python](https://github.com/dahlia/libsass-python)
-* [SassPython](https://github.com/marianoguerra/SassPython)
-* [pylibsass](https://github.com/rsenk330/pylibsass)
-* [python-scss](https://github.com/pistolero/python-scss)
-
-### Ruby
-* [sassruby](https://github.com/hcatlin/sassruby)
-
-### Scala
-* [Sass-Scala](https://github.com/kkung/Sass-Scala)
-### Tcl
-* [tclsass](https://github.com/flightaware/tclsass)
+[1]: implementations-3.md
diff --git a/docs/plugins.md b/docs/plugins.md
deleted file mode 100644
index a9711e3e16..0000000000
--- a/docs/plugins.md
+++ /dev/null
@@ -1,47 +0,0 @@
-Plugins are shared object files (.so on *nix and .dll on win) that can be loaded by LibSass on runtime. Currently we only provide a way to load internal/custom functions from plugins. In the future we probably will also add a way to provide custom importers via plugins (needs more refactoring to [support multiple importers with some kind of priority system](https://github.com/sass/libsass/issues/962)).
-
-## plugin.cpp
-
-```C++
-#include
-#include
-#include
-#include "sass_values.h"
-
-union Sass_Value* ADDCALL call_fn_foo(const union Sass_Value* s_args, void* cookie)
-{
- // we actually abuse the void* to store an "int"
- return sass_make_number((intptr_t)cookie, "px");
-}
-
-extern "C" const char* ADDCALL libsass_get_version() {
- return libsass_version();
-}
-
-extern "C" Sass_C_Function_List ADDCALL libsass_load_functions()
-{
- // allocate a custom function caller
- Sass_C_Function_Callback fn_foo =
- sass_make_function("foo()", call_fn_foo, (void*)42);
- // create list of all custom functions
- Sass_C_Function_List fn_list = sass_make_function_list(1);
- // put the only function in this plugin to the list
- sass_function_set_list_entry(fn_list, 0, fn_foo);
- // return the list
- return fn_list;
-}
-```
-
-To compile the plugin you need to have LibSass already built as a shared library (to link against it). The commands below expect the shared library in the `lib` sub-directory (`-Llib`). The plugin and the main LibSass process should "consume" the same shared LibSass library on runtime. It will propably also work if they use different LibSass versions. In this case we check if the major versions are compatible (i.e. 3.1.3 and 3.1.1 would be considered compatible).
-
-## Compile with gcc on linux
-
-```bash
-g++ -O2 -shared plugin.cpp -o plugin.so -fPIC -Llib -lsass
-```
-
-## Compile with mingw on windows
-
-```bash
-g++ -O2 -shared plugin.cpp -o plugin.dll -Llib -lsass
-```
diff --git a/docs/setup-environment.md b/docs/setup-environment.md
index e30845b6e2..beaedc74c8 100644
--- a/docs/setup-environment.md
+++ b/docs/setup-environment.md
@@ -3,7 +3,7 @@ In order to install and setup your local development environment, there are some
* git
* gcc/clang/llvm (Linux: build tools, Mac OS X: XCode w/ Command Line Tools)
-* ruby w/ bundler
+* ruby w/ bundler (only to run the spec-test suite)
OS X:
First you'll need to install XCode which you can now get from the AppStore installed on your mac. After you download that and run it, then run this on the command line:
diff --git a/docs/source-map-internals.md b/docs/source-map-internals.md
deleted file mode 100644
index fd829a198a..0000000000
--- a/docs/source-map-internals.md
+++ /dev/null
@@ -1,51 +0,0 @@
-This document is mainly intended for developers!
-
-# Documenting some of the source map internals
-
-Since source maps are somewhat a black box to all LibSass maintainers, [I](@mgreter) will try to document my findings with source maps in LibSass, as I come across them. This document will also brievely explain how LibSass parses the source and how it outputs the result.
-
-The main storage for SourceMap mappings is the `mappings` vector:
-
-```
-# in source_map.hpp
-vector mappings
-# in mappings.hpp
-struct Mapping ...
- Position original_position;
- Position generated_position;
-```
-
-## Every parsed token has its source associated
-
-LibSass uses a lexical parser. Whenever LibSass finds a token of interest, it creates a specific `AST_Node`, which will hold a reference to the input source with line/column information. `AST_Node` is the base class for all parsed items. They are declared in `ast.hpp` and are used in `parser.hpp`. Here a simple example:
-
-```
-if (lex< custom_property_name >()) {
- Sass::String* prop = new (ctx.mem) String_Constant(path, source_position, lexed);
- return new (ctx.mem) Declaration(path, prop->position(), prop, ...);
-}
-```
-
-## How is the `source_position` calculated
-
-This is automatically done with `lex` in `parser.hpp`. Whenever something is lexed, the `source_position` is updated. But be aware that `source_position` points to the beginning of the parsed text. If you need a mapping for the position where the parsing ended, you need to add another call to `lex` (to match nothing)!
-
-```
-lex< exactly < empty_str > >();
-end = new (ctx.mem) String_Constant(path, source_position, lexed);
-```
-
-## How are mappings for the output created
-
-So far we have collected all needed data for all tokens in the input stream. We can now use this information to create mappings when we put things into the output stream. Mappings are created via the `add_mappings` method:
-
-```
-# in source_map.hpp
-void add_mapping(AST_Node* node);
-```
-
-This method is called in two places:
-- `Inspect::append_to_buffer`
-- `Output_[Nested|Compressed]::append_to_buffer`
-
-Mappings can only be created for things that have been parsed into a `AST_Node`. Otherwise we do not have the information to create the mappings, which is the reason why LibSass currently only maps the most important tokens in source maps.
diff --git a/docs/trace.md b/docs/trace.md
deleted file mode 100644
index 4a57c901f9..0000000000
--- a/docs/trace.md
+++ /dev/null
@@ -1,26 +0,0 @@
-## This is proposed interface in https://github.com/sass/libsass/pull/1288
-
-Additional debugging macros with low overhead are available, `TRACE()` and `TRACEINST()`.
-
-Both macros simulate a string stream, so they can be used like this:
-
- TRACE() << "Reached.";
-
-produces:
-
- [LibSass] parse_value parser.cpp:1384 Reached.
-
-`TRACE()`
- logs function name, source filename, source file name to the standard error and the attached
- stream to the standard error.
-
-`TRACEINST(obj)`
- logs object instance address, function name, source filename, source file name to the standard error and the attached stream to the standard error, for example:
-
- TRACEINST(this) << "String_Constant created " << this;
-
-produces:
-
- [LibSass] 0x8031ba980:String_Constant ./ast.hpp:1371 String_Constant created (0,"auto")
-
-The macros generate output only of `LibSass_TRACE` is set in the environment.
diff --git a/docs/triage.md b/docs/triage.md
deleted file mode 100644
index 0fc11784cc..0000000000
--- a/docs/triage.md
+++ /dev/null
@@ -1,17 +0,0 @@
-This is an article about how to help with LibSass issues. Issue triage is a fancy word for explaining how we deal with incoming issues and make sure that the right problems get worked on. The lifecycle of an issue goes like this:
-
-1. Issue is reported by a user.
-2. If the issue seems like a bug, then the "bug" tag is added.
-3. If the reporting user didn't also create a spec test over at sass/sass-spec, the "needs test" tag is added.
-4. Verify that Ruby Sass *does not* have the same bug. LibSass strives to be an exact replica of how Ruby Sass works. If it's an issue that neither project has solved, please close the ticket with the "not in sass" label.
-5. The smallest possible breaking test is created in sass-spec. Cut away any extra information or non-breaking code until the core issue is made clear.
-6. Again, verify that the expected output matches the latest Ruby Sass release. Do this by using your own tool OR by running ./sass-spec.rb in the spec folder and making sure that your test passes!
-7. Create the test cases in sass-spec with the name spec/LibSass-todo-issues/issue_XXX/input.scss and expected_output.css where the XXX is the issue number here.
-8. Commit that test to sass-spec, making sure to reference the issue in the comment message like "Test to demonstrate sass/LibSass#XXX".
-9. Once the spec test exists, remove the "needs test" tag and replace it with "test written".
-10. A C++ developer will then work on the issue and issue a pull request to fix the issue.
-11. A core member verifies that the fix does actually fix the spec tests.
-12. The fix is merged into the project.
-13. The spec is moved from the LibSass-todo-issues folder into LibSass-closed-issues
-14. The issue is closed
-15. Have a soda pop or enjoyable beverage of your choice
diff --git a/docs/unicode.md b/docs/unicode.md
deleted file mode 100644
index 309d70e449..0000000000
--- a/docs/unicode.md
+++ /dev/null
@@ -1,45 +0,0 @@
-LibSass currently expects all input to be utf8 encoded (and outputs only utf8), if you actually have any unicode characters at all. We do not support conversion between encodings, even if you declare it with a `@charset` rule. The text below was originally posted as an [issue](https://github.com/sass/libsass/issues/381) on the LibSass tracker. Since then the status is outdated as LibSass now expects your
-input to be utf8/ascii compatible, as it has been proven that reading ANSI (e.g. single byte encodings) as utf8 can lead to unexpected
-behavior, which can in the worst case lead to buffer overruns/segfaults. Therefore LibSass now checks your input to be valid utf8 encoded!
-
-### [Declaring character encodings in CSS](http://www.w3.org/International/questions/qa-css-charset.en)
-
-This [explains](http://www.w3.org/International/questions/qa-css-charset.en) how the character encoding of a css file is determined. Since we are only dealing with local files, we never have a HTTP header. So the precedence should be 'charset' rule, byte-order mark (BOM) or auto-detection (finally falling back to system default/UTF-8). This may not sound too hard to implement, but what about import rules? The CSS specs do not forbid the mixing of different encodings! I [solved that](https://github.com/mgreter/webmerge/) by converting all files to UTF-8 internally. On writing there is an option to tell the tool what encoding it should be (UTF-8 by default). One can also define if it should write a BOM or not and if it should add the charset declaration.
-
-Since my [tool]((https://github.com/mgreter/webmerge/)) is written in perl, I have a lot of utilities at hand to deal with different unicode charsets. I'm pretty sure that most OSS uses [ICU](http://site.icu-project.org/) or [libiconv](https://www.gnu.org/software/libiconv/) to convert between different encodings. But I have now idea how easy/hard this would be to integrate platform independent (it seems doable). ANSII (single byte encoding) to utf8 is basically just a conversion table (for every supported code-page).
-
-### Current status on LibSass unicode support
-
-LibSass should/is fully UTF (and therefore plain ASCII) compatible.
-
-~~Currently LibSass seems to handle the common UTF-8 case pretty well. I believe it should correctly support all ASCII compatible encodings (like UTF-8 or Latin-1). If all includes use the same encoding, the output should be correct (in the same encoding). It should also handle unicode chars in [selectors, variable names and other identifiers](https://github.com/hcatlin/libsass/issues/244#issuecomment-34681227). This is true for all ASCII compatible encodings. So the main incompatible encodings (I'm aware of) are UTF-16/UTF-32 (which could be converted to UTF-8 with libiconv).~~
-
-LibSass 3.5 will enforce that your input is either plain ASCII (chars below 127) or utf8. It does not handle anything else, but therefore ensures that the output is in a valid form. Before version 3.5 you were able to mix different code-pages, which yielded unexpected behavior.
-
-### Current encoding auto detection
-
-LibSass currently reads all kind of BOMs and will error out if it finds something it doesn't know how to handle! It seems that it throws away the optional UTF-8 BOM (if any is found). IMO it would be nice if users could configure that (also if a charset rule should be added to the output). But it does not really take any `@charset` into account, it always assumes your input is utf8 and ignores any given `@charset`!
-
-### What is currently not supported
-
-- Using non ASCII compatible encodings (like UTF-16, Latin-1 etc.)
-- Using non ASCII characters in different encodings in different includes
-
-### What is missing to support the above cases
-
-- A way to convert between encodings (like libiconv/ICU)
-- Sniffing the charset inside the file (source is available)
-- Handling the conversion on import (and export)
-- Optional: Make output encoding configurable
-- Optional: Add optional/mandatory BOM (configurable)
-
-### Low priority feature
-
-I guess the current implementation should handle more than 99% of all real world use cases.
-A) Unicode characters are still seldom seen (as they can be written escaped)
-~~B) It will still work if it's UTF-8 or in any of the most common known western ISO codepages.
-Although I'm not sure how this applies to asian and other "exotic" codepages!~~
-
-I guess the biggest Problem is to have libiconv/ICU (or some other) library as a dependency. Since it contains a lot of rules for the conversions, I see it as the only way to handle this correctly. Once that is sorted out it should be pretty much straight forward to implement the missing pieces (in parser.cpp - Parser::parse should return encoding and add Parser::sniff_charset, then convert the source byte stream to UTF-8).
-
-I hope the statements above all hold true. Unicode is really not the easiest topic to wrap your head around. But since I did all the above recently in Perl, I wanted to document it here. Feel free to extend or criticize.
diff --git a/include/sass.h b/include/sass.h
index 1dd8b06dca..ef07d10ccf 100644
--- a/include/sass.h
+++ b/include/sass.h
@@ -1,15 +1,22 @@
#ifndef SASS_H
#define SASS_H
-// #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
+#include
+#include
+#include
+#include
#endif
-
diff --git a/include/sass/base.h b/include/sass/base.h
index 132da693ab..1d93cf6d80 100644
--- a/include/sass/base.h
+++ b/include/sass/base.h
@@ -1,9 +1,9 @@
+/*****************************************************************************/
+/* Part of LibSass, released under the MIT license (See LICENSE.txt). */
+/*****************************************************************************/
#ifndef SASS_BASE_H
#define SASS_BASE_H
-// #define DEBUG
-// #define DEBUG_SHARED_PTR
-
#ifdef _MSC_VER
#pragma warning(disable : 4503)
#ifndef _SCL_SECURE_NO_WARNINGS
@@ -23,9 +23,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)
@@ -37,7 +45,7 @@
#ifdef _WIN32
- /* You should define ADD_EXPORTS *only* when building the DLL. */
+/* You should define ADD_EXPORTS *only* when building the DLL. */
#ifdef ADD_EXPORTS
#define ADDAPI __declspec(dllexport)
#define ADDCALL __cdecl
@@ -54,41 +62,39 @@
#endif
-/* Make sure functions are exported with C linkage under C++ compilers. */
#ifdef __cplusplus
extern "C" {
#endif
+ // Change the virtual current working directory
+ 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);
+
+ // 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);
+
+ // 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);
-// 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);
+ // Deallocate libsass heap memory
+ ADDAPI void ADDCALL sass_free_memory(void* ptr);
+ ADDAPI void ADDCALL sass_free_c_string(char* ptr);
#ifdef __cplusplus
} // __cplusplus defined.
diff --git a/include/sass/compiler.h b/include/sass/compiler.h
new file mode 100644
index 0000000000..36a40fa4d8
--- /dev/null
+++ b/include/sass/compiler.h
@@ -0,0 +1,212 @@
+/*****************************************************************************/
+/* Part of LibSass, released under the MIT license (See LICENSE.txt). */
+/*****************************************************************************/
+#ifndef SASS_C_COMPILER_H
+#define SASS_C_COMPILER_H
+
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ // Create a new LibSass compiler context
+ ADDAPI struct SassCompiler* ADDCALL sass_make_compiler();
+
+ // Release all memory allocated with the compiler
+ 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);
+
+ // Write or print the output to the console or the configured output path
+ ADDAPI void ADDCALL sass_compiler_write_output(struct SassCompiler* compiler);
+
+ // Write source-map to configured path if options are set accordingly
+ ADDAPI void ADDCALL sass_compiler_write_srcmap(struct SassCompiler* compiler);
+
+ // Execute all compiler steps and write/print results
+ ADDAPI int ADDCALL sass_compiler_execute(struct SassCompiler* compiler);
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ // Add additional include paths where LibSass will look for includes.
+ // Note: the passed in `paths` can be path separated (`;` on windows, `:` otherwise).
+ ADDAPI void ADDCALL sass_compiler_add_include_paths(struct SassCompiler* compiler, const char* paths);
+
+ // Load dynamic loadable plugins from `paths`. Plugins are only supported on certain OSs and
+ // are still in experimental state. This will look for `*.dll`, `*.so` or `*.dynlib` files.
+ // It then tries to load the found libraries and does a few checks to see if the library
+ // is actually a LibSass plugin. We then call its init hook if the library is compatible.
+ // Note: the passed in `paths` can be path separated (`;` on windows, `:` otherwise).
+ ADDAPI void ADDCALL sass_compiler_load_plugins(struct SassCompiler* compiler, const char* paths);
+
+ // Add a custom header importer that will always be executed before any other
+ // compilations takes place. Useful to prepend a shared copyright header or to
+ // provide global variables or functions. This feature is still in experimental state.
+ // Note: With the adaption of Sass Modules this might be completely replaced in the future.
+ ADDAPI void ADDCALL sass_compiler_add_custom_header(struct SassCompiler* compiler, struct SassImporter* header);
+
+ // Add a custom importer that will be executed when a sass `@import` rule is found.
+ // This is useful to e.g. rewrite import locations or to load content from remote.
+ // For more please check https://github.com/sass/libsass/blob/master/docs/api-importer.md
+ // Note: The importer will not be called for regular css `@import url()` rules.
+ ADDAPI void ADDCALL sass_compiler_add_custom_importer(struct SassCompiler* compiler, struct SassImporter* importer);
+
+ // Add a custom function that will be executed when the corresponding function call is
+ // requested from any sass code. This is useful to provide custom functions in your code.
+ // For more please check https://github.com/sass/libsass/blob/master/docs/api-function.md
+ ADDAPI void ADDCALL sass_compiler_add_custom_function(struct SassCompiler* compiler, struct SassFunction* function);
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ // Setter for output style (see `enum SassOutputStyle` for possible options).
+ ADDAPI void ADDCALL sass_compiler_set_input_syntax(struct SassCompiler* compiler, enum SassImportSyntax syntax);
+
+ // Setter for output style (see `enum SassOutputStyle` for possible options).
+ ADDAPI void ADDCALL sass_compiler_set_output_style(struct SassCompiler* compiler, enum SassOutputStyle style);
+
+ // Try to detect and set logger options for terminal colors, unicode and columns.
+ ADDAPI void ADDCALL sass_compiler_autodetect_logger_capabilities(struct SassCompiler* compiler);
+
+ // Setter for enabling/disabling logging with ANSI colors.
+ ADDAPI void ADDCALL sass_compiler_set_logger_colors(struct SassCompiler* compiler, bool enable);
+
+ // Setter for enabling/disabling logging with unicode text.
+ ADDAPI void ADDCALL sass_compiler_set_logger_unicode(struct SassCompiler* compiler, bool enable);
+
+ // Getter for number precision (how floating point numbers are truncated).
+ ADDAPI int ADDCALL sass_compiler_get_precision(struct SassCompiler* compiler);
+
+ // Setter for number precision (how floating point numbers are truncated).
+ ADDAPI void ADDCALL sass_compiler_set_precision(struct SassCompiler* compiler, int precision);
+
+ // Getter for compiler entry point (which file or data to parse first).
+ ADDAPI struct SassImport* ADDCALL sass_compiler_get_entry_point(struct SassCompiler* compiler);
+
+ // Setter for compiler entry point (which file or data to parse first).
+ ADDAPI void ADDCALL sass_compiler_set_entry_point(struct SassCompiler* compiler, struct SassImport* import);
+
+ // Getter for compiler output path (where to store the result)
+ // Note: LibSass does not write the file, implementers should write to this path.
+ ADDAPI const char* ADDCALL sass_compiler_get_output_path(struct SassCompiler* compiler);
+
+ // Setter for compiler output path (where to store the result)
+ // Note: LibSass does not write the file, implementers should write to this path.
+ ADDAPI void ADDCALL sass_compiler_set_output_path(struct SassCompiler* compiler, const char* output_path);
+
+ // Getter for option to suppress anything being printed on stderr (quiet mode)
+ ADDAPI bool ADDCALL sass_compiler_get_suppress_stderr(struct SassCompiler* compiler);
+
+ // Setter for option to suppress anything being printed on stderr (quiet mode)
+ ADDAPI void ADDCALL sass_compiler_set_suppress_stderr(struct SassCompiler* compiler, bool suppress);
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ // Getter for warnings that occurred during any step.
+ ADDAPI const char* ADDCALL sass_compiler_get_warn_string(struct SassCompiler* compiler);
+
+ // Getter for output after parsing, compilation and rendering.
+ ADDAPI const char* ADDCALL sass_compiler_get_output_string(struct SassCompiler* compiler);
+
+ // Getter for footer string containing optional source-map (embedded or link).
+ ADDAPI const char* ADDCALL sass_compiler_get_footer_string(struct SassCompiler* compiler);
+
+ // Getter for string containing the optional source-mapping.
+ ADDAPI const char* ADDCALL sass_compiler_get_srcmap_string(struct SassCompiler* compiler);
+
+ // Check if implementor is expected to write a output file
+ ADDAPI bool ADDCALL sass_compiler_has_output_file(struct SassCompiler* compiler);
+
+ // Check if implementor is expected to write a source-map file
+ ADDAPI bool ADDCALL sass_compiler_has_srcmap_file(struct SassCompiler* compiler);
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ // Setter for source-map mode (how to embed or not embed the source-map).
+ ADDAPI void ADDCALL sass_compiler_set_srcmap_mode(struct SassCompiler* compiler, enum SassSrcMapMode mode);
+
+ // Setter for source-map path (where to store the source-mapping).
+ // Note: if path is not explicitly given, we will deduct one from output path.
+ // Note: LibSass does not write the file, implementers should write to this path.
+ ADDAPI void ADDCALL sass_compiler_set_srcmap_path(struct SassCompiler* compiler, const char* path);
+
+ // Getter for source-map path (where to store the source-mapping).
+ // Note: if path is not explicitly given, we will deduct one from output path.
+ // Note: the value will only be deducted after the main render phase is completed.
+ // Note: LibSass does not write the file, implementers should write to this path.
+ ADDAPI const char* ADDCALL sass_compiler_get_srcmap_path(struct SassCompiler* compiler);
+
+ // Setter for source-map root (simply passed to the resulting srcmap info).
+ // Note: if not given, no root attribute will be added to the srcmap info object.
+ ADDAPI void ADDCALL sass_compiler_set_srcmap_root(struct SassCompiler* compiler, const char* root);
+
+ // Setter for source-map file-url option (renders urls in srcmap as `file://` urls)
+ ADDAPI void ADDCALL sass_compiler_set_srcmap_file_urls(struct SassCompiler* compiler, bool enable);
+
+ // Setter for source-map embed-contents option (includes full sources in the srcmap info)
+ ADDAPI void ADDCALL sass_compiler_set_srcmap_embed_contents(struct SassCompiler* compiler, bool enable);
+
+ // Setter to enable more detailed source map (also meaning bigger payload).
+ // Mostly useful if you want to post process the results again where the more detailed
+ // source-maps might by used by downstream post-processor to point back to original files.
+ ADDAPI void ADDCALL sass_compiler_set_srcmap_details(struct SassCompiler* compiler, bool openers, bool closers);
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ // Getter to return the number of all included files.
+ ADDAPI size_t ADDCALL sass_compiler_get_included_files_count(struct SassCompiler* compiler);
+
+ // Getter to return path to the included file at position `n`.
+ ADDAPI const char* ADDCALL sass_compiler_get_included_file_path(struct SassCompiler* compiler, size_t n);
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ // Getter for current import context. Use `SassImport` functions to query the state.
+ ADDAPI const struct SassImport* ADDCALL sass_compiler_get_last_import(struct SassCompiler* compiler);
+
+ // 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);
+
+ // Returns status code for compiler (0 meaning success, anything else is an error)
+ ADDAPI int ADDCALL sass_compiler_get_status(struct SassCompiler* compiler);
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ // Resolve a file relative to last import or include paths in the sass option struct.
+ ADDAPI char* ADDCALL sass_compiler_find_file(const char* path, struct SassCompiler* compiler);
+
+ // Resolve an include relative to last import or include paths in the sass option struct.
+ // This will do a lookup as LibSass would do internally (partials, different extensions).
+ // ToDo: Check if we should add `includeIndex` option to check for directory index files!?
+ ADDAPI char* ADDCALL sass_compiler_find_include(const char* path, struct SassCompiler* compiler);
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+} // EO extern "C".
+#endif
+
+#endif
diff --git a/include/sass/context.h b/include/sass/context.h
deleted file mode 100644
index 7eb181e259..0000000000
--- a/include/sass/context.h
+++ /dev/null
@@ -1,174 +0,0 @@
-#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);
-
-// Resolve a file relative to last import or include paths in the sass option struct
-// find_file looks for the exact file name while find_include does a regular sass include
-ADDAPI char* ADDCALL sass_compiler_find_file (const char* path, struct Sass_Compiler* compiler);
-ADDAPI char* ADDCALL sass_compiler_find_include (const char* path, struct Sass_Compiler* compiler);
-
-#ifdef __cplusplus
-} // __cplusplus defined.
-#endif
-
-#endif
diff --git a/include/sass/enums.h b/include/sass/enums.h
new file mode 100644
index 0000000000..1cc51e769a
--- /dev/null
+++ b/include/sass/enums.h
@@ -0,0 +1,56 @@
+/*****************************************************************************/
+/* Part of LibSass, released under the MIT license (See LICENSE.txt). */
+/*****************************************************************************/
+#ifndef SASS_ENUMS_H
+#define SASS_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!
+ SASS_STYLE_TO_CSS
+ };
+
+ // Type of parser to use
+ enum SassImportSyntax {
+ SASS_IMPORT_AUTO,
+ SASS_IMPORT_SCSS,
+ SASS_IMPORT_SASS,
+ SASS_IMPORT_CSS,
+ };
+
+ // Config how to produce source-map
+ enum SassSrcMapMode {
+ // Don't render any source-mapping.
+ SASS_SRCMAP_NONE,
+ // Only render the `srcmap` string.
+ // The `footer` will be `NULL`.
+ SASS_SRCMAP_CREATE,
+ // Write srcmap link into `footer`
+ SASS_SRCMAP_EMBED_LINK,
+ // Embed srcmap into `footer`
+ SASS_SRCMAP_EMBED_JSON,
+ };
+
+ // State of the compiler object
+ enum SassCompilerState {
+ SASS_COMPILER_CREATED,
+ SASS_COMPILER_PARSED,
+ SASS_COMPILER_COMPILED,
+ SASS_COMPILER_RENDERED,
+ SASS_COMPILER_DESTROYED,
+ SASS_COMPILER_FAILED,
+ };
+
+#ifdef __cplusplus
+} // __cplusplus defined.
+#endif
+
+#endif
diff --git a/include/sass/error.h b/include/sass/error.h
new file mode 100644
index 0000000000..8c6ae8caab
--- /dev/null
+++ b/include/sass/error.h
@@ -0,0 +1,62 @@
+/*****************************************************************************/
+/* Part of LibSass, released under the MIT license (See LICENSE.txt). */
+/*****************************************************************************/
+#ifndef SASS_ERROR_H
+#define SASS_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);
+
+ // Getter for plain error message (use after compiler was rendered).
+ ADDAPI const char* ADDCALL sass_error_get_string(const struct SassError* error);
+
+ // Getter for error status as css (In order to show error in browser).
+ // Memory returned by this function must be freed via `sass_free_c_string`.
+ ADDAPI char* ADDCALL sass_error_get_css(const struct SassError* error);
+
+ // Getter for error status as json object (Useful to pass to downstream).
+ // Memory returned by this function must be freed via `sass_free_c_string`.
+ ADDAPI char* ADDCALL sass_error_get_json(const struct SassError* error);
+
+ // Getter for formatted error message. According to logger style this
+ // may be in unicode and may contain ANSI escape codes for colors.
+ ADDAPI const char* ADDCALL sass_error_get_formatted(const struct SassError* error);
+
+ // Getter for line position where error occurred (starts from 1).
+ ADDAPI size_t ADDCALL sass_error_get_line(const struct SassError* error);
+
+ // Getter for column position where error occurred (starts from 1).
+ ADDAPI size_t ADDCALL sass_error_get_column(const struct SassError* error);
+
+ // Getter for source content referenced in line and column.
+ ADDAPI const char* ADDCALL sass_error_get_content(const struct SassError* error);
+
+ // Getter for path where the error occurred.
+ ADDAPI const char* ADDCALL sass_error_get_path(const struct SassError* error);
+
+ // Getter for number of traces attached to error object.
+ ADDAPI size_t ADDCALL sass_error_count_traces(const struct SassError* error);
+
+ // Getter for last trace (or nullptr if none are available).
+ ADDAPI const struct SassTrace* ADDCALL sass_error_last_trace(const struct SassError* error);
+
+ // Getter for nth trace (or nullptr if `n` is invalid).
+ ADDAPI const struct SassTrace* ADDCALL sass_error_get_trace(const struct SassError* error, size_t n);
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+} // __cplusplus defined.
+#endif
+
+#endif
diff --git a/include/sass/function.h b/include/sass/function.h
new file mode 100644
index 0000000000..aea052bca8
--- /dev/null
+++ b/include/sass/function.h
@@ -0,0 +1,49 @@
+/*****************************************************************************/
+/* Part of LibSass, released under the MIT license (See LICENSE.txt). */
+/*****************************************************************************/
+#ifndef SASS_FUNCTION_H
+#define SASS_FUNCTION_H
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ // Type definition for custom functions
+ typedef struct SassValue* (*SassFunctionLambda)(
+ struct SassValue*, struct SassCompiler* compiler, void* cookie);
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ // Create custom function (with arbitrary data pointer called `cookie`)
+ // The pointer is often used to store the callback into the actual binding.
+ ADDAPI struct SassFunction* ADDCALL sass_make_function (const char* signature, SassFunctionLambda lambda, void* cookie);
+
+ // Deallocate custom function and release memory
+ ADDAPI void ADDCALL sass_delete_function (struct SassFunction* entry);
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ // Getter for custom function signature.
+ ADDAPI const char* ADDCALL sass_function_get_signature (struct SassFunction* function);
+
+ // Getter for custom function lambda.
+ ADDAPI SassFunctionLambda ADDCALL sass_function_get_lambda (struct SassFunction* function);
+
+ // Getter for custom function data cookie.
+ ADDAPI void* ADDCALL sass_function_get_cookie (struct SassFunction* function);
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+} // __cplusplus defined.
+#endif
+
+#endif
diff --git a/include/sass/functions.h b/include/sass/functions.h
deleted file mode 100644
index ac47e8ede1..0000000000
--- a/include/sass/functions.h
+++ /dev/null
@@ -1,139 +0,0 @@
-#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);
-
-
-// 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);
-
-// 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);
-
-// Deallocator for associated memory
-ADDAPI void ADDCALL sass_delete_importer (Sass_Importer_Entry 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);
-
-// Getters and Setters for environments (lexical, local and global)
-ADDAPI union Sass_Value* ADDCALL sass_env_get_lexical (Sass_Env_Frame, const char*);
-ADDAPI void ADDCALL sass_env_set_lexical (Sass_Env_Frame, const char*, union Sass_Value*);
-ADDAPI union Sass_Value* ADDCALL sass_env_get_local (Sass_Env_Frame, const char*);
-ADDAPI void ADDCALL sass_env_set_local (Sass_Env_Frame, const char*, union Sass_Value*);
-ADDAPI union Sass_Value* ADDCALL sass_env_get_global (Sass_Env_Frame, const char*);
-ADDAPI void ADDCALL sass_env_set_global (Sass_Env_Frame, const char*, union Sass_Value*);
-
-// Getters for import entry
-ADDAPI const char* ADDCALL sass_import_get_imp_path (Sass_Import_Entry);
-ADDAPI const char* ADDCALL sass_import_get_abs_path (Sass_Import_Entry);
-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);
-// 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);
-
-// 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);
-
-
-
-// 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);
-
-// 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);
-
-
-#ifdef __cplusplus
-} // __cplusplus defined.
-#endif
-
-#endif
diff --git a/include/sass/fwdecl.h b/include/sass/fwdecl.h
new file mode 100644
index 0000000000..42e0c6b2f6
--- /dev/null
+++ b/include/sass/fwdecl.h
@@ -0,0 +1,32 @@
+/*****************************************************************************/
+/* Part of LibSass, released under the MIT license (See LICENSE.txt). */
+/*****************************************************************************/
+#ifndef SASS_FWDECL_H
+#define SASS_FWDECL_H
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ // Forward declare anonymous structs
+ // C never sees any implementation
+ struct SassValue; // ref-counted
+ struct SassTrace; // C++ wrapper
+ struct SassError; // CAPI-struct
+ struct SassCompiler; // C++ wrapper
+ struct SassFunction; // CAPI-struct
+ struct SassSource; // C++ wrapper
+ struct SassSrcSpan; // C++ wrapper
+ struct SassImport; // ref-counted
+ struct SassImporter; // CAPI-struct
+ struct SassImportList; // std::deque
+ struct SassMapIterator; // CAPI-struct
+ struct SassGetOpt; // Helper
+
+#ifdef __cplusplus
+} // __cplusplus defined.
+#endif
+
+#endif
diff --git a/include/sass/getopt.h b/include/sass/getopt.h
new file mode 100644
index 0000000000..d7a000d8cb
--- /dev/null
+++ b/include/sass/getopt.h
@@ -0,0 +1,92 @@
+/*****************************************************************************/
+/* Part of LibSass, released under the MIT license (See LICENSE.txt). */
+/*****************************************************************************/
+#ifndef SASS_C_GETOPT_H
+#define SASS_C_GETOPT_H
+
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ // Just forward declare
+ struct SassGetOptEnum;
+
+ // Struct must be known in order to access it in the callback
+ // We don't expect this to change much once it is proven good
+ // We also don't want to support all cases under the sun!
+ union SassOptionValue {
+ int integer;
+ bool boolean;
+ const char* string;
+ enum SassOutputStyle style;
+ enum SassImportSyntax syntax;
+ enum SassSrcMapMode mode;
+ };
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ // Create a new option parser to help with parsing config from users
+ // Optimized to act like GNU GetOpt Long to consume main `argv` items
+ // But can also be used to parse any other list of config strings
+ ADDAPI struct SassGetOpt* ADDCALL sass_make_getopt(struct SassCompiler* compiler);
+
+ // Delete and finalize the option parser. Make sure to call
+ // this before you want to start the actual compilation phase.
+ ADDAPI void ADDCALL sass_delete_getopt(struct SassGetOpt* getopt);
+
+ // Utility function to tell LibSass to register its default options
+ // It is recommended to always call this function right after creation
+ ADDAPI void ADDCALL sass_getopt_populate_options(struct SassGetOpt* getopt);
+
+ // Utility function to tell LibSass to register its default arguments
+ ADDAPI void ADDCALL sass_getopt_populate_arguments(struct SassGetOpt* getopt);
+
+ // Parse one config string at a time, as you would normally do with main `argv`.
+ ADDAPI void ADDCALL sass_getopt_parse(struct SassGetOpt* getopt, const char* arg);
+
+ // Return string with the full help message describing all commands
+ // This is formatted in a similar fashion as GNU tools using getopt
+ ADDAPI char* ADDCALL sass_getopt_get_help(struct SassGetOpt* getopt);
+
+ // Register additional option that can be parsed
+ ADDAPI void ADDCALL sass_getopt_register_option(struct SassGetOpt* getopt,
+ // Short and long parameter names
+ const char short_name,
+ const char* long_name,
+ // Description used in help/usage message
+ const char* description,
+ // Whether to act like a boolean
+ const bool boolean,
+ // Name of required argument
+ const char* argument,
+ // Make argument optional
+ const bool optional,
+ // Arguments must be one of this enum
+ const struct SassGetOptEnum* enums,
+ // Callback function, where we pass back the given option value
+ void (*cb) (struct SassGetOpt* getopt, union SassOptionValue value));
+
+ // Register additional argument that can be parsed
+ ADDAPI void ADDCALL sass_getopt_register_argument(struct SassGetOpt* getopt,
+ // Whether this argument is optional
+ bool optional,
+ // Name used in messages
+ const char* name,
+ // Callback function, where we pass back the given argument value
+ void (*cb) (struct SassGetOpt* getopt, const char* value));
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+} // __cplusplus defined.
+#endif
+
+#endif
diff --git a/include/sass/import.h b/include/sass/import.h
new file mode 100644
index 0000000000..01ea298ced
--- /dev/null
+++ b/include/sass/import.h
@@ -0,0 +1,89 @@
+/*****************************************************************************/
+/* Part of LibSass, released under the MIT license (See LICENSE.txt). */
+/*****************************************************************************/
+#ifndef SASS_C_IMPORT_H
+#define SASS_C_IMPORT_H
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ // Create import entry by reading from `stdin`.
+ ADDAPI struct SassImport* ADDCALL sass_make_stdin_import(const char* imp_path);
+
+ // Create import entry to load the passed input path.
+ ADDAPI struct SassImport* ADDCALL sass_make_file_import(const char* imp_path);
+
+ // Create import entry for the passed data with optional path.
+ // Note: we take ownership of the passed `content` memory.
+ ADDAPI struct SassImport* ADDCALL sass_make_content_import(char* content, const char* imp_path);
+
+ // Create single import entry returned by the custom importer inside the list.
+ // Note: source/srcmap can be empty to let LibSass do the file resolving.
+ // Note: we take ownership of the passed `source` and `srcmap` memory.
+ ADDAPI struct SassImport* ADDCALL sass_make_import(const char* imp_path, const char* abs_base,
+ char* source, char* srcmap, enum SassImportSyntax format);
+
+ // Just in case we have some stray import structs
+ ADDAPI void ADDCALL sass_delete_import(struct SassImport* import);
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ // Getter for specific import format for the given import (force css/sass/scss or set to auto)
+ ADDAPI enum SassImportSyntax ADDCALL sass_import_get_type(const struct SassImport* import);
+
+ // Setter for specific import format for the given import (force css/sass/scss or set to auto)
+ ADDAPI void ADDCALL sass_import_set_syntax(struct SassImport* import, enum SassImportSyntax syntax);
+
+ // Getter for original import path (as seen when parsed)
+ ADDAPI const char* ADDCALL sass_import_get_imp_path(const struct SassImport* import);
+
+ // Getter for resolve absolute path (after being resolved)
+ ADDAPI const char* ADDCALL sass_import_get_abs_path(const struct SassImport* import);
+
+ // Getter for import error message (used by custom importers).
+ // If error is not `nullptr`, the import must be considered as failed.
+ ADDAPI const char* ADDCALL sass_import_get_error_message(struct SassImport* import);
+
+ // Setter for import error message (used by custom importers).
+ // If error is not `nullptr`, the import must be considered as failed.
+ ADDAPI void ADDCALL sass_import_set_error_message(struct SassImport* import, const char* msg);
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ // Create new list container for imports.
+ ADDAPI struct SassImportList* ADDCALL sass_make_import_list();
+
+ // Release memory of list container and all children.
+ ADDAPI void ADDCALL sass_delete_import_list(struct SassImportList* list);
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ // Return number of items currently in the list.
+ ADDAPI size_t ADDCALL sass_import_list_size(struct SassImportList* list);
+
+ // Remove and return first item in the list (as in a fifo queue).
+ ADDAPI struct SassImport* ADDCALL sass_import_list_shift(struct SassImportList* list);
+
+ // Append additional import to the list container.
+ ADDAPI void ADDCALL sass_import_list_push(struct SassImportList* list, struct SassImport* import);
+
+ // Append additional import to the list container and takes ownership of the import.
+ ADDAPI void ADDCALL sass_import_list_emplace(struct SassImportList* list, struct SassImport* import);
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+} // __cplusplus defined.
+#endif
+
+#endif
diff --git a/include/sass/importer.h b/include/sass/importer.h
new file mode 100644
index 0000000000..2f49120fb9
--- /dev/null
+++ b/include/sass/importer.h
@@ -0,0 +1,51 @@
+/*****************************************************************************/
+/* Part of LibSass, released under the MIT license (See LICENSE.txt). */
+/*****************************************************************************/
+#ifndef SASS_C_IMPORTER_H
+#define SASS_C_IMPORTER_H
+
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ // Type definitions for importer functions
+ typedef struct SassImportList* (*SassImporterLambda)(
+ const char* url, struct SassImporter* cb, struct SassCompiler* compiler);
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ // Create custom importer (with arbitrary data pointer called `cookie`)
+ // The pointer is often used to store the callback into the actual binding.
+ ADDAPI struct SassImporter* ADDCALL sass_make_importer(
+ SassImporterLambda lambda, double priority, void* cookie);
+
+ // Deallocate the importer and release memory
+ ADDAPI void ADDCALL sass_delete_importer(struct SassImporter* cb);
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ // Getter for importer lambda function (the one being actually invoked)
+ ADDAPI SassImporterLambda ADDCALL sass_importer_get_lambda(struct SassImporter* cb);
+
+ // Getter for importer priority (lowest priority is invoked first)
+ ADDAPI double ADDCALL sass_importer_get_priority(struct SassImporter* cb);
+
+ // Getter for arbitrary cookie (used by implementers to store stuff)
+ ADDAPI void* ADDCALL sass_importer_get_cookie(struct SassImporter* cb);
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+} // __cplusplus defined.
+#endif
+
+#endif
diff --git a/include/sass/traces.h b/include/sass/traces.h
new file mode 100644
index 0000000000..8949aff578
--- /dev/null
+++ b/include/sass/traces.h
@@ -0,0 +1,84 @@
+/*****************************************************************************/
+/* Part of LibSass, released under the MIT license (See LICENSE.txt). */
+/*****************************************************************************/
+#ifndef SASS_TRACES_H
+#define SASS_TRACES_H
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ // Traces must be got directly from the underlying object. We expose
+ // traces during eval (BackTraces) and when handling error (StackTraces).
+
+ /////////////////////////////////////////////////////////////////////////
+ // Implementation related to struct SassTrace
+ /////////////////////////////////////////////////////////////////////////
+
+ // Getter for name of this trace (normally the function name or empty).
+ ADDAPI const char* ADDCALL sass_trace_get_name(struct SassTrace* trace);
+
+ // Getter to check if trace is from a function call (otherwise import).
+ ADDAPI bool ADDCALL sass_trace_was_fncall(struct SassTrace* trace);
+
+ // Getter for the SourceSpan (aka ParserState) for further details
+ ADDAPI const struct SassSrcSpan* ADDCALL sass_trace_get_srcspan(struct SassTrace* trace);
+
+ /////////////////////////////////////////////////////////////////////////
+ // Implementation related to struct SassSrcSpan
+ /////////////////////////////////////////////////////////////////////////
+
+ // Getter for line position of trace (starting from 0)
+ ADDAPI size_t ADDCALL sass_srcspan_get_src_ln(struct SassSrcSpan* pstate);
+
+ // Getter for column position of trace (starting from 0)
+ ADDAPI size_t ADDCALL sass_srcspan_get_src_col(struct SassSrcSpan* pstate);
+
+ // Getter for line position of trace (starting from 1)
+ ADDAPI size_t ADDCALL sass_srcspan_get_src_line(struct SassSrcSpan* pstate);
+
+ // Getter for column position of trace (starting from 1)
+ ADDAPI size_t ADDCALL sass_srcspan_get_src_column(struct SassSrcSpan* pstate);
+
+ // Getter for line span of trace (starting from 0)
+ ADDAPI size_t ADDCALL sass_srcspan_get_span_ln(struct SassSrcSpan* pstate);
+
+ // Getter for column span of trace (starting from 0)
+ ADDAPI size_t ADDCALL sass_srcspan_get_span_col(struct SassSrcSpan* pstate);
+
+ // Getter for attached source of trace for further details
+ ADDAPI struct SassSource* ADDCALL sass_srcspan_get_source(struct SassSrcSpan* pstate);
+
+ /////////////////////////////////////////////////////////////////////////
+ // Implementation related to struct SassSource
+ /////////////////////////////////////////////////////////////////////////
+
+ // Getter for absolute path this source was loaded from. This path should
+ // always be absolute but there is no real hard requirement for it. Custom
+ // importers may use different pattern for paths. LibSass tries to support
+ // regular win/nix paths and urls. But we it also try to be agnostic here,
+ // so anything a custom importer returns will be returned here.
+ ADDAPI const char* ADDCALL sass_source_get_abs_path(struct SassSource* source);
+
+ // Getter for import path this source was loaded from. This path should
+ // be as it was found when the import was parsed. This is merely useful
+ // for debugging purposes, but we keep it around anyway.
+ ADDAPI const char* ADDCALL sass_source_get_imp_path(struct SassSource* source);
+
+ // Getter for the loaded content attached to the source.
+ ADDAPI const char* ADDCALL sass_source_get_content(struct SassSource* source);
+
+ // Getter for the loaded srcmap attached to the source.
+ // Note: not used yet, only here for future improvements.
+ 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..feafc5a508 100644
--- a/include/sass/values.h
+++ b/include/sass/values.h
@@ -1,142 +1,187 @@
-#ifndef SASS_C_VALUES_H
-#define SASS_C_VALUES_H
+/*****************************************************************************/
+/* Part of LibSass, released under the MIT license (See LICENSE.txt). */
+/*****************************************************************************/
+#ifndef SASS_VALUES_H
+#define SASS_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 pointers are often RefCounted, 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 a container, the actual destruction of the original is skipped.
+
+// ToDo: how should we handle sass colors now that we have RGBA, HSLA and HWBA format?
+
#ifdef __cplusplus
extern "C" {
#endif
-
-// Forward declaration
-union Sass_Value;
-
-// Type for Sass values
-enum Sass_Tag {
- SASS_BOOLEAN,
- SASS_NUMBER,
- SASS_COLOR,
- SASS_STRING,
- SASS_LIST,
- SASS_MAP,
- SASS_NULL,
- SASS_ERROR,
- SASS_WARNING
-};
-
-// Tags for denoting Sass list separators
-enum Sass_Separator {
- 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
-};
-
-// Value Operators
-enum Sass_OP {
- AND, OR, // 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
-};
-
-// 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);
-
-// 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);
-
-// Make a deep cloned copy of the given sass value
-ADDAPI union Sass_Value* ADDCALL sass_clone_value (const union Sass_Value* 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);
-
-// 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);
-
-// 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);
-
-// 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);
-
-// 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);
-
-// 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);
-
-// 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);
-
-// 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);
-// Getters and setters for Sass_List
-ADDAPI enum Sass_Separator ADDCALL sass_list_get_separator (const union Sass_Value* v);
-ADDAPI void ADDCALL sass_list_set_separator (union Sass_Value* v, enum Sass_Separator value);
-ADDAPI bool ADDCALL sass_list_get_is_bracketed (const union Sass_Value* v);
-ADDAPI void ADDCALL sass_list_set_is_bracketed (union Sass_Value* v, bool value);
-// Getters and setters for Sass_List values
-ADDAPI union Sass_Value* ADDCALL sass_list_get_value (const union Sass_Value* v, size_t i);
-ADDAPI void ADDCALL sass_list_set_value (union Sass_Value* v, size_t i, union Sass_Value* value);
-
-// Getter for the number of items in map
-ADDAPI size_t ADDCALL sass_map_get_length (const union Sass_Value* v);
-// 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*);
-
-// 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);
-
-// 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);
+ // Type of Sass values
+ enum SassValueType {
+ SASS_BOOLEAN,
+ SASS_NUMBER,
+ SASS_COLOR,
+ SASS_STRING,
+ SASS_LIST,
+ SASS_MAP,
+ SASS_NULL,
+ SASS_ERROR,
+ SASS_WARNING,
+ SASS_FUNCTION,
+ SASS_CALCULATION,
+ SASS_CALC_OPERATION,
+ SASS_MIXIN
+ };
+
+ // List separators
+ enum SassSeparator {
+ SASS_COMMA,
+ SASS_SPACE,
+ SASS_DIV,
+ // 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 SassOperator {
+ OR, AND, // logical connectives
+ EQ, NEQ, GT, GTE, LT, LTE, // arithmetic relations
+ ADD, SUB, MUL, DIV, MOD, // arithmetic functions
+ ASSIGN, IESEQ // special IE single equal
+ };
+
+ // Creator functions for all value types
+ 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_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(void);
+ 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 SassValue children
+ // Means we will delete recursively for lists and maps
+ ADDAPI void ADDCALL sass_delete_value(struct SassValue* val);
+
+ // Make a deep cloned copy of the given sass value
+ 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 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 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 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(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(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(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(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(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 SassSeparator ADDCALL sass_list_get_separator(struct SassValue* v);
+ ADDAPI void ADDCALL sass_list_set_separator(struct SassValue* v, enum SassSeparator separator);
+ 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 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_size (struct SassValue* v);
+
+ ADDAPI void ADDCALL sass_map_set(struct SassValue* m, struct SassValue* k, struct SassValue* v);
+
+ 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 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 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 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/variable.h b/include/sass/variable.h
new file mode 100644
index 0000000000..5fbd925e38
--- /dev/null
+++ b/include/sass/variable.h
@@ -0,0 +1,41 @@
+/*****************************************************************************/
+/* Part of LibSass, released under the MIT license (See LICENSE.txt). */
+/*****************************************************************************/
+#ifndef SASS_VARIABLE_H
+#define SASS_VARIABLE_H
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+ // Getter for lexical variable (lexical to scope where function is called).
+ // Note: C-API function can only access existing variables and not create new ones!
+ ADDAPI struct SassValue* ADDCALL sass_env_get_lexical (struct SassCompiler* compiler, const char* name);
+
+ // Setter for lexical variable (lexical to scope where function is called).
+ // Returns true if variable was set or false if it does not exist (we can't create it)
+ // Note: C-API function can only access existing variables and not create new ones!
+ ADDAPI bool ADDCALL sass_env_set_lexical(struct SassCompiler* compiler, const char* name, struct SassValue* value);
+
+ // Getter for global variable (only variables on the root scope are considered).
+ // Note: C-API function can only access existing variables and not create new ones!
+ ADDAPI struct SassValue* ADDCALL sass_env_get_global (struct SassCompiler* compiler, const char* name);
+
+ // Setter for global variable (only variables on the root scope are considered).
+ // Returns true if variable was set or false if it does not exist (we can't create it)
+ // Note: C-API function can only access existing variables and not create new ones!
+ ADDAPI bool ADDCALL sass_env_set_global(struct SassCompiler* compiler, const char* name, struct SassValue* value);
+
+ /////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+} // EO extern "C".
+#endif
+
+#endif
diff --git a/include/sass/version.h b/include/sass/version.h
index 56ea016a25..bfa5509aed 100644
--- a/include/sass/version.h
+++ b/include/sass/version.h
@@ -1,12 +1,18 @@
+/*****************************************************************************/
+/* Part of LibSass, released under the MIT license (See LICENSE.txt). */
+/*****************************************************************************/
#ifndef SASS_VERSION_H
#define SASS_VERSION_H
-
+
+// In order to report something useful this constant must be
+// passed during compilation (e.g. -DLIBSASS_VERSION=\"x.y.z\").
+// Note: what you pass must be a valid string with quotes!
#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..8b2d1c81b5 100644
--- a/include/sass/version.h.in
+++ b/include/sass/version.h.in
@@ -1,12 +1,18 @@
-#ifndef SASS_VERSION_H
-#define SASS_VERSION_H
+/*****************************************************************************/
+/* Part of LibSass, released under the MIT license (See LICENSE.txt). */
+/*****************************************************************************/
+#ifndef SASS_VERSION_IN_H
+#define SASS_VERSION_IN_H
+// In order to report something useful this constant must be
+// passed during compilation (e.g. -DLIBSASS_VERSION=\"x.y.z\").
+// Note: what you pass must be a valid string with quotes!
#ifndef LIBSASS_VERSION
#define LIBSASS_VERSION "@PACKAGE_VERSION@"
#endif
#ifndef LIBSASS_LANGUAGE_VERSION
-#define LIBSASS_LANGUAGE_VERSION "3.5"
+#define LIBSASS_LANGUAGE_VERSION "3.9"
#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/res/resource.rc b/res/resource.rc
index bfbb2c2e09..17289a7117 100644
--- a/res/resource.rc
+++ b/res/resource.rc
@@ -20,12 +20,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Sass Open Source Foundation"
VALUE "FileDescription", "A C/C++ implementation of a Sass compiler"
- VALUE "FileVersion", "1.0.0.0"
+ VALUE "FileVersion", "2.0.0.0"
VALUE "InternalName", "libsass"
- VALUE "LegalCopyright", "\251 2017 sass-lang.org"
+ VALUE "LegalCopyright", "\251 2021 libsass.org"
VALUE "OriginalFilename", "libsass.dll"
VALUE "ProductName", "LibSass Library"
- VALUE "ProductVersion", "1.0.0.0"
+ VALUE "ProductVersion", "2.0.0.0"
END
END
BLOCK "VarFileInfo"
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 84f25e00cb..fbb98d242f 100755
--- a/script/ci-build-libsass
+++ b/script/ci-build-libsass
@@ -44,15 +44,15 @@ fi
if [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then
MAKE_OPTS="$MAKE_OPTS -j1 V=1"
else
- MAKE_OPTS="$MAKE_OPTS -j5 V=1"
+ MAKE_OPTS="$MAKE_OPTS -j8 V=1"
fi
if [ "x$PREFIX" == "x" ]; then
- if [ "x$TRAVIS_BUILD_DIR" == "x" ]; then
- PREFIX=$SASS_LIBSASS_PATH/build
- else
- PREFIX=$TRAVIS_BUILD_DIR/build
- fi
+ #if [ "x$TRAVIS_BUILD_DIR" == "x" ]; then
+ PREFIX=$SASS_LIBSASS_PATH/installed
+ #else
+ # PREFIX=$TRAVIS_BUILD_DIR/build
+ #fi
fi
# enable address sanitation
@@ -60,9 +60,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
@@ -71,13 +71,19 @@ echo SASS_LIBSASS_PATH: $SASS_LIBSASS_PATH
echo TRAVIS_BUILD_DIR: $TRAVIS_BUILD_DIR
echo SASS_SASSC_PATH: $SASS_SASSC_PATH
echo SASS_SPEC_PATH: $SASS_SPEC_PATH
+echo EXTRA_CFLAGS: $EXTRA_CFLAGS
+echo EXTRA_CXXFLAGS: $EXTRA_CXXFLAGS
+echo EXTRA_LDFLAGS: $EXTRA_LDFLAGS
+echo MAKE_OPTS: $MAKE_OPTS
echo INSTALL_LOCATION: $PREFIX
if [ "x$AUTOTOOLS" == "xyes" ]; then
echo -en 'travis_fold:start:configure\r'
autoreconf --force --install
- ./configure --enable-tests $COVERAGE_OPT \
+ mkdir -p build
+ cd build
+ ../configure --enable-tests $COVERAGE_OPT \
--disable-silent-rules \
--with-sassc-dir=$SASS_SASSC_PATH \
--with-sass-spec-dir=$SASS_SPEC_PATH \
@@ -85,20 +91,29 @@ if [ "x$AUTOTOOLS" == "xyes" ]; then
${SHARED_OPT}
echo -en 'travis_fold:end:configure\r'
- make $MAKE_OPTS clean
+ echo "MAKE CLEAN"
+
+ PREFIX="$PREFIX" make $MAKE_OPTS clean
+
+ echo "MAKE INSTALL"
+
+ # install to prefix directory
+ PREFIX="$PREFIX" make $MAKE_OPTS install
+
+ cd ..
else
- make $MAKE_OPTS clean
+ PREFIX="$PREFIX" make $MAKE_OPTS clean
# Run C++ unit tests
- make $MAKE_OPTS -C test clean
- make $MAKE_OPTS -C test test
+ # make $MAKE_OPTS -C test clean
+ # make $MAKE_OPTS -C test test
-fi
+ # install to prefix directory
+ PREFIX="$PREFIX" make $MAKE_OPTS install
-# install to prefix directory
-PREFIX="$PREFIX" make $MAKE_OPTS install
+fi
ls -la $PREFIX/*
@@ -109,28 +124,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/refactor/libsass-4-alpha
+ 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..107015c326 100755
--- a/script/ci-build-plugin
+++ b/script/ci-build-plugin
@@ -34,11 +34,7 @@ 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
- else
- git clone https://github.com/mgreter/libsass-${PLUGIN} plugins/libsass-${PLUGIN}
- fi
+ git clone https://github.com/mgreter/libsass-${PLUGIN} plugins/libsass-${PLUGIN} --branch feature/libsass-4.0
fi
if [ ! -d plugins/libsass-${PLUGIN}/build ] ; then
mkdir plugins/libsass-${PLUGIN}/build
@@ -54,11 +50,11 @@ cd ../../..
# glob only works on paths relative to imports
if [ "x$PLUGIN" == "xglob" ]; then
- ${SASSC_BIN} --precision 5 --plugin-path plugins/libsass-${PLUGIN}/build ${SASS_SPEC_SPEC_DIR}/basic/input.scss > ${SASS_SPEC_SPEC_DIR}/basic/result.css
- ${SASSC_BIN} --precision 5 --plugin-path plugins/libsass-${PLUGIN}/build ${SASS_SPEC_SPEC_DIR}/basic/input.scss --sourcemap > /dev/null
+ ${SASSC_BIN} --precision 10 --plugin-path plugins/libsass-${PLUGIN}/build ${SASS_SPEC_SPEC_DIR}/basic/input.scss > ${SASS_SPEC_SPEC_DIR}/basic/result.css
+ # ${SASSC_BIN} --precision 10 --plugin-path plugins/libsass-${PLUGIN}/build ${SASS_SPEC_SPEC_DIR}/basic/input.scss --sourcemap > /dev/null
else
cat ${SASS_SPEC_SPEC_DIR}/basic/input.scss | ${SASSC_BIN} --precision 5 --plugin-path plugins/libsass-${PLUGIN}/build -I ${SASS_SPEC_SPEC_DIR}/basic > ${SASS_SPEC_SPEC_DIR}/basic/result.css
- cat ${SASS_SPEC_SPEC_DIR}/basic/input.scss | ${SASSC_BIN} --precision 5 --plugin-path plugins/libsass-${PLUGIN}/build -I ${SASS_SPEC_SPEC_DIR}/basic --sourcemap > /dev/null
+ # cat ${SASS_SPEC_SPEC_DIR}/basic/input.scss | ${SASSC_BIN} --precision 5 --plugin-path plugins/libsass-${PLUGIN}/build -I ${SASS_SPEC_SPEC_DIR}/basic --sourcemap > /dev/null
fi
RETVAL=$?; if [ "$RETVAL" != "0" ]; then exit $RETVAL; fi
diff --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..59703e19bc 100644
--- a/src/GNUmakefile.am
+++ b/src/GNUmakefile.am
@@ -30,7 +30,7 @@ include $(top_srcdir)/Makefile.conf
libsass_la_SOURCES = ${CSOURCES} ${SOURCES}
-libsass_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 1:0:0
+libsass_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 2:0:0
if ENABLE_TESTS
if ENABLE_COVERAGE
@@ -38,13 +38,19 @@ 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
sass_include_HEADERS = $(top_srcdir)/include/sass/base.h \
+ $(top_srcdir)/include/sass/compiler.h \
+ $(top_srcdir)/include/sass/enums.h \
+ $(top_srcdir)/include/sass/error.h \
+ $(top_srcdir)/include/sass/function.h \
+ $(top_srcdir)/include/sass/fwdecl.h \
+ $(top_srcdir)/include/sass/import.h \
+ $(top_srcdir)/include/sass/importer.h \
+ $(top_srcdir)/include/sass/traces.h \
$(top_srcdir)/include/sass/values.h \
- $(top_srcdir)/include/sass/version.h \
- $(top_srcdir)/include/sass/context.h \
- $(top_srcdir)/include/sass/functions.h
+ $(top_srcdir)/include/sass/variable.h \
+ $(top_srcdir)/include/sass/version.h
diff --git a/src/MurmurHash2.hpp b/src/MurmurHash2.hpp
index ab9b1634c6..5e70fae12f 100644
--- a/src/MurmurHash2.hpp
+++ b/src/MurmurHash2.hpp
@@ -1,15 +1,17 @@
-//-----------------------------------------------------------------------------
-// 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_
-
-//-----------------------------------------------------------------------------
+/*****************************************************************************/
+/* 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 SASS_MURMURHASH2_HPP
+#define SASS_MURMURHASH2_HPP
+
+/////////////////////////////////////////////////////////////////////////
// Platform-specific functions and macros
+/////////////////////////////////////////////////////////////////////////
// Microsoft Visual Studio
@@ -23,11 +25,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 +88,8 @@ inline uint32_t MurmurHash2 ( const void * key, int len, uint32_t seed )
return h;
}
-//-----------------------------------------------------------------------------
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
-#endif // _MURMURHASH2_H_
+#endif
diff --git a/src/ast.cpp b/src/ast.cpp
index 2c0dd64c94..7dde73c3db 100644
--- a/src/ast.cpp
+++ b/src/ast.cpp
@@ -1,953 +1,151 @@
-// 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;
- }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
+#include "cssize.hpp"
+#include "inspect.hpp"
+#include "exceptions.hpp"
+#include "dart_helpers.hpp"
- 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_)
- { }
+#include "debugger.hpp"
- 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();
- }
+namespace Sass {
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
- 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;
- }
+ // 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[16] = {
+ "or", "and", "eq", "neq", "gt", "gte", "lt", "lte",
+ "plus", "minus", "times", "div", "mod", "seq", "ieseq", "invalid"
+ };
- 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_)
- { }
+ // Needs to be in sync with SassOp enum
+ const char* SassOpOperator[16] = {
+ "||", "&&", "==", "!=", ">", ">=", "<", "<=",
+ "+", "-", "*", "/", "%", "=", "=", "invalid"
+ };
- bool Bubble::bubbles()
+ // Precedence is used to decide order
+ // in ExpressionParser::addOperator.
+ uint8_t sass_op_to_precedence(enum SassOperator op)
{
- 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;
+ return SassOpPresedence[op];
}
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- 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
+ // Get readable name for error messages
+ const char* sass_op_to_name(enum SassOperator op)
{
- if (is_custom_property()) return false;
- return !(value_ && !Cast(value_));
+ return SassOpName[op];
}
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- 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); }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- 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); }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- 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
+ // Get readable name for operator (e.g. `==`)
+ const char* sass_op_separator(enum SassOperator op)
{
- return false;
+ return SassOpOperator[op];
}
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- 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); }
-
- bool If::has_content()
+ // Get readable name for list operator (e.g. `,`, `/` or ` `)
+ const char* sass_list_separator(enum SassSeparator op)
{
- return ParentStatement::has_content() || (alternative_ && alternative_->has_content());
- }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- 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)
- {
- statement_type(EXTEND);
- }
- 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;
+ switch (op) {
+ case SASS_COMMA: return ", ";
+ case SASS_SPACE: return " ";
+ case SASS_DIV: return " / ";
+ default: return "";
}
- catch (...) { throw; }
- }
- size_t Unary_Expression::hash() const
- {
- if (hash_ == 0) {
- hash_ = std::hash()(optype_);
- hash_combine(hash_, operand()->hash());
- };
- return hash_;
}
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
- 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_);
- }
+ OutputOptions out(
+ SASS_STYLE_NESTED,
+ precision);
+ Inspect i(out);
+ i.inspect = true;
+ // Inspect must be const, accept isn't
+ const_cast(this)->accept(&i);
+ return i.get_buffer();
}
- void Argument::set_delayed(bool delayed)
+ sass::string Value::inspect(int precision, bool quotes) const
{
- if (value_) value_->set_delayed(delayed);
- is_delayed(delayed);
+ OutputOptions out(
+ SASS_STYLE_NESTED,
+ precision);
+ Inspect i(out);
+ i.inspect = true;
+ i.quotes = quotes;
+ // Inspect must be const, accept isn't
+ const_cast(this)->accept(&i);
+ return i.get_buffer();
}
- bool Argument::operator==(const Expression& rhs) 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; }
+ AstNode* Value::simplify(Logger& logger) {
+ callStackFrame frame(logger, pstate());
+ throw Exception::SassScriptException(logger, pstate(),
+ "Value " + inspect() + " can't be used in a calculation.");
}
- size_t Argument::hash() const
+ sass::string Value::toCss(bool quote) const
{
- if (hash_ == 0) {
- hash_ = std::hash()(name());
- hash_combine(hash_, value()->hash());
- }
- return hash_;
- }
-
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- 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);
+ OutputOptions out(
+ SASS_STYLE_TO_CSS,
+ SassDefaultPrecision);
+ Cssize i(out);
+ i.quotes = quote;
+ // Inspect must be const, accept isn't
+ const_cast(this)->accept(&i);
+ return i.get_buffer();
}
- Argument_Obj Arguments::get_rest_argument()
- {
- if (this->has_rest_argument()) {
- for (Argument_Obj arg : this->elements()) {
- if (arg->is_rest_argument()) {
- return arg;
- }
- }
- }
- return {};
- }
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
- Argument_Obj Arguments::get_keyword_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_keyword_argument()) {
- for (Argument_Obj arg : this->elements()) {
- if (arg->is_keyword_argument()) {
- return arg;
- }
- }
- }
- return {};
+ // Check out of boundary access
+ sassIndexToListIndex(index, logger, "n");
+ // Return single value
+ return this;
}
- void Arguments::adjust_after_pushing(Argument_Obj a)
+ // 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 (!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());
- }
- }
+ return getPairAsList(sassIndexToListIndex(index, logger, "n"));
}
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- 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)
- {
- 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;
- }
+ // Search the position of the given value
+ size_t List::indexOf(Value* value) {
+ return Sass::indexOf(elements(), value);
}
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- 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)
+ // 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)
{
- 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());
- }
- }
+ return get(sassIndexToListIndex(index, logger, "n"));
}
- /////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////
-
- // 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..8c599f3218 100644
--- a/src/ast.hpp
+++ b/src/ast.hpp
@@ -1,1064 +1,25 @@
-#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_imports.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