sassc 1.7.1 → 1.8.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -1
  3. data/ext/libsass/.gitignore +10 -6
  4. data/ext/libsass/.travis.yml +4 -1
  5. data/ext/libsass/GNUmakefile.am +88 -0
  6. data/ext/libsass/Makefile +157 -76
  7. data/ext/libsass/Makefile.conf +47 -0
  8. data/ext/libsass/Readme.md +13 -14
  9. data/ext/libsass/appveyor.yml +25 -41
  10. data/ext/libsass/configure.ac +20 -7
  11. data/ext/libsass/contrib/plugin.cpp +1 -1
  12. data/ext/libsass/include/sass.h +15 -0
  13. data/ext/libsass/{sass.h → include/sass/base.h} +17 -9
  14. data/ext/libsass/{sass_context.h → include/sass/context.h} +3 -1
  15. data/ext/libsass/{sass_functions.h → include/sass/functions.h} +4 -4
  16. data/ext/libsass/{sass_interface.h → include/sass/interface.h} +5 -2
  17. data/ext/libsass/{sass_values.h → include/sass/values.h} +15 -1
  18. data/ext/libsass/{sass_version.h → include/sass/version.h} +0 -0
  19. data/ext/libsass/{sass_version.h.in → include/sass/version.h.in} +0 -0
  20. data/ext/libsass/{sass2scss.h → include/sass2scss.h} +6 -7
  21. data/ext/libsass/m4/m4-ax_cxx_compile_stdcxx_11.m4 +167 -0
  22. data/ext/libsass/script/ci-build-libsass +67 -23
  23. data/ext/libsass/src/GNUmakefile.am +54 -0
  24. data/ext/libsass/src/ast.cpp +2029 -0
  25. data/ext/libsass/{ast.hpp → src/ast.hpp} +832 -660
  26. data/ext/libsass/src/ast_def_macros.hpp +47 -0
  27. data/ext/libsass/src/ast_factory.hpp +93 -0
  28. data/ext/libsass/{ast_fwd_decl.hpp → src/ast_fwd_decl.hpp} +9 -4
  29. data/ext/libsass/{b64 → src/b64}/cencode.h +1 -1
  30. data/ext/libsass/{b64 → src/b64}/encode.h +0 -0
  31. data/ext/libsass/{backtrace.hpp → src/backtrace.hpp} +9 -10
  32. data/ext/libsass/{base64vlq.cpp → src/base64vlq.cpp} +2 -2
  33. data/ext/libsass/{base64vlq.hpp → src/base64vlq.hpp} +1 -2
  34. data/ext/libsass/{bind.cpp → src/bind.cpp} +96 -59
  35. data/ext/libsass/{bind.hpp → src/bind.hpp} +1 -1
  36. data/ext/libsass/src/c99func.c +54 -0
  37. data/ext/libsass/{cencode.c → src/cencode.c} +5 -5
  38. data/ext/libsass/src/color_maps.cpp +643 -0
  39. data/ext/libsass/src/color_maps.hpp +333 -0
  40. data/ext/libsass/{constants.cpp → src/constants.cpp} +10 -1
  41. data/ext/libsass/{constants.hpp → src/constants.hpp} +7 -0
  42. data/ext/libsass/{context.cpp → src/context.cpp} +152 -122
  43. data/ext/libsass/src/context.hpp +150 -0
  44. data/ext/libsass/{cssize.cpp → src/cssize.cpp} +123 -109
  45. data/ext/libsass/{cssize.hpp → src/cssize.hpp} +9 -13
  46. data/ext/libsass/{debug.hpp → src/debug.hpp} +9 -9
  47. data/ext/libsass/src/debugger.hpp +683 -0
  48. data/ext/libsass/{emitter.cpp → src/emitter.cpp} +13 -13
  49. data/ext/libsass/{emitter.hpp → src/emitter.hpp} +10 -11
  50. data/ext/libsass/src/environment.cpp +184 -0
  51. data/ext/libsass/src/environment.hpp +92 -0
  52. data/ext/libsass/src/error_handling.cpp +46 -0
  53. data/ext/libsass/src/error_handling.hpp +34 -0
  54. data/ext/libsass/src/eval.cpp +1462 -0
  55. data/ext/libsass/src/eval.hpp +107 -0
  56. data/ext/libsass/src/expand.cpp +653 -0
  57. data/ext/libsass/{expand.hpp → src/expand.hpp} +17 -16
  58. data/ext/libsass/{extend.cpp → src/extend.cpp} +198 -139
  59. data/ext/libsass/{extend.hpp → src/extend.hpp} +7 -8
  60. data/ext/libsass/{file.cpp → src/file.cpp} +103 -57
  61. data/ext/libsass/{file.hpp → src/file.hpp} +23 -14
  62. data/ext/libsass/{functions.cpp → src/functions.cpp} +642 -333
  63. data/ext/libsass/{functions.hpp → src/functions.hpp} +17 -4
  64. data/ext/libsass/{inspect.cpp → src/inspect.cpp} +147 -260
  65. data/ext/libsass/{inspect.hpp → src/inspect.hpp} +7 -7
  66. data/ext/libsass/{json.cpp → src/json.cpp} +33 -43
  67. data/ext/libsass/{json.hpp → src/json.hpp} +1 -1
  68. data/ext/libsass/{kwd_arg_macros.hpp → src/kwd_arg_macros.hpp} +0 -0
  69. data/ext/libsass/{lexer.cpp → src/lexer.cpp} +28 -0
  70. data/ext/libsass/{lexer.hpp → src/lexer.hpp} +25 -10
  71. data/ext/libsass/{listize.cpp → src/listize.cpp} +17 -13
  72. data/ext/libsass/{listize.hpp → src/listize.hpp} +0 -2
  73. data/ext/libsass/{mapping.hpp → src/mapping.hpp} +0 -0
  74. data/ext/libsass/src/memory_manager.cpp +76 -0
  75. data/ext/libsass/src/memory_manager.hpp +48 -0
  76. data/ext/libsass/{node.cpp → src/node.cpp} +89 -18
  77. data/ext/libsass/{node.hpp → src/node.hpp} +5 -6
  78. data/ext/libsass/{operation.hpp → src/operation.hpp} +18 -12
  79. data/ext/libsass/{output.cpp → src/output.cpp} +47 -55
  80. data/ext/libsass/{output.hpp → src/output.hpp} +5 -4
  81. data/ext/libsass/src/parser.cpp +2529 -0
  82. data/ext/libsass/{parser.hpp → src/parser.hpp} +84 -60
  83. data/ext/libsass/{paths.hpp → src/paths.hpp} +10 -13
  84. data/ext/libsass/{plugins.cpp → src/plugins.cpp} +14 -17
  85. data/ext/libsass/{plugins.hpp → src/plugins.hpp} +10 -11
  86. data/ext/libsass/{position.cpp → src/position.cpp} +5 -6
  87. data/ext/libsass/{position.hpp → src/position.hpp} +19 -22
  88. data/ext/libsass/{prelexer.cpp → src/prelexer.cpp} +401 -53
  89. data/ext/libsass/{prelexer.hpp → src/prelexer.hpp} +50 -10
  90. data/ext/libsass/{remove_placeholders.cpp → src/remove_placeholders.cpp} +12 -16
  91. data/ext/libsass/{remove_placeholders.hpp → src/remove_placeholders.hpp} +1 -7
  92. data/ext/libsass/{sass.cpp → src/sass.cpp} +3 -5
  93. data/ext/libsass/{sass2scss.cpp → src/sass2scss.cpp} +51 -46
  94. data/ext/libsass/{sass_context.cpp → src/sass_context.cpp} +114 -112
  95. data/ext/libsass/{sass_functions.cpp → src/sass_functions.cpp} +11 -18
  96. data/ext/libsass/{sass_interface.cpp → src/sass_interface.cpp} +44 -81
  97. data/ext/libsass/{sass_util.cpp → src/sass_util.cpp} +26 -8
  98. data/ext/libsass/{sass_util.hpp → src/sass_util.hpp} +14 -18
  99. data/ext/libsass/{sass_values.cpp → src/sass_values.cpp} +91 -20
  100. data/ext/libsass/{source_map.cpp → src/source_map.cpp} +13 -13
  101. data/ext/libsass/{source_map.hpp → src/source_map.hpp} +9 -9
  102. data/ext/libsass/{subset_map.hpp → src/subset_map.hpp} +29 -31
  103. data/ext/libsass/{support → src/support}/libsass.pc.in +0 -0
  104. data/ext/libsass/src/to_c.cpp +73 -0
  105. data/ext/libsass/src/to_c.hpp +41 -0
  106. data/ext/libsass/src/to_string.cpp +47 -0
  107. data/ext/libsass/{to_string.hpp → src/to_string.hpp} +9 -7
  108. data/ext/libsass/src/to_value.cpp +109 -0
  109. data/ext/libsass/src/to_value.hpp +50 -0
  110. data/ext/libsass/{units.cpp → src/units.cpp} +56 -51
  111. data/ext/libsass/{units.hpp → src/units.hpp} +8 -9
  112. data/ext/libsass/{utf8.h → src/utf8.h} +0 -0
  113. data/ext/libsass/{utf8 → src/utf8}/checked.h +0 -0
  114. data/ext/libsass/{utf8 → src/utf8}/core.h +12 -12
  115. data/ext/libsass/{utf8 → src/utf8}/unchecked.h +0 -0
  116. data/ext/libsass/{utf8_string.cpp → src/utf8_string.cpp} +0 -0
  117. data/ext/libsass/{utf8_string.hpp → src/utf8_string.hpp} +6 -6
  118. data/ext/libsass/{util.cpp → src/util.cpp} +144 -86
  119. data/ext/libsass/src/util.hpp +59 -0
  120. data/ext/libsass/src/values.cpp +137 -0
  121. data/ext/libsass/src/values.hpp +12 -0
  122. data/ext/libsass/test/test_node.cpp +33 -33
  123. data/ext/libsass/test/test_paths.cpp +5 -6
  124. data/ext/libsass/test/test_selector_difference.cpp +4 -5
  125. data/ext/libsass/test/test_specificity.cpp +4 -5
  126. data/ext/libsass/test/test_subset_map.cpp +91 -91
  127. data/ext/libsass/test/test_superselector.cpp +11 -11
  128. data/ext/libsass/test/test_unification.cpp +4 -4
  129. data/ext/libsass/win/libsass.targets +101 -0
  130. data/ext/libsass/win/libsass.vcxproj +45 -127
  131. data/ext/libsass/win/libsass.vcxproj.filters +303 -0
  132. data/lib/sassc/import_handler.rb +1 -1
  133. data/lib/sassc/native/native_functions_api.rb +3 -3
  134. data/lib/sassc/version.rb +1 -1
  135. data/test/custom_importer_test.rb +1 -4
  136. data/test/functions_test.rb +3 -2
  137. data/test/native_test.rb +4 -3
  138. metadata +117 -110
  139. data/ext/libsass/Makefile.am +0 -146
  140. data/ext/libsass/ast.cpp +0 -945
  141. data/ext/libsass/ast_def_macros.hpp +0 -21
  142. data/ext/libsass/ast_factory.hpp +0 -92
  143. data/ext/libsass/color_names.hpp +0 -327
  144. data/ext/libsass/context.hpp +0 -157
  145. data/ext/libsass/contextualize.cpp +0 -148
  146. data/ext/libsass/contextualize.hpp +0 -46
  147. data/ext/libsass/contextualize_eval.cpp +0 -93
  148. data/ext/libsass/contextualize_eval.hpp +0 -44
  149. data/ext/libsass/debugger.hpp +0 -558
  150. data/ext/libsass/environment.hpp +0 -163
  151. data/ext/libsass/error_handling.cpp +0 -35
  152. data/ext/libsass/error_handling.hpp +0 -32
  153. data/ext/libsass/eval.cpp +0 -1392
  154. data/ext/libsass/eval.hpp +0 -88
  155. data/ext/libsass/expand.cpp +0 -575
  156. data/ext/libsass/memory_manager.hpp +0 -57
  157. data/ext/libsass/parser.cpp +0 -2403
  158. data/ext/libsass/posix/getopt.c +0 -562
  159. data/ext/libsass/posix/getopt.h +0 -95
  160. data/ext/libsass/to_c.cpp +0 -61
  161. data/ext/libsass/to_c.hpp +0 -44
  162. data/ext/libsass/to_string.cpp +0 -34
  163. data/ext/libsass/util.hpp +0 -54
  164. data/ext/libsass/win/libsass.filters +0 -312
@@ -33,7 +33,6 @@
33
33
  #endif
34
34
 
35
35
  // using std::string
36
- using namespace std;
37
36
 
38
37
  // add namespace for c++
39
38
  namespace Sass
@@ -53,7 +52,7 @@ namespace Sass
53
52
  const int SASS2SCSS_CONVERT_COMMENT = 128;
54
53
 
55
54
  // String for finding something interesting
56
- const string SASS2SCSS_FIND_WHITESPACE = " \t\n\v\f\r";
55
+ const std::string SASS2SCSS_FIND_WHITESPACE = " \t\n\v\f\r";
57
56
 
58
57
  // converter struct
59
58
  // holding all states
@@ -70,17 +69,17 @@ namespace Sass
70
69
  // has semicolon
71
70
  bool semicolon;
72
71
  // comment context
73
- string comment;
72
+ std::string comment;
74
73
  // flag end of file
75
74
  bool end_of_file;
76
75
  // whitespace buffer
77
- string whitespace;
76
+ std::string whitespace;
78
77
  // context/block stack
79
- stack<string> indents;
78
+ std::stack<std::string> indents;
80
79
  };
81
80
 
82
81
  // function only available in c++ code
83
- char* sass2scss (const string sass, const int options);
82
+ char* sass2scss (const std::string& sass, const int options);
84
83
 
85
84
  }
86
85
  // EO namespace
@@ -112,4 +111,4 @@ extern "C" {
112
111
  } // __cplusplus defined.
113
112
  #endif
114
113
 
115
- #endif
114
+ #endif
@@ -0,0 +1,167 @@
1
+ # ============================================================================
2
+ # http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html
3
+ # ============================================================================
4
+ #
5
+ # SYNOPSIS
6
+ #
7
+ # AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional])
8
+ #
9
+ # DESCRIPTION
10
+ #
11
+ # Check for baseline language coverage in the compiler for the C++11
12
+ # standard; if necessary, add switches to CXXFLAGS to enable support.
13
+ #
14
+ # The first argument, if specified, indicates whether you insist on an
15
+ # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
16
+ # -std=c++11). If neither is specified, you get whatever works, with
17
+ # preference for an extended mode.
18
+ #
19
+ # The second argument, if specified 'mandatory' or if left unspecified,
20
+ # indicates that baseline C++11 support is required and that the macro
21
+ # should error out if no mode with that support is found. If specified
22
+ # 'optional', then configuration proceeds regardless, after defining
23
+ # HAVE_CXX11 if and only if a supporting mode is found.
24
+ #
25
+ # LICENSE
26
+ #
27
+ # Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
28
+ # Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
29
+ # Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
30
+ # Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
31
+ #
32
+ # Copying and distribution of this file, with or without modification, are
33
+ # permitted in any medium without royalty provided the copyright notice
34
+ # and this notice are preserved. This file is offered as-is, without any
35
+ # warranty.
36
+
37
+ #serial 11
38
+
39
+ m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[
40
+ template <typename T>
41
+ struct check
42
+ {
43
+ static_assert(sizeof(int) <= sizeof(T), "not big enough");
44
+ };
45
+
46
+ struct Base {
47
+ virtual void f() {}
48
+ };
49
+ struct Child : public Base {
50
+ virtual void f() override {}
51
+ };
52
+
53
+ typedef check<check<bool>> right_angle_brackets;
54
+
55
+ int a;
56
+ decltype(a) b;
57
+
58
+ typedef check<int> check_type;
59
+ check_type c;
60
+ check_type&& cr = static_cast<check_type&&>(c);
61
+
62
+ auto d = a;
63
+ auto l = [](){};
64
+ // Prevent Clang error: unused variable 'l' [-Werror,-Wunused-variable]
65
+ struct use_l { use_l() { l(); } };
66
+
67
+ // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
68
+ // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this
69
+ namespace test_template_alias_sfinae {
70
+ struct foo {};
71
+
72
+ template<typename T>
73
+ using member = typename T::member_type;
74
+
75
+ template<typename T>
76
+ void func(...) {}
77
+
78
+ template<typename T>
79
+ void func(member<T>*) {}
80
+
81
+ void test();
82
+
83
+ void test() {
84
+ func<foo>(0);
85
+ }
86
+ }
87
+ ]])
88
+
89
+ AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl
90
+ m4_if([$1], [], [],
91
+ [$1], [ext], [],
92
+ [$1], [noext], [],
93
+ [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl
94
+ m4_if([$2], [], [ax_cxx_compile_cxx11_required=true],
95
+ [$2], [mandatory], [ax_cxx_compile_cxx11_required=true],
96
+ [$2], [optional], [ax_cxx_compile_cxx11_required=false],
97
+ [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])])
98
+ AC_LANG_PUSH([C++])dnl
99
+ ac_success=no
100
+ AC_CACHE_CHECK(whether $CXX supports C++11 features by default,
101
+ ax_cv_cxx_compile_cxx11,
102
+ [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
103
+ [ax_cv_cxx_compile_cxx11=yes],
104
+ [ax_cv_cxx_compile_cxx11=no])])
105
+ if test x$ax_cv_cxx_compile_cxx11 = xyes; then
106
+ ac_success=yes
107
+ fi
108
+
109
+ m4_if([$1], [noext], [], [dnl
110
+ if test x$ac_success = xno; then
111
+ for switch in -std=gnu++11 -std=gnu++0x; do
112
+ cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
113
+ AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
114
+ $cachevar,
115
+ [ac_save_CXXFLAGS="$CXXFLAGS"
116
+ CXXFLAGS="$CXXFLAGS $switch"
117
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
118
+ [eval $cachevar=yes],
119
+ [eval $cachevar=no])
120
+ CXXFLAGS="$ac_save_CXXFLAGS"])
121
+ if eval test x\$$cachevar = xyes; then
122
+ CXXFLAGS="$CXXFLAGS $switch"
123
+ ac_success=yes
124
+ break
125
+ fi
126
+ done
127
+ fi])
128
+
129
+ m4_if([$1], [ext], [], [dnl
130
+ if test x$ac_success = xno; then
131
+ dnl HP's aCC needs +std=c++11 according to:
132
+ dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
133
+ for switch in -std=c++11 -std=c++0x +std=c++11; do
134
+ cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
135
+ AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
136
+ $cachevar,
137
+ [ac_save_CXXFLAGS="$CXXFLAGS"
138
+ CXXFLAGS="$CXXFLAGS $switch"
139
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
140
+ [eval $cachevar=yes],
141
+ [eval $cachevar=no])
142
+ CXXFLAGS="$ac_save_CXXFLAGS"])
143
+ if eval test x\$$cachevar = xyes; then
144
+ CXXFLAGS="$CXXFLAGS $switch"
145
+ ac_success=yes
146
+ break
147
+ fi
148
+ done
149
+ fi])
150
+ AC_LANG_POP([C++])
151
+ if test x$ax_cxx_compile_cxx11_required = xtrue; then
152
+ if test x$ac_success = xno; then
153
+ AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.])
154
+ fi
155
+ else
156
+ if test x$ac_success = xno; then
157
+ HAVE_CXX11=0
158
+ AC_MSG_NOTICE([No compiler with C++11 support was found])
159
+ else
160
+ HAVE_CXX11=1
161
+ AC_DEFINE(HAVE_CXX11,1,
162
+ [define if the compiler supports basic C++11 syntax])
163
+ fi
164
+
165
+ AC_SUBST(HAVE_CXX11)
166
+ fi
167
+ ])
@@ -36,49 +36,93 @@ else
36
36
  MAKE_OPTS="$MAKE_OPTS -j3 V=1"
37
37
  fi
38
38
 
39
+ if [ "x$PREFIX" == "x" ]; then
40
+ if [ "x$TRAVIS_BUILD_DIR" == "x" ]; then
41
+ PREFIX=$SASS_LIBSASS_PATH/build
42
+ else
43
+ PREFIX=$TRAVIS_BUILD_DIR/build
44
+ fi
45
+ fi
46
+
47
+ echo SASS_LIBSASS_PATH: $SASS_LIBSASS_PATH
48
+ echo TRAVIS_BUILD_DIR: $TRAVIS_BUILD_DIR
49
+ echo SASS_SASSC_PATH: $SASS_SASSC_PATH
50
+ echo SASS_SPEC_PATH: $SASS_SPEC_PATH
51
+ echo INSTALL_LOCATION: $PREFIX
52
+
39
53
  if [ "x$AUTOTOOLS" == "xyes" ]; then
40
54
 
41
55
  echo -en 'travis_fold:start:configure\r'
42
56
  autoreconf --force --install
43
57
  ./configure --enable-tests $COVERAGE_OPT \
44
- --prefix=build \
45
58
  --disable-silent-rules \
46
59
  --with-sassc-dir=$SASS_SASSC_PATH \
47
60
  --with-sass-spec-dir=$SASS_SPEC_PATH \
48
- --prefix=$TRAVIS_BUILD_DIR \
61
+ --prefix=$PREFIX \
49
62
  ${SHARED_OPT}
50
63
  echo -en 'travis_fold:end:configure\r'
51
64
 
52
- make clean
53
-
54
- make $MAKE_OPTS install
65
+ make clean $MAKE_OPTS
55
66
 
56
- if [ -d build/lib ]; then
57
- mkdir -p lib
58
- cp -a build/lib/* lib/
59
- fi
67
+ # install to prefix directory
68
+ PREFIX="$PREFIX" make install
60
69
 
61
70
  else
62
71
 
63
- make clean
72
+ make clean $MAKE_OPTS
64
73
 
65
- # does what $BUILD says
66
- make $MAKE_OPTS
74
+ fi
67
75
 
68
- # sassc has static as dep
69
- make $MAKE_OPTS $SASS_SASSC_PATH/bin/sassc
76
+ # install to prefix directory
77
+ PREFIX="$PREFIX" make install
70
78
 
71
- fi
79
+ ls -la $PREFIX/*
72
80
 
73
81
  echo successfully compiled libsass
74
82
  echo AUTOTOOLS=$AUTOTOOLS COVERAGE=$COVERAGE BUILD=$BUILD
75
83
 
76
- if [ "x$PREFIX" == "x" ]; then
77
- if [ "x$TRAVIS_BUILD_DIR" == "x" ]; then
78
- PREFIX=/usr/local
79
- else
80
- PREFIX=$TRAVIS_BUILD_DIR
81
- fi
82
- fi
84
+ if [ "$CONTINUOUS_INTEGRATION" == "true" ] && [ "$TRAVIS_PULL_REQUEST" != "false" ] && [ "$TRAVIS_OS_NAME" == "linux" ];
85
+ then
86
+ echo "Downloading jq"
87
+
88
+ curl http://stedolan.github.io/jq/download/linux64/jq > jq
89
+ chmod +x jq
90
+
91
+ echo "Fetching PR $TRAVIS_PULL_REQUEST"
92
+
93
+ JSON=$(curl -u xzyfer:882aeec2a5b847b7d67c61d7788c2721f011e2ea -sS https://api.github.com/repos/sass/libsass/pulls/$TRAVIS_PULL_REQUEST)
83
94
 
84
- LD_LIBRARY_PATH="$PREFIX/lib/" script/spec
95
+ SPEC_PR=$(echo $JSON | jq -r .body)
96
+
97
+ BLAH="sass\/sass-spec(#|\/pull\/)([0-9]+)"
98
+
99
+ if [[ $SPEC_PR =~ $BLAH ]];
100
+ then
101
+ SPEC_PR="${BASH_REMATCH[2]}"
102
+
103
+ echo "Fetching Sass Spec PR $SPEC_PR"
104
+
105
+ JSON=$(curl -u xzyfer:882aeec2a5b847b7d67c61d7788c2721f011e2ea -sS https://api.github.com/repos/sass/sass-spec/pulls/$SPEC_PR)
106
+
107
+ SPEC_REMOTE=$(echo $JSON | jq -r .head.repo.clone_url)
108
+ SPEC_SHA=$(echo $JSON | jq -r .head.sha)
109
+
110
+ echo "Cloning $SPEC_REMOTE"
111
+
112
+ git clone $SPEC_REMOTE sass-spec-pr
113
+
114
+ echo "Checking out $SPEC_SHA"
115
+
116
+ cd sass-spec-pr
117
+ git checkout $SPEC_SHA
118
+
119
+ echo "Re-running Sass Spec"
120
+
121
+ cd ..
122
+ SASS_SPEC_PATH="sass-spec-pr" LD_LIBRARY_PATH="$PREFIX/lib/" make $MAKE_OPTS test_build
123
+ else
124
+ LD_LIBRARY_PATH="$PREFIX/lib/" script/spec
125
+ fi
126
+ else
127
+ LD_LIBRARY_PATH="$PREFIX/lib/" script/spec
128
+ fi
@@ -0,0 +1,54 @@
1
+ ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -I m4 -I script
2
+
3
+ AM_COPT = -Wall -O2
4
+ AM_COVLDFLAGS =
5
+
6
+ if ENABLE_COVERAGE
7
+ AM_COPT = -O0 --coverage
8
+ AM_COVLDFLAGS += -lgcov
9
+ endif
10
+
11
+ AM_CPPFLAGS = -I$(top_srcdir)/include
12
+ AM_CFLAGS = $(AM_COPT)
13
+ AM_CXXFLAGS = $(AM_COPT)
14
+ AM_LDFLAGS = $(AM_COPT) $(AM_COVLDFLAGS)
15
+
16
+ if COMPILER_IS_MINGW32
17
+ AM_CXXFLAGS += -std=gnu++0x
18
+ else
19
+ AM_CXXFLAGS += -std=c++0x
20
+ endif
21
+
22
+ EXTRA_DIST = \
23
+ COPYING \
24
+ INSTALL \
25
+ LICENSE \
26
+ Readme.md
27
+
28
+ pkgconfigdir = $(libdir)/pkgconfig
29
+ pkgconfig_DATA = support/libsass.pc
30
+
31
+ lib_LTLIBRARIES = libsass.la
32
+
33
+ include $(top_srcdir)/Makefile.conf
34
+
35
+ libsass_la_SOURCES = ${CSOURCES} ${SOURCES}
36
+
37
+ libsass_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 0:9:0
38
+
39
+ if ENABLE_TESTS
40
+ if ENABLE_COVERAGE
41
+ nodist_EXTRA_libsass_la_SOURCES = non-existent-file-to-force-CXX-linking.cxx
42
+ endif
43
+ endif
44
+
45
+ include_HEADERS = $(top_srcdir)/include/sass.h \
46
+ $(top_srcdir)/include/sass2scss.h
47
+
48
+ sass_includedir = $(includedir)/sass
49
+
50
+ sass_include_HEADERS = $(top_srcdir)/include/sass/base.h \
51
+ $(top_srcdir)/include/sass/values.h \
52
+ $(top_srcdir)/include/sass/version.h \
53
+ $(top_srcdir)/include/sass/context.h \
54
+ $(top_srcdir)/include/sass/functions.h
@@ -0,0 +1,2029 @@
1
+ #include "ast.hpp"
2
+ #include "context.hpp"
3
+ #include "node.hpp"
4
+ #include "extend.hpp"
5
+ #include "to_string.hpp"
6
+ #include "color_maps.hpp"
7
+ #include <set>
8
+ #include <iomanip>
9
+ #include <algorithm>
10
+ #include <iostream>
11
+
12
+ namespace Sass {
13
+
14
+ static Null sass_null(Sass::Null(ParserState("null")));
15
+
16
+ bool Supports_Operator::needs_parens(Supports_Condition* cond) const {
17
+ return dynamic_cast<Supports_Negation*>(cond) ||
18
+ (dynamic_cast<Supports_Operator*>(cond) &&
19
+ dynamic_cast<Supports_Operator*>(cond)->operand() != operand());
20
+ }
21
+
22
+ bool Supports_Negation::needs_parens(Supports_Condition* cond) const {
23
+ return dynamic_cast<Supports_Negation*>(cond) ||
24
+ dynamic_cast<Supports_Operator*>(cond);
25
+ }
26
+
27
+ void AST_Node::update_pstate(const ParserState& pstate)
28
+ {
29
+ pstate_.offset += pstate - pstate_ + pstate.offset;
30
+ }
31
+
32
+ inline bool is_ns_eq(const std::string& l, const std::string& r)
33
+ {
34
+ if (l.empty() && r.empty()) return true;
35
+ else if (l.empty() && r == "*") return true;
36
+ else if (r.empty() && l == "*") return true;
37
+ else return l == r;
38
+ }
39
+
40
+
41
+
42
+ bool Compound_Selector::operator< (const Compound_Selector& rhs) const
43
+ {
44
+ size_t L = std::min(length(), rhs.length());
45
+ for (size_t i = 0; i < L; ++i)
46
+ {
47
+ Simple_Selector* l = (*this)[i];
48
+ Simple_Selector* r = rhs[i];
49
+ if (!l && !r) return false;
50
+ else if (!r) return false;
51
+ else if (!l) return true;
52
+ else if (*l != *r)
53
+ { return *l < *r; }
54
+ }
55
+ // just compare the length now
56
+ return length() < rhs.length();
57
+ }
58
+
59
+ bool Compound_Selector::has_parent_ref()
60
+ {
61
+ return has_parent_reference();
62
+ }
63
+
64
+ bool Complex_Selector::has_parent_ref()
65
+ {
66
+ return (head() && head()->has_parent_ref()) ||
67
+ (tail() && tail()->has_parent_ref());
68
+ }
69
+
70
+ bool Complex_Selector::operator< (const Complex_Selector& rhs) const
71
+ {
72
+ // const iterators for tails
73
+ const Complex_Selector* l = this;
74
+ const Complex_Selector* r = &rhs;
75
+ Compound_Selector* l_h = l ? l->head() : 0;
76
+ Compound_Selector* r_h = r ? r->head() : 0;
77
+ // process all tails
78
+ while (true)
79
+ {
80
+ // skip empty ancestor first
81
+ if (l && l->is_empty_ancestor())
82
+ {
83
+ l = l->tail();
84
+ l_h = l ? l->head() : 0;
85
+ continue;
86
+ }
87
+ // skip empty ancestor first
88
+ if (r && r->is_empty_ancestor())
89
+ {
90
+ r = r->tail();
91
+ r_h = r ? r->head() : 0;
92
+ continue;
93
+ }
94
+ // check for valid selectors
95
+ if (!l) return !!r;
96
+ if (!r) return false;
97
+ // both are null
98
+ else if (!l_h && !r_h)
99
+ {
100
+ // check combinator after heads
101
+ if (l->combinator() != r->combinator())
102
+ { return l->combinator() < r->combinator(); }
103
+ // advance to next tails
104
+ l = l->tail();
105
+ r = r->tail();
106
+ // fetch the next headers
107
+ l_h = l ? l->head() : 0;
108
+ r_h = r ? r->head() : 0;
109
+ }
110
+ // one side is null
111
+ else if (!r_h) return true;
112
+ else if (!l_h) return false;
113
+ // heads ok and equal
114
+ else if (*l_h == *r_h)
115
+ {
116
+ // check combinator after heads
117
+ if (l->combinator() != r->combinator())
118
+ { return l->combinator() < r->combinator(); }
119
+ // advance to next tails
120
+ l = l->tail();
121
+ r = r->tail();
122
+ // fetch the next headers
123
+ l_h = l ? l->head() : 0;
124
+ r_h = r ? r->head() : 0;
125
+ }
126
+ // heads are not equal
127
+ else return *l_h < *r_h;
128
+ }
129
+ return true;
130
+ }
131
+
132
+ bool Complex_Selector::operator== (const Complex_Selector& rhs) const
133
+ {
134
+ // const iterators for tails
135
+ const Complex_Selector* l = this;
136
+ const Complex_Selector* r = &rhs;
137
+ Compound_Selector* l_h = l ? l->head() : 0;
138
+ Compound_Selector* r_h = r ? r->head() : 0;
139
+ // process all tails
140
+ while (true)
141
+ {
142
+ // skip empty ancestor first
143
+ if (l && l->is_empty_ancestor())
144
+ {
145
+ l = l->tail();
146
+ l_h = l ? l->head() : 0;
147
+ continue;
148
+ }
149
+ // skip empty ancestor first
150
+ if (r && r->is_empty_ancestor())
151
+ {
152
+ r = r->tail();
153
+ r_h = r ? r->head() : 0;
154
+ continue;
155
+ }
156
+ // check the pointers
157
+ if (!r) return !l;
158
+ if (!l) return !r;
159
+ // both are null
160
+ if (!l_h && !r_h)
161
+ {
162
+ // check combinator after heads
163
+ if (l->combinator() != r->combinator())
164
+ { return l->combinator() < r->combinator(); }
165
+ // advance to next tails
166
+ l = l->tail();
167
+ r = r->tail();
168
+ // fetch the next heads
169
+ l_h = l ? l->head() : 0;
170
+ r_h = r ? r->head() : 0;
171
+ }
172
+ // fail if only one is null
173
+ else if (!r_h) return !l_h;
174
+ else if (!l_h) return !r_h;
175
+ // heads ok and equal
176
+ else if (*l_h == *r_h)
177
+ {
178
+ // check combinator after heads
179
+ if (l->combinator() != r->combinator())
180
+ { return l->combinator() == r->combinator(); }
181
+ // advance to next tails
182
+ l = l->tail();
183
+ r = r->tail();
184
+ // fetch the next heads
185
+ l_h = l ? l->head() : 0;
186
+ r_h = r ? r->head() : 0;
187
+ }
188
+ // abort
189
+ else break;
190
+ }
191
+ // unreachable
192
+ return false;
193
+ }
194
+
195
+ Compound_Selector* Compound_Selector::unify_with(Compound_Selector* rhs, Context& ctx)
196
+ {
197
+ Compound_Selector* unified = rhs;
198
+ for (size_t i = 0, L = length(); i < L; ++i)
199
+ {
200
+ if (!unified) break;
201
+ unified = (*this)[i]->unify_with(unified, ctx);
202
+ }
203
+ return unified;
204
+ }
205
+
206
+ bool Simple_Selector::operator== (const Simple_Selector& rhs) const
207
+ {
208
+ const Attribute_Selector* ll = dynamic_cast<const Attribute_Selector*>(this);
209
+ const Attribute_Selector* rr = dynamic_cast<const Attribute_Selector*>(&rhs);
210
+ if (ll && rr) return *ll == *rr;
211
+
212
+ if (is_ns_eq(ns(), rhs.ns()))
213
+ { return name() == rhs.name(); }
214
+ return ns() == rhs.ns();
215
+ }
216
+
217
+ bool Simple_Selector::operator< (const Simple_Selector& rhs) const
218
+ {
219
+ const Attribute_Selector* ll = dynamic_cast<const Attribute_Selector*>(this);
220
+ const Attribute_Selector* rr = dynamic_cast<const Attribute_Selector*>(&rhs);
221
+ if (ll && rr) return *ll < *rr;
222
+
223
+ if (is_ns_eq(ns(), rhs.ns()))
224
+ { return name() < rhs.name(); }
225
+ return ns() < rhs.ns();
226
+ }
227
+
228
+ bool Selector_List::operator== (const Selector& rhs) const
229
+ {
230
+ // solve the double dispatch problem by using RTTI information via dynamic cast
231
+ if (const Selector_List* ls = dynamic_cast<const Selector_List*>(&rhs)) { return *this == *ls; }
232
+ else if (const Complex_Selector* ls = dynamic_cast<const Complex_Selector*>(&rhs)) { return *this == *ls; }
233
+ else if (const Compound_Selector* ls = dynamic_cast<const Compound_Selector*>(&rhs)) { return *this == *ls; }
234
+ // no compare method
235
+ return this == &rhs;
236
+ }
237
+
238
+ bool Selector_List::operator== (const Selector_List& rhs) const
239
+ {
240
+ // for array access
241
+ size_t i = 0, n = 0;
242
+ size_t iL = length();
243
+ size_t nL = rhs.length();
244
+ // create temporary vectors and sort them
245
+ std::vector<Complex_Selector*> l_lst = this->elements();
246
+ std::vector<Complex_Selector*> r_lst = rhs.elements();
247
+ std::sort(l_lst.begin(), l_lst.end(), cmp_complex_selector());
248
+ std::sort(r_lst.begin(), r_lst.end(), cmp_complex_selector());
249
+ // process loop
250
+ while (true)
251
+ {
252
+ // first check for valid index
253
+ if (i == iL) return iL == nL;
254
+ else if (n == nL) return iL == nL;
255
+ // the access the vector items
256
+ Complex_Selector* l = l_lst[i];
257
+ Complex_Selector* r = r_lst[n];
258
+ // skip nulls
259
+ if (!l) ++i;
260
+ else if (!r) ++n;
261
+ // do the check now
262
+ else if (*l != *r)
263
+ { return false; }
264
+ // advance now
265
+ ++i; ++n;
266
+ }
267
+ // no mismatch
268
+ return true;
269
+ }
270
+
271
+ Compound_Selector* Simple_Selector::unify_with(Compound_Selector* rhs, Context& ctx)
272
+ {
273
+ To_String to_string(&ctx);
274
+ for (size_t i = 0, L = rhs->length(); i < L; ++i)
275
+ { if (perform(&to_string) == (*rhs)[i]->perform(&to_string)) return rhs; }
276
+
277
+ // check for pseudo elements because they are always last
278
+ size_t i, L;
279
+ bool found = false;
280
+ if (typeid(*this) == typeid(Pseudo_Selector) || typeid(*this) == typeid(Wrapped_Selector))
281
+ {
282
+ for (i = 0, L = rhs->length(); i < L; ++i)
283
+ {
284
+ if ((typeid(*(*rhs)[i]) == typeid(Pseudo_Selector) || typeid(*(*rhs)[i]) == typeid(Wrapped_Selector)) && (*rhs)[L-1]->is_pseudo_element())
285
+ { found = true; break; }
286
+ }
287
+ }
288
+ else
289
+ {
290
+ for (i = 0, L = rhs->length(); i < L; ++i)
291
+ {
292
+ if (typeid(*(*rhs)[i]) == typeid(Pseudo_Selector) || typeid(*(*rhs)[i]) == typeid(Wrapped_Selector))
293
+ { found = true; break; }
294
+ }
295
+ }
296
+ if (!found)
297
+ {
298
+ Compound_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, *rhs);
299
+ (*cpy) << this;
300
+ return cpy;
301
+ }
302
+ Compound_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, rhs->pstate());
303
+ for (size_t j = 0; j < i; ++j)
304
+ { (*cpy) << (*rhs)[j]; }
305
+ (*cpy) << this;
306
+ for (size_t j = i; j < L; ++j)
307
+ { (*cpy) << (*rhs)[j]; }
308
+ return cpy;
309
+ }
310
+
311
+ Simple_Selector* Type_Selector::unify_with(Simple_Selector* rhs, Context& ctx)
312
+ {
313
+ // check if ns can be extended
314
+ // true for no ns or universal
315
+ if (has_universal_ns())
316
+ {
317
+ // but dont extend with universal
318
+ // true for valid ns and universal
319
+ if (!rhs->is_universal_ns())
320
+ {
321
+ // creaty the copy inside (avoid unnecessary copies)
322
+ Type_Selector* ts = SASS_MEMORY_NEW(ctx.mem, Type_Selector, *this);
323
+ // overwrite the name if star is given as name
324
+ if (ts->name() == "*") { ts->name(rhs->name()); }
325
+ // now overwrite the namespace name and flag
326
+ ts->ns(rhs->ns()); ts->has_ns(rhs->has_ns());
327
+ // return copy
328
+ return ts;
329
+ }
330
+ }
331
+ // namespace may changed, check the name now
332
+ // overwrite star (but not with another star)
333
+ if (name() == "*" && rhs->name() != "*")
334
+ {
335
+ // creaty the copy inside (avoid unnecessary copies)
336
+ Type_Selector* ts = SASS_MEMORY_NEW(ctx.mem, Type_Selector, *this);
337
+ // simply set the new name
338
+ ts->name(rhs->name());
339
+ // return copy
340
+ return ts;
341
+ }
342
+ // return original
343
+ return this;
344
+ }
345
+
346
+ Compound_Selector* Type_Selector::unify_with(Compound_Selector* rhs, Context& ctx)
347
+ {
348
+ // TODO: handle namespaces
349
+
350
+ // if the rhs is empty, just return a copy of this
351
+ if (rhs->length() == 0) {
352
+ Compound_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, rhs->pstate());
353
+ (*cpy) << this;
354
+ return cpy;
355
+ }
356
+
357
+ Simple_Selector* rhs_0 = (*rhs)[0];
358
+ // otherwise, this is a tag name
359
+ if (name() == "*")
360
+ {
361
+ if (typeid(*rhs_0) == typeid(Type_Selector))
362
+ {
363
+ // if rhs is universal, just return this tagname + rhs's qualifiers
364
+ Compound_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, *rhs);
365
+ Type_Selector* ts = static_cast<Type_Selector*>(rhs_0);
366
+ (*cpy)[0] = this->unify_with(ts, ctx);
367
+ return cpy;
368
+ }
369
+ else if (dynamic_cast<Selector_Qualifier*>(rhs_0)) {
370
+ // qualifier is `.class`, so we can prefix with `ns|*.class`
371
+ Compound_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, rhs->pstate());
372
+ if (has_ns() && !rhs_0->has_ns()) {
373
+ if (ns() != "*") (*cpy) << this;
374
+ }
375
+ for (size_t i = 0, L = rhs->length(); i < L; ++i)
376
+ { (*cpy) << (*rhs)[i]; }
377
+ return cpy;
378
+ }
379
+
380
+
381
+ return rhs;
382
+ }
383
+
384
+ if (typeid(*rhs_0) == typeid(Type_Selector))
385
+ {
386
+ // if rhs is universal, just return this tagname + rhs's qualifiers
387
+ if (rhs_0->name() != "*" && rhs_0->ns() != "*" && rhs_0->name() != name()) return 0;
388
+ // otherwise create new compound and unify first simple selector
389
+ Compound_Selector* copy = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, *rhs);
390
+ (*copy)[0] = this->unify_with(rhs_0, ctx);
391
+ return copy;
392
+
393
+ }
394
+ // else it's a tag name and a bunch of qualifiers -- just append them
395
+ Compound_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, rhs->pstate());
396
+ if (name() != "*") (*cpy) << this;
397
+ (*cpy) += rhs;
398
+ return cpy;
399
+ }
400
+
401
+ Compound_Selector* Selector_Qualifier::unify_with(Compound_Selector* rhs, Context& ctx)
402
+ {
403
+ if (name()[0] == '#')
404
+ {
405
+ for (size_t i = 0, L = rhs->length(); i < L; ++i)
406
+ {
407
+ Simple_Selector* rhs_i = (*rhs)[i];
408
+ if (typeid(*rhs_i) == typeid(Selector_Qualifier) &&
409
+ static_cast<Selector_Qualifier*>(rhs_i)->name()[0] == '#' &&
410
+ static_cast<Selector_Qualifier*>(rhs_i)->name() != name())
411
+ return 0;
412
+ }
413
+ }
414
+ rhs->has_line_break(has_line_break());
415
+ return Simple_Selector::unify_with(rhs, ctx);
416
+ }
417
+
418
+ Compound_Selector* Pseudo_Selector::unify_with(Compound_Selector* rhs, Context& ctx)
419
+ {
420
+ if (is_pseudo_element())
421
+ {
422
+ for (size_t i = 0, L = rhs->length(); i < L; ++i)
423
+ {
424
+ Simple_Selector* rhs_i = (*rhs)[i];
425
+ if (typeid(*rhs_i) == typeid(Pseudo_Selector) &&
426
+ static_cast<Pseudo_Selector*>(rhs_i)->is_pseudo_element() &&
427
+ static_cast<Pseudo_Selector*>(rhs_i)->name() != name())
428
+ { return 0; }
429
+ }
430
+ }
431
+ return Simple_Selector::unify_with(rhs, ctx);
432
+ }
433
+
434
+ bool Attribute_Selector::operator< (const Attribute_Selector& rhs) const
435
+ {
436
+ if (is_ns_eq(ns(), rhs.ns())) {
437
+ if (name() == rhs.name()) {
438
+ if (matcher() == rhs.matcher()) {
439
+ return value() < rhs.value();
440
+ } else { return matcher() < rhs.matcher(); }
441
+ } else { return name() < rhs.name(); }
442
+ }
443
+ else return false;
444
+ }
445
+
446
+ bool Attribute_Selector::operator< (const Simple_Selector& rhs) const
447
+ {
448
+ if (const Attribute_Selector* w = dynamic_cast<const Attribute_Selector*>(&rhs))
449
+ {
450
+ return *this < *w;
451
+ }
452
+ if (is_ns_eq(ns(), rhs.ns()))
453
+ { return name() < rhs.name(); }
454
+ return ns() < rhs.ns();
455
+ }
456
+
457
+ bool Attribute_Selector::operator== (const Attribute_Selector& rhs) const
458
+ {
459
+ if (is_ns_eq(ns(), rhs.ns()) && name() == rhs.name())
460
+ { return matcher() == rhs.matcher() && value() == rhs.value(); }
461
+ else return false;
462
+ }
463
+
464
+ bool Attribute_Selector::operator== (const Simple_Selector& rhs) const
465
+ {
466
+ if (const Attribute_Selector* w = dynamic_cast<const Attribute_Selector*>(&rhs))
467
+ {
468
+ return *this == *w;
469
+ }
470
+ if (is_ns_eq(ns(), rhs.ns()))
471
+ { return name() == rhs.name(); }
472
+ return ns() == rhs.ns();
473
+ }
474
+
475
+ bool Wrapped_Selector::operator== (const Wrapped_Selector& rhs) const
476
+ {
477
+ if (is_ns_eq(ns(), rhs.ns()) && name() == rhs.name())
478
+ { return *(selector()) == *(rhs.selector()); }
479
+ else return false;
480
+ }
481
+
482
+ bool Wrapped_Selector::operator== (const Simple_Selector& rhs) const
483
+ {
484
+ if (const Wrapped_Selector* w = dynamic_cast<const Wrapped_Selector*>(&rhs))
485
+ {
486
+ return *this == *w;
487
+ }
488
+ if (is_ns_eq(ns(), rhs.ns()))
489
+ { return name() == rhs.name(); }
490
+ return ns() == rhs.ns();
491
+ }
492
+
493
+ bool Wrapped_Selector::is_superselector_of(Wrapped_Selector* sub)
494
+ {
495
+ if (this->name() != sub->name()) return false;
496
+ if (this->name() == ":current") return false;
497
+ if (Selector_List* rhs_list = dynamic_cast<Selector_List*>(sub->selector())) {
498
+ if (Selector_List* lhs_list = dynamic_cast<Selector_List*>(selector())) {
499
+ return lhs_list->is_superselector_of(rhs_list);
500
+ }
501
+ error("is_superselector expected a Selector_List", sub->pstate());
502
+ } else {
503
+ error("is_superselector expected a Selector_List", sub->pstate());
504
+ }
505
+ return false;
506
+ }
507
+
508
+ bool Compound_Selector::is_superselector_of(Selector_List* rhs, std::string wrapped)
509
+ {
510
+ for (Complex_Selector* item : rhs->elements()) {
511
+ if (is_superselector_of(item, wrapped)) return true;
512
+ }
513
+ return false;
514
+ }
515
+
516
+ bool Compound_Selector::is_superselector_of(Complex_Selector* rhs, std::string wrapped)
517
+ {
518
+ if (rhs->head()) return is_superselector_of(rhs->head(), wrapped);
519
+ return false;
520
+ }
521
+
522
+ bool Compound_Selector::is_superselector_of(Compound_Selector* rhs, std::string wrapping)
523
+ {
524
+ To_String to_string;
525
+
526
+ Compound_Selector* lhs = this;
527
+ Simple_Selector* lbase = lhs->base();
528
+ Simple_Selector* rbase = rhs->base();
529
+
530
+ // Check if pseudo-elements are the same between the selectors
531
+
532
+ std::set<std::string> lpsuedoset, rpsuedoset;
533
+ for (size_t i = 0, L = length(); i < L; ++i)
534
+ {
535
+ if ((*this)[i]->is_pseudo_element()) {
536
+ std::string pseudo((*this)[i]->perform(&to_string));
537
+ pseudo = pseudo.substr(pseudo.find_first_not_of(":")); // strip off colons to ensure :after matches ::after since ruby sass is forgiving
538
+ lpsuedoset.insert(pseudo);
539
+ }
540
+ }
541
+ for (size_t i = 0, L = rhs->length(); i < L; ++i)
542
+ {
543
+ if ((*rhs)[i]->is_pseudo_element()) {
544
+ std::string pseudo((*rhs)[i]->perform(&to_string));
545
+ pseudo = pseudo.substr(pseudo.find_first_not_of(":")); // strip off colons to ensure :after matches ::after since ruby sass is forgiving
546
+ rpsuedoset.insert(pseudo);
547
+ }
548
+ }
549
+ if (lpsuedoset != rpsuedoset) {
550
+ return false;
551
+ }
552
+
553
+ std::set<std::string> lset, rset;
554
+
555
+ if (lbase && rbase)
556
+ {
557
+ if (lbase->perform(&to_string) == rbase->perform(&to_string)) {
558
+ for (size_t i = 1, L = length(); i < L; ++i)
559
+ { lset.insert((*this)[i]->perform(&to_string)); }
560
+ for (size_t i = 1, L = rhs->length(); i < L; ++i)
561
+ { rset.insert((*rhs)[i]->perform(&to_string)); }
562
+ return includes(rset.begin(), rset.end(), lset.begin(), lset.end());
563
+ }
564
+ return false;
565
+ }
566
+
567
+ for (size_t i = 0, iL = length(); i < iL; ++i)
568
+ {
569
+ Selector* lhs = (*this)[i];
570
+ // very special case for wrapped matches selector
571
+ if (Wrapped_Selector* wrapped = dynamic_cast<Wrapped_Selector*>(lhs)) {
572
+ if (wrapped->name() == ":not") {
573
+ if (Selector_List* not_list = dynamic_cast<Selector_List*>(wrapped->selector())) {
574
+ if (not_list->is_superselector_of(rhs, wrapped->name())) return false;
575
+ } else {
576
+ throw std::runtime_error("wrapped not selector is not a list");
577
+ }
578
+ }
579
+ if (wrapped->name() == ":matches" || wrapped->name() == ":-moz-any") {
580
+ lhs = wrapped->selector();
581
+ if (Selector_List* list = dynamic_cast<Selector_List*>(wrapped->selector())) {
582
+ if (Compound_Selector* comp = dynamic_cast<Compound_Selector*>(rhs)) {
583
+ if (!wrapping.empty() && wrapping != wrapped->name()) return false;
584
+ if (wrapping.empty() || wrapping != wrapped->name()) {;
585
+ if (list->is_superselector_of(comp, wrapped->name())) return true;
586
+ }
587
+ }
588
+ }
589
+ }
590
+ Simple_Selector* rhs_sel = rhs->elements().size() > i ? (*rhs)[i] : 0;
591
+ if (Wrapped_Selector* wrapped_r = dynamic_cast<Wrapped_Selector*>(rhs_sel)) {
592
+ if (wrapped->name() == wrapped_r->name()) {
593
+ if (wrapped->is_superselector_of(wrapped_r)) {
594
+ continue;
595
+ rset.insert(lhs->perform(&to_string));
596
+
597
+ }}
598
+ }
599
+ }
600
+ // match from here on as strings
601
+ lset.insert(lhs->perform(&to_string));
602
+ }
603
+
604
+ for (size_t n = 0, nL = rhs->length(); n < nL; ++n)
605
+ {
606
+ auto r = (*rhs)[n];
607
+ if (Wrapped_Selector* wrapped = dynamic_cast<Wrapped_Selector*>(r)) {
608
+ if (wrapped->name() == ":not") {
609
+ if (Selector_List* ls = dynamic_cast<Selector_List*>(wrapped->selector())) {
610
+ ls->remove_parent_selectors();
611
+ if (is_superselector_of(ls, wrapped->name())) return false;
612
+ }
613
+ }
614
+ if (wrapped->name() == ":matches" || wrapped->name() == ":-moz-any") {
615
+ if (!wrapping.empty()) {
616
+ if (wrapping != wrapped->name()) return false;
617
+ }
618
+ if (Selector_List* ls = dynamic_cast<Selector_List*>(wrapped->selector())) {
619
+ ls->remove_parent_selectors();
620
+ return (is_superselector_of(ls, wrapped->name()));
621
+ }
622
+ }
623
+ }
624
+ rset.insert(r->perform(&to_string));
625
+ }
626
+
627
+ //for (auto l : lset) { cerr << "l: " << l << endl; }
628
+ //for (auto r : rset) { cerr << "r: " << r << endl; }
629
+
630
+ if (lset.empty()) return true;
631
+ // return true if rset contains all the elements of lset
632
+ return includes(rset.begin(), rset.end(), lset.begin(), lset.end());
633
+
634
+ }
635
+
636
+ // create complex selector (ancestor of) from compound selector
637
+ Complex_Selector* Compound_Selector::to_complex(Memory_Manager& mem)
638
+ {
639
+ // create an intermediate complex selector
640
+ return SASS_MEMORY_NEW(mem, Complex_Selector,
641
+ pstate(),
642
+ Complex_Selector::ANCESTOR_OF,
643
+ this,
644
+ 0);
645
+ }
646
+
647
+ Selector_List* Complex_Selector::unify_with(Complex_Selector* other, Context& ctx)
648
+ {
649
+
650
+ // get last tails (on the right side)
651
+ Complex_Selector* l_last = this->last();
652
+ Complex_Selector* r_last = other->last();
653
+
654
+ // check valid pointers (assertion)
655
+ SASS_ASSERT(l_last, "lhs is null");
656
+ SASS_ASSERT(r_last, "rhs is null");
657
+
658
+ // Not sure about this check, but closest way I could check
659
+ // was to see if this is a ruby 'SimpleSequence' equivalent.
660
+ // It seems to do the job correctly as some specs react to this
661
+ if (l_last->combinator() != Combinator::ANCESTOR_OF) return 0;
662
+ if (r_last->combinator() != Combinator::ANCESTOR_OF ) return 0;
663
+
664
+ // get the headers for the last tails
665
+ Compound_Selector* l_last_head = l_last->head();
666
+ Compound_Selector* r_last_head = r_last->head();
667
+
668
+ // check valid head pointers (assertion)
669
+ SASS_ASSERT(l_last_head, "lhs head is null");
670
+ SASS_ASSERT(r_last_head, "rhs head is null");
671
+
672
+ // get the unification of the last compound selectors
673
+ Compound_Selector* unified = r_last_head->unify_with(l_last_head, ctx);
674
+
675
+ // abort if we could not unify heads
676
+ if (unified == 0) return 0;
677
+
678
+ // check for universal (star: `*`) selector
679
+ bool is_universal = l_last_head->is_universal() ||
680
+ r_last_head->is_universal();
681
+
682
+ if (is_universal)
683
+ {
684
+ // move the head
685
+ l_last->head(0);
686
+ r_last->head(unified);
687
+ }
688
+
689
+ // create nodes from both selectors
690
+ Node lhsNode = complexSelectorToNode(this, ctx);
691
+ Node rhsNode = complexSelectorToNode(other, ctx);
692
+
693
+ // overwrite universal base
694
+ if (!is_universal)
695
+ {
696
+ // create some temporaries to convert to node
697
+ Complex_Selector* fake = unified->to_complex(ctx.mem);
698
+ Node unified_node = complexSelectorToNode(fake, ctx);
699
+ // add to permutate the list?
700
+ rhsNode.plus(unified_node);
701
+ }
702
+
703
+ // do some magic we inherit from node and extend
704
+ Node node = Extend::subweave(lhsNode, rhsNode, ctx);
705
+ Selector_List* result = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate());
706
+ NodeDequePtr col = node.collection(); // move from collection to list
707
+ for (NodeDeque::iterator it = col->begin(), end = col->end(); it != end; it++)
708
+ { (*result) << nodeToComplexSelector(Node::naiveTrim(*it, ctx), ctx); }
709
+
710
+ // only return if list has some entries
711
+ return result->length() ? result : 0;
712
+
713
+ }
714
+
715
+ bool Compound_Selector::operator== (const Compound_Selector& rhs) const
716
+ {
717
+ // for array access
718
+ size_t i = 0, n = 0;
719
+ size_t iL = length();
720
+ size_t nL = rhs.length();
721
+ // create temporary vectors and sort them
722
+ std::vector<Simple_Selector*> l_lst = this->elements();
723
+ std::vector<Simple_Selector*> r_lst = rhs.elements();
724
+ std::sort(l_lst.begin(), l_lst.end(), cmp_simple_selector());
725
+ std::sort(r_lst.begin(), r_lst.end(), cmp_simple_selector());
726
+ // process loop
727
+ while (true)
728
+ {
729
+ // first check for valid index
730
+ if (i == iL) return iL == nL;
731
+ else if (n == nL) return iL == nL;
732
+ // the access the vector items
733
+ Simple_Selector* l = l_lst[i];
734
+ Simple_Selector* r = r_lst[n];
735
+ // skip nulls
736
+ if (!l) ++i;
737
+ if (!r) ++n;
738
+ // do the check now
739
+ else if (*l != *r)
740
+ { return false; }
741
+ // advance now
742
+ ++i; ++n;
743
+ }
744
+ // no mismatch
745
+ return true;
746
+ }
747
+
748
+ bool Complex_Selector_Pointer_Compare::operator() (const Complex_Selector* const pLeft, const Complex_Selector* const pRight) const {
749
+ return *pLeft < *pRight;
750
+ }
751
+
752
+ bool Complex_Selector::is_superselector_of(Compound_Selector* rhs, std::string wrapping)
753
+ {
754
+ return last()->head() && last()->head()->is_superselector_of(rhs, wrapping);
755
+ }
756
+
757
+ bool Complex_Selector::is_superselector_of(Complex_Selector* rhs, std::string wrapping)
758
+ {
759
+ Complex_Selector* lhs = this;
760
+ To_String to_string;
761
+ // check for selectors with leading or trailing combinators
762
+ if (!lhs->head() || !rhs->head())
763
+ { return false; }
764
+ const Complex_Selector* l_innermost = lhs->innermost();
765
+ if (l_innermost->combinator() != Complex_Selector::ANCESTOR_OF)
766
+ { return false; }
767
+ const Complex_Selector* r_innermost = rhs->innermost();
768
+ if (r_innermost->combinator() != Complex_Selector::ANCESTOR_OF)
769
+ { return false; }
770
+ // more complex (i.e., longer) selectors are always more specific
771
+ size_t l_len = lhs->length(), r_len = rhs->length();
772
+ if (l_len > r_len)
773
+ { return false; }
774
+
775
+ if (l_len == 1)
776
+ { return lhs->head()->is_superselector_of(rhs->last()->head(), wrapping); }
777
+
778
+ // we have to look one tail deeper, since we cary the
779
+ // combinator around for it (which is important here)
780
+ if (rhs->tail() && lhs->tail() && combinator() != Complex_Selector::ANCESTOR_OF) {
781
+ Complex_Selector* lhs_tail = lhs->tail();
782
+ Complex_Selector* rhs_tail = rhs->tail();
783
+ if (lhs_tail->combinator() != rhs_tail->combinator()) return false;
784
+ if (lhs_tail->head() && !rhs_tail->head()) return false;
785
+ if (!lhs_tail->head() && rhs_tail->head()) return false;
786
+ if (lhs_tail->head() && lhs_tail->head()) {
787
+ if (!lhs_tail->head()->is_superselector_of(rhs_tail->head())) return false;
788
+ }
789
+ }
790
+
791
+ bool found = false;
792
+ Complex_Selector* marker = rhs;
793
+ for (size_t i = 0, L = rhs->length(); i < L; ++i) {
794
+ if (i == L-1)
795
+ { return false; }
796
+ if (lhs->head() && marker->head() && lhs->head()->is_superselector_of(marker->head(), wrapping))
797
+ { found = true; break; }
798
+ marker = marker->tail();
799
+ }
800
+ if (!found)
801
+ { return false; }
802
+
803
+ /*
804
+ Hmm, I hope I have the logic right:
805
+
806
+ if lhs has a combinator:
807
+ if !(marker has a combinator) return false
808
+ if !(lhs.combinator == '~' ? marker.combinator != '>' : lhs.combinator == marker.combinator) return false
809
+ return lhs.tail-without-innermost.is_superselector_of(marker.tail-without-innermost)
810
+ else if marker has a combinator:
811
+ if !(marker.combinator == ">") return false
812
+ return lhs.tail.is_superselector_of(marker.tail)
813
+ else
814
+ return lhs.tail.is_superselector_of(marker.tail)
815
+ */
816
+ if (lhs->combinator() != Complex_Selector::ANCESTOR_OF)
817
+ {
818
+ if (marker->combinator() == Complex_Selector::ANCESTOR_OF)
819
+ { return false; }
820
+ if (!(lhs->combinator() == Complex_Selector::PRECEDES ? marker->combinator() != Complex_Selector::PARENT_OF : lhs->combinator() == marker->combinator()))
821
+ { return false; }
822
+ return lhs->tail()->is_superselector_of(marker->tail());
823
+ }
824
+ else if (marker->combinator() != Complex_Selector::ANCESTOR_OF)
825
+ {
826
+ if (marker->combinator() != Complex_Selector::PARENT_OF)
827
+ { return false; }
828
+ return lhs->tail()->is_superselector_of(marker->tail());
829
+ }
830
+ else
831
+ {
832
+ return lhs->tail()->is_superselector_of(marker->tail());
833
+ }
834
+ // catch-all
835
+ return false;
836
+ }
837
+
838
+ size_t Complex_Selector::length() const
839
+ {
840
+ // TODO: make this iterative
841
+ if (!tail()) return 1;
842
+ return 1 + tail()->length();
843
+ }
844
+
845
+ Complex_Selector* Complex_Selector::context(Context& ctx)
846
+ {
847
+ if (!tail()) return 0;
848
+ if (!head()) return tail()->context(ctx);
849
+ Complex_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Complex_Selector, pstate(), combinator(), head(), tail()->context(ctx));
850
+ cpy->media_block(media_block());
851
+ return cpy;
852
+ }
853
+
854
+ // append another complex selector at the end
855
+ // check if we need to append some headers
856
+ // then we need to check for the combinator
857
+ // only then we can safely set the new tail
858
+ void Complex_Selector::append(Context& ctx, Complex_Selector* ss)
859
+ {
860
+
861
+ Complex_Selector* t = ss->tail();
862
+ Combinator c = ss->combinator();
863
+ String* r = ss->reference();
864
+ Compound_Selector* h = ss->head();
865
+
866
+ if (ss->has_line_feed()) has_line_feed(true);
867
+ if (ss->has_line_break()) has_line_break(true);
868
+
869
+ // append old headers
870
+ if (h && h->length()) {
871
+ if (last()->combinator() != ANCESTOR_OF && c != ANCESTOR_OF) {
872
+ error("Invalid parent selector", pstate_);
873
+ } else if (last()->head_ && last()->head_->length()) {
874
+ Compound_Selector* rh = last()->head();
875
+ size_t i = 0, L = h->length();
876
+ if (dynamic_cast<Type_Selector*>(h->first())) {
877
+ if (Selector_Qualifier* sq = dynamic_cast<Selector_Qualifier*>(rh->last())) {
878
+ Selector_Qualifier* sqs = new Selector_Qualifier(*sq);
879
+ sqs->name(sqs->name() + (*h)[0]->name());
880
+ (*rh)[rh->length()-1] = sqs;
881
+ for (i = 1; i < L; ++i) *rh << (*h)[i];
882
+ } else if (Type_Selector* ts = dynamic_cast<Type_Selector*>(rh->last())) {
883
+ Type_Selector* tss = new Type_Selector(*ts);
884
+ tss->name(tss->name() + (*h)[0]->name());
885
+ (*rh)[rh->length()-1] = tss;
886
+ for (i = 1; i < L; ++i) *rh << (*h)[i];
887
+ } else {
888
+ *last()->head_ += h;
889
+ }
890
+ } else {
891
+ *last()->head_ += h;
892
+ }
893
+ } else {
894
+ *last()->head_ += h;
895
+ }
896
+ } else {
897
+ // std::cerr << "has no or empty head\n";
898
+ }
899
+
900
+ if (last()) {
901
+ if (last()->combinator() != ANCESTOR_OF && c != ANCESTOR_OF) {
902
+ Complex_Selector* inter = SASS_MEMORY_NEW(ctx.mem, Complex_Selector, pstate());
903
+ inter->reference(r);
904
+ inter->combinator(c);
905
+ inter->tail(t);
906
+ last()->tail(inter);
907
+ } else {
908
+ if (last()->combinator() == ANCESTOR_OF) {
909
+ last()->combinator(c);
910
+ last()->reference(r);
911
+ }
912
+ last()->tail(t);
913
+ }
914
+ }
915
+
916
+
917
+ }
918
+
919
+ Selector_List* Selector_List::parentize(Selector_List* ps, Context& ctx)
920
+ {
921
+ Selector_List* ss = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate());
922
+ for (size_t pi = 0, pL = ps->length(); pi < pL; ++pi) {
923
+ Selector_List* list = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate());
924
+ *list << (*ps)[pi];
925
+ for (size_t si = 0, sL = this->length(); si < sL; ++si) {
926
+ *ss += (*this)[si]->parentize(list, ctx);
927
+ }
928
+ }
929
+ return ss;
930
+ }
931
+
932
+ Selector_List* Complex_Selector::parentize(Selector_List* parents, Context& ctx)
933
+ {
934
+
935
+ Complex_Selector* tail = this->tail();
936
+ Compound_Selector* head = this->head();
937
+
938
+ // first parentize the tail (which may return an expanded list)
939
+ Selector_List* tails = tail ? tail->parentize(parents, ctx) : 0;
940
+
941
+ if (head && head->length() > 0) {
942
+
943
+ // we have a parent selector in a simple compound list
944
+ // mix parent complex selector into the compound list
945
+ if (dynamic_cast<Parent_Selector*>((*head)[0])) {
946
+ if (parents && parents->length()) {
947
+ Selector_List* retval = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate());
948
+ if (tails && tails->length() > 0) {
949
+ for (size_t n = 0, nL = tails->length(); n < nL; ++n) {
950
+ for (size_t i = 0, iL = parents->length(); i < iL; ++i) {
951
+ Complex_Selector* t = (*tails)[n];
952
+ Complex_Selector* parent = (*parents)[i];
953
+ Complex_Selector* s = parent->cloneFully(ctx);
954
+ Complex_Selector* ss = this->clone(ctx);
955
+ ss->tail(t ? t->clone(ctx) : 0);
956
+ Compound_Selector* h = head_->clone(ctx);
957
+ if (h->length()) h->erase(h->begin());
958
+ ss->head(h->length() ? h : 0);
959
+ s->append(ctx, ss);
960
+ *retval << s;
961
+ }
962
+ }
963
+ }
964
+ // have no tails but parents
965
+ // loop above is inside out
966
+ else {
967
+ for (size_t i = 0, iL = parents->length(); i < iL; ++i) {
968
+ Complex_Selector* parent = (*parents)[i];
969
+ Complex_Selector* s = parent->cloneFully(ctx);
970
+ Complex_Selector* ss = this->clone(ctx);
971
+ ss->tail(tail ? tail->clone(ctx) : 0);
972
+ Compound_Selector* h = head_->clone(ctx);
973
+ if (h->length()) h->erase(h->begin());
974
+ ss->head(h->length() ? h : 0);
975
+ // \/ IMO ruby sass bug \/
976
+ ss->has_line_feed(false);
977
+ s->append(ctx, ss);
978
+ *retval << s;
979
+ }
980
+ }
981
+ return retval;
982
+ }
983
+ // have no parent but some tails
984
+ else {
985
+ Selector_List* retval = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate());
986
+ if (tails && tails->length() > 0) {
987
+ for (size_t n = 0, nL = tails->length(); n < nL; ++n) {
988
+ Complex_Selector* cpy = this->clone(ctx);
989
+ cpy->tail((*tails)[n]->cloneFully(ctx));
990
+ cpy->head(SASS_MEMORY_NEW(ctx.mem, Compound_Selector, head->pstate()));
991
+ for (size_t i = 1, L = this->head()->length(); i < L; ++i)
992
+ *cpy->head() << (*this->head())[i];
993
+ if (!cpy->head()->length()) cpy->head(0);
994
+ *retval << cpy->skip_empty_reference();
995
+ }
996
+ }
997
+ // have no parent and not tails
998
+ else {
999
+ Complex_Selector* cpy = this->clone(ctx);
1000
+ cpy->head(SASS_MEMORY_NEW(ctx.mem, Compound_Selector, head->pstate()));
1001
+ for (size_t i = 1, L = this->head()->length(); i < L; ++i)
1002
+ *cpy->head() << (*this->head())[i];
1003
+ if (!cpy->head()->length()) cpy->head(0);
1004
+ *retval << cpy->skip_empty_reference();
1005
+ }
1006
+ return retval;
1007
+ }
1008
+ }
1009
+ // no parent selector in head
1010
+ else {
1011
+ return this->tails(ctx, tails);
1012
+ }
1013
+
1014
+ }
1015
+ // has no head
1016
+ else {
1017
+ return this->tails(ctx, tails);
1018
+ }
1019
+
1020
+ // unreachable
1021
+ return 0;
1022
+ }
1023
+
1024
+ Selector_List* Complex_Selector::tails(Context& ctx, Selector_List* tails)
1025
+ {
1026
+ Selector_List* rv = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate_);
1027
+ if (tails && tails->length()) {
1028
+ for (size_t i = 0, iL = tails->length(); i < iL; ++i) {
1029
+ Complex_Selector* pr = this->clone(ctx);
1030
+ pr->tail((*tails)[i]);
1031
+ *rv << pr;
1032
+ }
1033
+ }
1034
+ else {
1035
+ *rv << this;
1036
+ }
1037
+ return rv;
1038
+ }
1039
+
1040
+ // return the last tail that is defined
1041
+ Complex_Selector* Complex_Selector::first()
1042
+ {
1043
+ // declare variables used in loop
1044
+ Complex_Selector* cur = this->tail_;
1045
+ const Compound_Selector* head = head_;
1046
+ // processing loop
1047
+ while (cur)
1048
+ {
1049
+ // get the head
1050
+ head = cur->head_;
1051
+ // check for single parent ref
1052
+ if (head && head->length() == 1)
1053
+ {
1054
+ // abort (and return) if it is not a parent selector
1055
+ if (!dynamic_cast<Parent_Selector*>((*head)[0])) break;
1056
+ }
1057
+ // advance to next
1058
+ cur = cur->tail_;
1059
+ }
1060
+ // result
1061
+ return cur;
1062
+ }
1063
+
1064
+ // return the last tail that is defined
1065
+ const Complex_Selector* Complex_Selector::first() const
1066
+ {
1067
+ // declare variables used in loop
1068
+ const Complex_Selector* cur = this->tail_;
1069
+ const Compound_Selector* head = head_;
1070
+ // processing loop
1071
+ while (cur)
1072
+ {
1073
+ // get the head
1074
+ head = cur->head_;
1075
+ // check for single parent ref
1076
+ if (head && head->length() == 1)
1077
+ {
1078
+ // abort (and return) if it is not a parent selector
1079
+ if (!dynamic_cast<Parent_Selector*>((*head)[0])) break;
1080
+ }
1081
+ // advance to next
1082
+ cur = cur->tail_;
1083
+ }
1084
+ // result
1085
+ return cur;
1086
+ }
1087
+
1088
+ // return the last tail that is defined
1089
+ Complex_Selector* Complex_Selector::last()
1090
+ {
1091
+ // ToDo: implement with a while loop
1092
+ return tail_? tail_->last() : this;
1093
+ }
1094
+
1095
+ // return the last tail that is defined
1096
+ const Complex_Selector* Complex_Selector::last() const
1097
+ {
1098
+ // ToDo: implement with a while loop
1099
+ return tail_? tail_->last() : this;
1100
+ }
1101
+
1102
+
1103
+ Complex_Selector::Combinator Complex_Selector::clear_innermost()
1104
+ {
1105
+ Combinator c;
1106
+ if (!tail() || tail()->tail() == 0)
1107
+ { c = combinator(); combinator(ANCESTOR_OF); tail(0); }
1108
+ else
1109
+ { c = tail()->clear_innermost(); }
1110
+ return c;
1111
+ }
1112
+
1113
+ void Complex_Selector::set_innermost(Complex_Selector* val, Combinator c)
1114
+ {
1115
+ if (!tail())
1116
+ { tail(val); combinator(c); }
1117
+ else
1118
+ { tail()->set_innermost(val, c); }
1119
+ }
1120
+
1121
+ Complex_Selector* Complex_Selector::clone(Context& ctx) const
1122
+ {
1123
+ Complex_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Complex_Selector, *this);
1124
+ cpy->media_block(this->media_block());
1125
+ if (tail()) cpy->tail(tail()->clone(ctx));
1126
+ return cpy;
1127
+ }
1128
+
1129
+ Complex_Selector* Complex_Selector::cloneFully(Context& ctx) const
1130
+ {
1131
+ Complex_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Complex_Selector, *this);
1132
+
1133
+ if (head()) {
1134
+ cpy->head(head()->clone(ctx));
1135
+ }
1136
+
1137
+ if (tail()) {
1138
+ cpy->tail(tail()->cloneFully(ctx));
1139
+ }
1140
+
1141
+ return cpy;
1142
+ }
1143
+
1144
+ Compound_Selector* Compound_Selector::clone(Context& ctx) const
1145
+ {
1146
+ Compound_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, *this);
1147
+ cpy->media_block(this->media_block());
1148
+ return cpy;
1149
+ }
1150
+
1151
+ Selector_List* Selector_List::clone(Context& ctx) const
1152
+ {
1153
+ Selector_List* cpy = SASS_MEMORY_NEW(ctx.mem, Selector_List, *this);
1154
+ cpy->media_block(this->media_block());
1155
+ return cpy;
1156
+ }
1157
+
1158
+ Selector_List* Selector_List::cloneFully(Context& ctx) const
1159
+ {
1160
+ Selector_List* cpy = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate());
1161
+ for (size_t i = 0, L = length(); i < L; ++i) {
1162
+ *cpy << (*this)[i]->cloneFully(ctx);
1163
+ }
1164
+ return cpy;
1165
+ }
1166
+
1167
+ /* not used anymore - remove?
1168
+ Selector_Placeholder* Selector::find_placeholder()
1169
+ {
1170
+ return 0;
1171
+ }*/
1172
+
1173
+ // remove parent selector references
1174
+ // basically unwraps parsed selectors
1175
+ void Selector_List::remove_parent_selectors()
1176
+ {
1177
+ // Check every rhs selector against left hand list
1178
+ for(size_t i = 0, L = length(); i < L; ++i) {
1179
+ if (!(*this)[i]->head()) continue;
1180
+ if ((*this)[i]->head()->is_empty_reference()) {
1181
+ // simply move to the next tail if we have "no" combinator
1182
+ if ((*this)[i]->combinator() == Complex_Selector::ANCESTOR_OF) {
1183
+ if ((*this)[i]->tail() && (*this)[i]->has_line_feed()) {
1184
+ (*this)[i]->tail()->has_line_feed(true);
1185
+ }
1186
+ (*this)[i] = (*this)[i]->tail();
1187
+ }
1188
+ // otherwise remove the first item from head
1189
+ else {
1190
+ (*this)[i]->head()->erase((*this)[i]->head()->begin());
1191
+ }
1192
+ }
1193
+ }
1194
+ }
1195
+
1196
+ void Selector_List::adjust_after_pushing(Complex_Selector* c)
1197
+ {
1198
+ if (c->has_reference()) has_reference(true);
1199
+ }
1200
+
1201
+ // it's a superselector if every selector of the right side
1202
+ // list is a superselector of the given left side selector
1203
+ bool Complex_Selector::is_superselector_of(Selector_List *sub, std::string wrapping)
1204
+ {
1205
+ // Check every rhs selector against left hand list
1206
+ for(size_t i = 0, L = sub->length(); i < L; ++i) {
1207
+ if (!is_superselector_of((*sub)[i], wrapping)) return false;
1208
+ }
1209
+ return true;
1210
+ }
1211
+
1212
+ // it's a superselector if every selector of the right side
1213
+ // list is a superselector of the given left side selector
1214
+ bool Selector_List::is_superselector_of(Selector_List *sub, std::string wrapping)
1215
+ {
1216
+ // Check every rhs selector against left hand list
1217
+ for(size_t i = 0, L = sub->length(); i < L; ++i) {
1218
+ if (!is_superselector_of((*sub)[i], wrapping)) return false;
1219
+ }
1220
+ return true;
1221
+ }
1222
+
1223
+ // it's a superselector if every selector on the right side
1224
+ // is a superselector of any one of the left side selectors
1225
+ bool Selector_List::is_superselector_of(Compound_Selector *sub, std::string wrapping)
1226
+ {
1227
+ // Check every lhs selector against right hand
1228
+ for(size_t i = 0, L = length(); i < L; ++i) {
1229
+ if ((*this)[i]->is_superselector_of(sub, wrapping)) return true;
1230
+ }
1231
+ return false;
1232
+ }
1233
+
1234
+ // it's a superselector if every selector on the right side
1235
+ // is a superselector of any one of the left side selectors
1236
+ bool Selector_List::is_superselector_of(Complex_Selector *sub, std::string wrapping)
1237
+ {
1238
+ // Check every lhs selector against right hand
1239
+ for(size_t i = 0, L = length(); i < L; ++i) {
1240
+ if ((*this)[i]->is_superselector_of(sub)) return true;
1241
+ }
1242
+ return false;
1243
+ }
1244
+
1245
+ Selector_List* Selector_List::unify_with(Selector_List* rhs, Context& ctx) {
1246
+ std::vector<Complex_Selector*> unified_complex_selectors;
1247
+ // Unify all of children with RHS's children, storing the results in `unified_complex_selectors`
1248
+ for (size_t lhs_i = 0, lhs_L = length(); lhs_i < lhs_L; ++lhs_i) {
1249
+ Complex_Selector* seq1 = (*this)[lhs_i];
1250
+ for(size_t rhs_i = 0, rhs_L = rhs->length(); rhs_i < rhs_L; ++rhs_i) {
1251
+ Complex_Selector* seq2 = (*rhs)[rhs_i];
1252
+
1253
+ Selector_List* result = seq1->unify_with(seq2, ctx);
1254
+ if( result ) {
1255
+ for(size_t i = 0, L = result->length(); i < L; ++i) {
1256
+ unified_complex_selectors.push_back( (*result)[i] );
1257
+ }
1258
+ }
1259
+ }
1260
+ }
1261
+
1262
+ // Creates the final Selector_List by combining all the complex selectors
1263
+ Selector_List* final_result = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate());
1264
+ for (auto itr = unified_complex_selectors.begin(); itr != unified_complex_selectors.end(); ++itr) {
1265
+ *final_result << *itr;
1266
+ }
1267
+ return final_result;
1268
+ }
1269
+
1270
+ void Selector_List::populate_extends(Selector_List* extendee, Context& ctx, ExtensionSubsetMap& extends) {
1271
+ To_String to_string;
1272
+
1273
+ Selector_List* extender = this;
1274
+ for (auto complex_sel : extendee->elements()) {
1275
+ Complex_Selector* c = complex_sel;
1276
+
1277
+
1278
+ // Ignore any parent selectors, until we find the first non Selector_Reference head
1279
+ Compound_Selector* compound_sel = c->head();
1280
+ Complex_Selector* pIter = complex_sel;
1281
+ while (pIter) {
1282
+ Compound_Selector* pHead = pIter->head();
1283
+ if (pHead && dynamic_cast<Parent_Selector*>(pHead->elements()[0]) == NULL) {
1284
+ compound_sel = pHead;
1285
+ break;
1286
+ }
1287
+
1288
+ pIter = pIter->tail();
1289
+ }
1290
+
1291
+ if (!pIter->head() || pIter->tail()) {
1292
+ error("nested selectors may not be extended", c->pstate());
1293
+ }
1294
+
1295
+ compound_sel->is_optional(extendee->is_optional());
1296
+
1297
+ for (size_t i = 0, L = extender->length(); i < L; ++i) {
1298
+ extends.put(compound_sel->to_str_vec(), std::make_pair((*extender)[i], compound_sel));
1299
+ }
1300
+ }
1301
+ };
1302
+
1303
+ std::vector<std::string> Compound_Selector::to_str_vec()
1304
+ {
1305
+ To_String to_string;
1306
+ std::vector<std::string> result;
1307
+ result.reserve(length());
1308
+ for (size_t i = 0, L = length(); i < L; ++i)
1309
+ { result.push_back((*this)[i]->perform(&to_string)); }
1310
+ return result;
1311
+ }
1312
+
1313
+ Compound_Selector* Compound_Selector::minus(Compound_Selector* rhs, Context& ctx)
1314
+ {
1315
+ To_String to_string(&ctx);
1316
+ Compound_Selector* result = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, pstate());
1317
+ // result->has_parent_reference(has_parent_reference());
1318
+
1319
+ // not very efficient because it needs to preserve order
1320
+ for (size_t i = 0, L = length(); i < L; ++i)
1321
+ {
1322
+ bool found = false;
1323
+ std::string thisSelector((*this)[i]->perform(&to_string));
1324
+ for (size_t j = 0, M = rhs->length(); j < M; ++j)
1325
+ {
1326
+ if (thisSelector == (*rhs)[j]->perform(&to_string))
1327
+ {
1328
+ found = true;
1329
+ break;
1330
+ }
1331
+ }
1332
+ if (!found) (*result) << (*this)[i];
1333
+ }
1334
+
1335
+ return result;
1336
+ }
1337
+
1338
+ void Compound_Selector::mergeSources(SourcesSet& sources, Context& ctx)
1339
+ {
1340
+ for (SourcesSet::iterator iterator = sources.begin(), endIterator = sources.end(); iterator != endIterator; ++iterator) {
1341
+ this->sources_.insert((*iterator)->clone(ctx));
1342
+ }
1343
+ }
1344
+
1345
+ void Arguments::adjust_after_pushing(Argument* a)
1346
+ {
1347
+ if (!a->name().empty()) {
1348
+ if (/* has_rest_argument_ || */ has_keyword_argument_) {
1349
+ error("named arguments must precede variable-length argument", a->pstate());
1350
+ }
1351
+ has_named_arguments_ = true;
1352
+ }
1353
+ else if (a->is_rest_argument()) {
1354
+ if (has_rest_argument_) {
1355
+ error("functions and mixins may only be called with one variable-length argument", a->pstate());
1356
+ }
1357
+ if (has_keyword_argument_) {
1358
+ error("only keyword arguments may follow variable arguments", a->pstate());
1359
+ }
1360
+ has_rest_argument_ = true;
1361
+ }
1362
+ else if (a->is_keyword_argument()) {
1363
+ if (has_keyword_argument_) {
1364
+ error("functions and mixins may only be called with one keyword argument", a->pstate());
1365
+ }
1366
+ has_keyword_argument_ = true;
1367
+ }
1368
+ else {
1369
+ if (has_rest_argument_) {
1370
+ error("ordinal arguments must precede variable-length arguments", a->pstate());
1371
+ }
1372
+ if (has_named_arguments_) {
1373
+ error("ordinal arguments must precede named arguments", a->pstate());
1374
+ }
1375
+ }
1376
+ }
1377
+
1378
+ bool Ruleset::is_invisible() const {
1379
+ Selector_List* sl = static_cast<Selector_List*>(selector());
1380
+ for (size_t i = 0, L = sl->length(); i < L; ++i)
1381
+ if (!(*sl)[i]->has_placeholder()) return false;
1382
+ return true;
1383
+ }
1384
+
1385
+ bool Media_Block::is_invisible() const {
1386
+ for (size_t i = 0, L = block()->length(); i < L; ++i) {
1387
+ if (!(*block())[i]->is_invisible()) return false;
1388
+ }
1389
+ return true;
1390
+ }
1391
+
1392
+ Number::Number(ParserState pstate, double val, std::string u, bool zero)
1393
+ : Value(pstate),
1394
+ value_(val),
1395
+ zero_(zero),
1396
+ numerator_units_(std::vector<std::string>()),
1397
+ denominator_units_(std::vector<std::string>()),
1398
+ hash_(0)
1399
+ {
1400
+ size_t l = 0, r = 0;
1401
+ if (!u.empty()) {
1402
+ bool nominator = true;
1403
+ while (true) {
1404
+ r = u.find_first_of("*/", l);
1405
+ std::string unit(u.substr(l, r == std::string::npos ? r : r - l));
1406
+ if (!unit.empty()) {
1407
+ if (nominator) numerator_units_.push_back(unit);
1408
+ else denominator_units_.push_back(unit);
1409
+ }
1410
+ if (r == std::string::npos) break;
1411
+ // ToDo: should error for multiple slashes
1412
+ // if (!nominator && u[r] == '/') error(...)
1413
+ if (u[r] == '/')
1414
+ nominator = false;
1415
+ l = r + 1;
1416
+ }
1417
+ }
1418
+ concrete_type(NUMBER);
1419
+ }
1420
+
1421
+ std::string Number::unit() const
1422
+ {
1423
+ std::string u;
1424
+ for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
1425
+ if (i) u += '*';
1426
+ u += numerator_units_[i];
1427
+ }
1428
+ if (!denominator_units_.empty()) u += '/';
1429
+ for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
1430
+ if (i) u += '*';
1431
+ u += denominator_units_[i];
1432
+ }
1433
+ return u;
1434
+ }
1435
+
1436
+ bool Number::is_unitless()
1437
+ { return numerator_units_.empty() && denominator_units_.empty(); }
1438
+
1439
+ void Number::normalize(const std::string& prefered, bool strict)
1440
+ {
1441
+
1442
+ // first make sure same units cancel each other out
1443
+ // it seems that a map table will fit nicely to do this
1444
+ // we basically construct exponents for each unit
1445
+ // has the advantage that they will be pre-sorted
1446
+ std::map<std::string, int> exponents;
1447
+
1448
+ // initialize by summing up occurences in unit vectors
1449
+ for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) ++ exponents[numerator_units_[i]];
1450
+ for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) -- exponents[denominator_units_[i]];
1451
+
1452
+ // the final conversion factor
1453
+ double factor = 1;
1454
+
1455
+ // get the first entry of numerators
1456
+ // forward it when entry is converted
1457
+ std::vector<std::string>::iterator nom_it = numerator_units_.begin();
1458
+ std::vector<std::string>::iterator nom_end = numerator_units_.end();
1459
+ std::vector<std::string>::iterator denom_it = denominator_units_.begin();
1460
+ std::vector<std::string>::iterator denom_end = denominator_units_.end();
1461
+
1462
+ // main normalization loop
1463
+ // should be close to optimal
1464
+ while (denom_it != denom_end)
1465
+ {
1466
+ // get and increment afterwards
1467
+ const std::string denom = *(denom_it ++);
1468
+ // skip already canceled out unit
1469
+ if (exponents[denom] >= 0) continue;
1470
+ // skip all units we don't know how to convert
1471
+ if (string_to_unit(denom) == UNKNOWN) continue;
1472
+ // now search for nominator
1473
+ while (nom_it != nom_end)
1474
+ {
1475
+ // get and increment afterwards
1476
+ const std::string nom = *(nom_it ++);
1477
+ // skip already canceled out unit
1478
+ if (exponents[nom] <= 0) continue;
1479
+ // skip all units we don't know how to convert
1480
+ if (string_to_unit(nom) == UNKNOWN) continue;
1481
+ // we now have two convertable units
1482
+ // add factor for current conversion
1483
+ factor *= conversion_factor(nom, denom, strict);
1484
+ // update nominator/denominator exponent
1485
+ -- exponents[nom]; ++ exponents[denom];
1486
+ // inner loop done
1487
+ break;
1488
+ }
1489
+ }
1490
+
1491
+ // now we can build up the new unit arrays
1492
+ numerator_units_.clear();
1493
+ denominator_units_.clear();
1494
+
1495
+ // build them by iterating over the exponents
1496
+ for (auto exp : exponents)
1497
+ {
1498
+ // maybe there is more effecient way to push
1499
+ // the same item multiple times to a vector?
1500
+ for(size_t i = 0, S = abs(exp.second); i < S; ++i)
1501
+ {
1502
+ // opted to have these switches in the inner loop
1503
+ // makes it more readable and should not cost much
1504
+ if (!exp.first.empty()) {
1505
+ if (exp.second < 0) denominator_units_.push_back(exp.first);
1506
+ else if (exp.second > 0) numerator_units_.push_back(exp.first);
1507
+ }
1508
+ }
1509
+ }
1510
+
1511
+ // apply factor to value_
1512
+ // best precision this way
1513
+ value_ *= factor;
1514
+
1515
+ // maybe convert to other unit
1516
+ // easier implemented on its own
1517
+ try { convert(prefered, strict); }
1518
+ catch (incompatibleUnits& err)
1519
+ { error(err.what(), pstate()); }
1520
+ catch (...) { throw; }
1521
+
1522
+ }
1523
+
1524
+ void Number::convert(const std::string& prefered, bool strict)
1525
+ {
1526
+ // abort if unit is empty
1527
+ if (prefered.empty()) return;
1528
+
1529
+ // first make sure same units cancel each other out
1530
+ // it seems that a map table will fit nicely to do this
1531
+ // we basically construct exponents for each unit
1532
+ // has the advantage that they will be pre-sorted
1533
+ std::map<std::string, int> exponents;
1534
+
1535
+ // initialize by summing up occurences in unit vectors
1536
+ for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) ++ exponents[numerator_units_[i]];
1537
+ for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) -- exponents[denominator_units_[i]];
1538
+
1539
+ // the final conversion factor
1540
+ double factor = 1;
1541
+
1542
+ std::vector<std::string>::iterator denom_it = denominator_units_.begin();
1543
+ std::vector<std::string>::iterator denom_end = denominator_units_.end();
1544
+
1545
+ // main normalization loop
1546
+ // should be close to optimal
1547
+ while (denom_it != denom_end)
1548
+ {
1549
+ // get and increment afterwards
1550
+ const std::string denom = *(denom_it ++);
1551
+ // check if conversion is needed
1552
+ if (denom == prefered) continue;
1553
+ // skip already canceled out unit
1554
+ if (exponents[denom] >= 0) continue;
1555
+ // skip all units we don't know how to convert
1556
+ if (string_to_unit(denom) == UNKNOWN) continue;
1557
+ // we now have two convertable units
1558
+ // add factor for current conversion
1559
+ factor *= conversion_factor(denom, prefered, strict);
1560
+ // update nominator/denominator exponent
1561
+ ++ exponents[denom]; -- exponents[prefered];
1562
+ }
1563
+
1564
+ std::vector<std::string>::iterator nom_it = numerator_units_.begin();
1565
+ std::vector<std::string>::iterator nom_end = numerator_units_.end();
1566
+
1567
+ // now search for nominator
1568
+ while (nom_it != nom_end)
1569
+ {
1570
+ // get and increment afterwards
1571
+ const std::string nom = *(nom_it ++);
1572
+ // check if conversion is needed
1573
+ if (nom == prefered) continue;
1574
+ // skip already canceled out unit
1575
+ if (exponents[nom] <= 0) continue;
1576
+ // skip all units we don't know how to convert
1577
+ if (string_to_unit(nom) == UNKNOWN) continue;
1578
+ // we now have two convertable units
1579
+ // add factor for current conversion
1580
+ factor *= conversion_factor(nom, prefered, strict);
1581
+ // update nominator/denominator exponent
1582
+ -- exponents[nom]; ++ exponents[prefered];
1583
+ }
1584
+
1585
+ // now we can build up the new unit arrays
1586
+ numerator_units_.clear();
1587
+ denominator_units_.clear();
1588
+
1589
+ // build them by iterating over the exponents
1590
+ for (auto exp : exponents)
1591
+ {
1592
+ // maybe there is more effecient way to push
1593
+ // the same item multiple times to a vector?
1594
+ for(size_t i = 0, S = abs(exp.second); i < S; ++i)
1595
+ {
1596
+ // opted to have these switches in the inner loop
1597
+ // makes it more readable and should not cost much
1598
+ if (!exp.first.empty()) {
1599
+ if (exp.second < 0) denominator_units_.push_back(exp.first);
1600
+ else if (exp.second > 0) numerator_units_.push_back(exp.first);
1601
+ }
1602
+ }
1603
+ }
1604
+
1605
+ // apply factor to value_
1606
+ // best precision this way
1607
+ value_ *= factor;
1608
+
1609
+ }
1610
+
1611
+ // useful for making one number compatible with another
1612
+ std::string Number::find_convertible_unit() const
1613
+ {
1614
+ for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
1615
+ std::string u(numerator_units_[i]);
1616
+ if (string_to_unit(u) != UNKNOWN) return u;
1617
+ }
1618
+ for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
1619
+ std::string u(denominator_units_[i]);
1620
+ if (string_to_unit(u) != UNKNOWN) return u;
1621
+ }
1622
+ return std::string();
1623
+ }
1624
+
1625
+ bool Custom_Warning::operator== (const Expression& rhs) const
1626
+ {
1627
+ if (const Custom_Warning* r = dynamic_cast<const Custom_Warning*>(&rhs)) {
1628
+ return message() == r->message();
1629
+ }
1630
+ return false;
1631
+ }
1632
+
1633
+ bool Custom_Error::operator== (const Expression& rhs) const
1634
+ {
1635
+ if (const Custom_Error* r = dynamic_cast<const Custom_Error*>(&rhs)) {
1636
+ return message() == r->message();
1637
+ }
1638
+ return false;
1639
+ }
1640
+
1641
+ bool Number::operator== (const Expression& rhs) const
1642
+ {
1643
+ if (const Number* r = dynamic_cast<const Number*>(&rhs)) {
1644
+ return (numerator_units_ == r->numerator_units_) &&
1645
+ (denominator_units_ == r->denominator_units_) &&
1646
+ std::fabs(value() - r->value()) < NUMBER_EPSILON;
1647
+ }
1648
+ return false;
1649
+ }
1650
+
1651
+ bool Number::operator< (const Number& rhs) const
1652
+ {
1653
+ Number tmp_r(rhs);
1654
+ tmp_r.normalize(find_convertible_unit());
1655
+ std::string l_unit(unit());
1656
+ std::string r_unit(tmp_r.unit());
1657
+ if (!l_unit.empty() && !r_unit.empty() && unit() != tmp_r.unit()) {
1658
+ error("cannot compare numbers with incompatible units", pstate());
1659
+ }
1660
+ return value() < tmp_r.value();
1661
+ }
1662
+
1663
+ bool String_Quoted::operator== (const Expression& rhs) const
1664
+ {
1665
+ if (const String_Quoted* qstr = dynamic_cast<const String_Quoted*>(&rhs)) {
1666
+ return (value() == qstr->value());
1667
+ } else if (const String_Constant* cstr = dynamic_cast<const String_Constant*>(&rhs)) {
1668
+ return (value() == cstr->value());
1669
+ }
1670
+ return false;
1671
+ }
1672
+
1673
+ bool String_Constant::operator== (const Expression& rhs) const
1674
+ {
1675
+ if (const String_Quoted* qstr = dynamic_cast<const String_Quoted*>(&rhs)) {
1676
+ return (value() == qstr->value());
1677
+ } else if (const String_Constant* cstr = dynamic_cast<const String_Constant*>(&rhs)) {
1678
+ return (value() == cstr->value());
1679
+ }
1680
+ return false;
1681
+ }
1682
+
1683
+ bool String_Schema::operator== (const Expression& rhs) const
1684
+ {
1685
+ if (const String_Schema* r = dynamic_cast<const String_Schema*>(&rhs)) {
1686
+ if (length() != r->length()) return false;
1687
+ for (size_t i = 0, L = length(); i < L; ++i) {
1688
+ Expression* rv = (*r)[i];
1689
+ Expression* lv = (*this)[i];
1690
+ if (!lv || !rv) return false;
1691
+ if (!(*lv == *rv)) return false;
1692
+ }
1693
+ return true;
1694
+ }
1695
+ return false;
1696
+ }
1697
+
1698
+ bool Boolean::operator== (const Expression& rhs) const
1699
+ {
1700
+ if (const Boolean* r = dynamic_cast<const Boolean*>(&rhs)) {
1701
+ return (value() == r->value());
1702
+ }
1703
+ return false;
1704
+ }
1705
+
1706
+ bool Color::operator== (const Expression& rhs) const
1707
+ {
1708
+ if (const Color* r = dynamic_cast<const Color*>(&rhs)) {
1709
+ return r_ == r->r() &&
1710
+ g_ == r->g() &&
1711
+ b_ == r->b() &&
1712
+ a_ == r->a();
1713
+ }
1714
+ return false;
1715
+ }
1716
+
1717
+ bool List::operator== (const Expression& rhs) const
1718
+ {
1719
+ if (const List* r = dynamic_cast<const List*>(&rhs)) {
1720
+ if (length() != r->length()) return false;
1721
+ if (separator() != r->separator()) return false;
1722
+ for (size_t i = 0, L = length(); i < L; ++i) {
1723
+ Expression* rv = (*r)[i];
1724
+ Expression* lv = (*this)[i];
1725
+ if (!lv || !rv) return false;
1726
+ if (!(*lv == *rv)) return false;
1727
+ }
1728
+ return true;
1729
+ }
1730
+ return false;
1731
+ }
1732
+
1733
+ bool Map::operator== (const Expression& rhs) const
1734
+ {
1735
+ if (const Map* r = dynamic_cast<const Map*>(&rhs)) {
1736
+ if (length() != r->length()) return false;
1737
+ for (auto key : keys()) {
1738
+ Expression* lv = at(key);
1739
+ Expression* rv = r->at(key);
1740
+ if (!rv || !lv) return false;
1741
+ if (!(*lv == *rv)) return false;
1742
+ }
1743
+ return true;
1744
+ }
1745
+ return false;
1746
+ }
1747
+
1748
+ bool Null::operator== (const Expression& rhs) const
1749
+ {
1750
+ return rhs.concrete_type() == NULL_VAL;
1751
+ }
1752
+
1753
+ size_t List::size() const {
1754
+ if (!is_arglist_) return length();
1755
+ // arglist expects a list of arguments
1756
+ // so we need to break before keywords
1757
+ for (size_t i = 0, L = length(); i < L; ++i) {
1758
+ if (Argument* arg = dynamic_cast<Argument*>((*this)[i])) {
1759
+ if (!arg->name().empty()) return i;
1760
+ }
1761
+ }
1762
+ return length();
1763
+ }
1764
+
1765
+ Expression* Hashed::at(Expression* k) const
1766
+ {
1767
+ if (elements_.count(k))
1768
+ { return elements_.at(k); }
1769
+ else { return &sass_null; }
1770
+ }
1771
+
1772
+ std::string Map::to_string(bool compressed, int precision) const
1773
+ {
1774
+ std::string res("");
1775
+ if (empty()) return res;
1776
+ if (is_invisible()) return res;
1777
+ bool items_output = false;
1778
+ for (auto key : keys()) {
1779
+ if (key->is_invisible()) continue;
1780
+ if (at(key)->is_invisible()) continue;
1781
+ if (items_output) res += compressed ? "," : ", ";
1782
+ Value* v_key = dynamic_cast<Value*>(key);
1783
+ Value* v_val = dynamic_cast<Value*>(at(key));
1784
+ if (v_key) res += v_key->to_string(compressed, precision);
1785
+ res += compressed ? ":" : ": ";
1786
+ if (v_val) res += v_val->to_string(compressed, precision);
1787
+ items_output = true;
1788
+ }
1789
+ return res;
1790
+ }
1791
+
1792
+ std::string List::to_string(bool compressed, int precision) const
1793
+ {
1794
+ std::string res("");
1795
+ if (empty()) return res;
1796
+ if (is_invisible()) return res;
1797
+ bool items_output = false;
1798
+ std::string sep = separator() == SASS_COMMA ? "," : " ";
1799
+ if (!compressed && sep == ",") sep += " ";
1800
+ for (size_t i = 0, L = size(); i < L; ++i) {
1801
+ Expression* item = (*this)[i];
1802
+ if (item->is_invisible()) continue;
1803
+ if (items_output) res += sep;
1804
+ if (Value* v_val = dynamic_cast<Value*>(item))
1805
+ { res += v_val->to_string(compressed, precision); }
1806
+ items_output = true;
1807
+ }
1808
+ return res;
1809
+ }
1810
+
1811
+ std::string String_Schema::to_string(bool compressed, int precision) const
1812
+ {
1813
+ std::string res("");
1814
+ for (size_t i = 0, L = length(); i < L; ++i) {
1815
+ if ((*this)[i]->is_interpolant()) res += "#{";
1816
+ if (Value* val = dynamic_cast<Value*>((*this)[i]))
1817
+ { res += val->to_string(compressed, precision); }
1818
+ if ((*this)[i]->is_interpolant()) res += "}";
1819
+ }
1820
+ return res;
1821
+ }
1822
+
1823
+ std::string Null::to_string(bool compressed, int precision) const
1824
+ {
1825
+ return "null";
1826
+ }
1827
+
1828
+ std::string Boolean::to_string(bool compressed, int precision) const
1829
+ {
1830
+ return value_ ? "true" : "false";
1831
+ }
1832
+
1833
+ // helper function for serializing colors
1834
+ template <size_t range>
1835
+ static double cap_channel(double c) {
1836
+ if (c > range) return range;
1837
+ else if (c < 0) return 0;
1838
+ else return c;
1839
+ }
1840
+
1841
+ std::string Color::to_string(bool compressed, int precision) const
1842
+ {
1843
+ std::stringstream ss;
1844
+
1845
+ // original color name
1846
+ // maybe an unknown token
1847
+ std::string name = disp();
1848
+
1849
+ // resolved color
1850
+ std::string res_name = name;
1851
+
1852
+ double r = round(cap_channel<0xff>(r_));
1853
+ double g = round(cap_channel<0xff>(g_));
1854
+ double b = round(cap_channel<0xff>(b_));
1855
+ double a = cap_channel<1> (a_);
1856
+
1857
+ // get color from given name (if one was given at all)
1858
+ if (name != "" && name_to_color(name)) {
1859
+ const Color* n = name_to_color(name);
1860
+ r = round(cap_channel<0xff>(n->r()));
1861
+ g = round(cap_channel<0xff>(n->g()));
1862
+ b = round(cap_channel<0xff>(n->b()));
1863
+ a = cap_channel<1> (n->a());
1864
+ }
1865
+ // otherwise get the possible resolved color name
1866
+ else {
1867
+ double numval = r * 0x10000 + g * 0x100 + b;
1868
+ if (color_to_name(numval))
1869
+ res_name = color_to_name(numval);
1870
+ }
1871
+
1872
+ std::stringstream hexlet;
1873
+ hexlet << '#' << std::setw(1) << std::setfill('0');
1874
+ // create a short color hexlet if there is any need for it
1875
+ if (compressed && is_color_doublet(r, g, b) && a == 1) {
1876
+ hexlet << std::hex << std::setw(1) << (static_cast<unsigned long>(r) >> 4);
1877
+ hexlet << std::hex << std::setw(1) << (static_cast<unsigned long>(g) >> 4);
1878
+ hexlet << std::hex << std::setw(1) << (static_cast<unsigned long>(b) >> 4);
1879
+ } else {
1880
+ hexlet << std::hex << std::setw(2) << static_cast<unsigned long>(r);
1881
+ hexlet << std::hex << std::setw(2) << static_cast<unsigned long>(g);
1882
+ hexlet << std::hex << std::setw(2) << static_cast<unsigned long>(b);
1883
+ }
1884
+
1885
+ if (compressed && !this->is_delayed()) name = "";
1886
+
1887
+ // retain the originally specified color definition if unchanged
1888
+ if (name != "") {
1889
+ ss << name;
1890
+ }
1891
+ else if (r == 0 && g == 0 && b == 0 && a == 0) {
1892
+ ss << "transparent";
1893
+ }
1894
+ else if (a >= 1) {
1895
+ if (res_name != "") {
1896
+ if (compressed && hexlet.str().size() < res_name.size()) {
1897
+ ss << hexlet.str();
1898
+ } else {
1899
+ ss << res_name;
1900
+ }
1901
+ }
1902
+ else {
1903
+ ss << hexlet.str();
1904
+ }
1905
+ }
1906
+ else {
1907
+ ss << "rgba(";
1908
+ ss << static_cast<unsigned long>(r) << ",";
1909
+ if (!compressed) ss << " ";
1910
+ ss << static_cast<unsigned long>(g) << ",";
1911
+ if (!compressed) ss << " ";
1912
+ ss << static_cast<unsigned long>(b) << ",";
1913
+ if (!compressed) ss << " ";
1914
+ ss << a << ')';
1915
+ }
1916
+
1917
+ return ss.str();
1918
+
1919
+ }
1920
+
1921
+ std::string Number::to_string(bool compressed, int precision) const
1922
+ {
1923
+
1924
+ std::string res;
1925
+
1926
+ // check if the fractional part of the value equals to zero
1927
+ // neat trick from http://stackoverflow.com/a/1521682/1550314
1928
+ // double int_part; bool is_int = modf(value, &int_part) == 0.0;
1929
+
1930
+ // this all cannot be done with one run only, since fixed
1931
+ // output differs from normal output and regular output
1932
+ // can contain scientific notation which we do not want!
1933
+
1934
+ // first sample
1935
+ std::stringstream ss;
1936
+ ss.precision(12);
1937
+ ss << value_;
1938
+
1939
+ // check if we got scientific notation in result
1940
+ if (ss.str().find_first_of("e") != std::string::npos) {
1941
+ ss.clear(); ss.str(std::string());
1942
+ ss.precision(std::max(12, precision));
1943
+ ss << std::fixed << value_;
1944
+ }
1945
+
1946
+ std::string tmp = ss.str();
1947
+ size_t pos_point = tmp.find_first_of(".,");
1948
+ size_t pos_fract = tmp.find_last_not_of("0");
1949
+ bool is_int = pos_point == pos_fract ||
1950
+ pos_point == std::string::npos;
1951
+
1952
+ // reset stream for another run
1953
+ ss.clear(); ss.str(std::string());
1954
+
1955
+ // take a shortcut for integers
1956
+ if (is_int)
1957
+ {
1958
+ ss.precision(0);
1959
+ ss << std::fixed << value_;
1960
+ res = std::string(ss.str());
1961
+ }
1962
+ // process floats
1963
+ else
1964
+ {
1965
+ // do we have have too much precision?
1966
+ if (pos_fract < precision + pos_point)
1967
+ { precision = (int)(pos_fract - pos_point); }
1968
+ // round value again
1969
+ ss.precision(precision);
1970
+ ss << std::fixed << value_;
1971
+ res = std::string(ss.str());
1972
+ // maybe we truncated up to decimal point
1973
+ size_t pos = res.find_last_not_of("0");
1974
+ bool at_dec_point = res[pos] == '.' ||
1975
+ res[pos] == ',';
1976
+ // don't leave a blank point
1977
+ if (at_dec_point) ++ pos;
1978
+ res.resize (pos + 1);
1979
+ }
1980
+
1981
+ // some final cosmetics
1982
+ if (res == "-0.0") res.erase(0, 1);
1983
+ else if (res == "-0") res.erase(0, 1);
1984
+ else if (res == "") res = "0";
1985
+
1986
+ // add unit now
1987
+ res += unit();
1988
+
1989
+ // and return
1990
+ return res;
1991
+
1992
+ }
1993
+
1994
+ std::string String_Quoted::to_string(bool compressed, int precision) const
1995
+ {
1996
+ return quote_mark_ ? quote(value_, quote_mark_, true) : value_;
1997
+ }
1998
+
1999
+ std::string String_Constant::to_string(bool compressed, int precision) const
2000
+ {
2001
+ return quote_mark_ ? quote(value_, quote_mark_, true) : value_;
2002
+ }
2003
+
2004
+ std::string Custom_Error::to_string(bool compressed, int precision) const
2005
+ {
2006
+ return message();
2007
+ }
2008
+ std::string Custom_Warning::to_string(bool compressed, int precision) const
2009
+ {
2010
+ return message();
2011
+ }
2012
+
2013
+ //////////////////////////////////////////////////////////////////////////////////////////
2014
+ // Additional method on Lists to retrieve values directly or from an encompassed Argument.
2015
+ //////////////////////////////////////////////////////////////////////////////////////////
2016
+ Expression* List::value_at_index(size_t i) {
2017
+ if (is_arglist_) {
2018
+ if (Argument* arg = dynamic_cast<Argument*>((*this)[i])) {
2019
+ return arg->value();
2020
+ } else {
2021
+ return (*this)[i];
2022
+ }
2023
+ } else {
2024
+ return (*this)[i];
2025
+ }
2026
+ }
2027
+
2028
+ }
2029
+