sassc 1.11.4 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +2 -2
  3. data/CODE_OF_CONDUCT.md +10 -0
  4. data/README.md +4 -1
  5. data/ext/libsass/.editorconfig +1 -1
  6. data/ext/libsass/.github/CONTRIBUTING.md +7 -7
  7. data/ext/libsass/.github/ISSUE_TEMPLATE.md +31 -6
  8. data/ext/libsass/.gitignore +3 -0
  9. data/ext/libsass/.travis.yml +37 -18
  10. data/ext/libsass/GNUmakefile.am +23 -37
  11. data/ext/libsass/Makefile +10 -6
  12. data/ext/libsass/Makefile.conf +3 -0
  13. data/ext/libsass/Readme.md +68 -63
  14. data/ext/libsass/appveyor.yml +7 -3
  15. data/ext/libsass/configure.ac +10 -14
  16. data/ext/libsass/docs/api-context-internal.md +29 -21
  17. data/ext/libsass/docs/api-context.md +26 -6
  18. data/ext/libsass/docs/api-doc.md +49 -16
  19. data/ext/libsass/docs/api-function-example.md +1 -1
  20. data/ext/libsass/docs/api-function.md +31 -7
  21. data/ext/libsass/docs/api-importer.md +19 -19
  22. data/ext/libsass/docs/api-value.md +4 -2
  23. data/ext/libsass/docs/build-on-windows.md +4 -4
  24. data/ext/libsass/docs/build-with-mingw.md +3 -3
  25. data/ext/libsass/docs/build.md +9 -9
  26. data/ext/libsass/docs/custom-functions-internal.md +10 -8
  27. data/ext/libsass/docs/implementations.md +20 -8
  28. data/ext/libsass/docs/unicode.md +16 -10
  29. data/ext/libsass/include/sass/base.h +0 -3
  30. data/ext/libsass/include/sass/context.h +20 -2
  31. data/ext/libsass/include/sass/functions.h +31 -0
  32. data/ext/libsass/include/sass/values.h +3 -1
  33. data/ext/libsass/include/sass/version.h +1 -1
  34. data/ext/libsass/include/sass/version.h.in +1 -1
  35. data/ext/libsass/include/sass2scss.h +1 -1
  36. data/ext/libsass/res/resource.rc +6 -6
  37. data/ext/libsass/script/ci-build-libsass +10 -5
  38. data/ext/libsass/script/ci-build-plugin +62 -0
  39. data/ext/libsass/script/ci-install-compiler +1 -1
  40. data/ext/libsass/script/ci-install-deps +4 -7
  41. data/ext/libsass/script/ci-report-coverage +13 -3
  42. data/ext/libsass/script/tap-driver +1 -1
  43. data/ext/libsass/script/tap-runner +1 -1
  44. data/ext/libsass/src/GNUmakefile.am +1 -1
  45. data/ext/libsass/src/ast.cpp +537 -762
  46. data/ext/libsass/src/ast.hpp +377 -419
  47. data/ext/libsass/src/ast_def_macros.hpp +26 -1
  48. data/ext/libsass/src/ast_fwd_decl.cpp +29 -0
  49. data/ext/libsass/src/ast_fwd_decl.hpp +94 -21
  50. data/ext/libsass/src/b64/encode.h +3 -1
  51. data/ext/libsass/src/backtrace.cpp +46 -0
  52. data/ext/libsass/src/backtrace.hpp +7 -54
  53. data/ext/libsass/src/bind.cpp +72 -50
  54. data/ext/libsass/src/bind.hpp +0 -1
  55. data/ext/libsass/src/cencode.c +6 -0
  56. data/ext/libsass/src/check_nesting.cpp +157 -135
  57. data/ext/libsass/src/check_nesting.hpp +11 -10
  58. data/ext/libsass/src/color_maps.cpp +10 -6
  59. data/ext/libsass/src/color_maps.hpp +6 -8
  60. data/ext/libsass/src/constants.cpp +4 -3
  61. data/ext/libsass/src/constants.hpp +4 -3
  62. data/ext/libsass/src/context.cpp +110 -47
  63. data/ext/libsass/src/context.hpp +11 -1
  64. data/ext/libsass/src/cssize.cpp +105 -94
  65. data/ext/libsass/src/cssize.hpp +4 -5
  66. data/ext/libsass/src/debugger.hpp +247 -244
  67. data/ext/libsass/src/emitter.cpp +30 -6
  68. data/ext/libsass/src/emitter.hpp +7 -0
  69. data/ext/libsass/src/environment.cpp +67 -16
  70. data/ext/libsass/src/environment.hpp +28 -7
  71. data/ext/libsass/src/error_handling.cpp +92 -64
  72. data/ext/libsass/src/error_handling.hpp +64 -43
  73. data/ext/libsass/src/eval.cpp +494 -544
  74. data/ext/libsass/src/eval.hpp +17 -23
  75. data/ext/libsass/src/expand.cpp +182 -154
  76. data/ext/libsass/src/expand.hpp +4 -5
  77. data/ext/libsass/src/extend.cpp +299 -291
  78. data/ext/libsass/src/extend.hpp +46 -11
  79. data/ext/libsass/src/file.cpp +103 -36
  80. data/ext/libsass/src/file.hpp +21 -4
  81. data/ext/libsass/src/functions.cpp +561 -312
  82. data/ext/libsass/src/functions.hpp +8 -5
  83. data/ext/libsass/src/inspect.cpp +108 -53
  84. data/ext/libsass/src/inspect.hpp +5 -2
  85. data/ext/libsass/src/lexer.cpp +15 -7
  86. data/ext/libsass/src/lexer.hpp +13 -4
  87. data/ext/libsass/src/listize.cpp +3 -2
  88. data/ext/libsass/src/listize.hpp +0 -1
  89. data/ext/libsass/src/memory/SharedPtr.cpp +16 -18
  90. data/ext/libsass/src/memory/SharedPtr.hpp +47 -43
  91. data/ext/libsass/src/node.cpp +34 -38
  92. data/ext/libsass/src/node.hpp +6 -8
  93. data/ext/libsass/src/operation.hpp +2 -2
  94. data/ext/libsass/src/operators.cpp +240 -0
  95. data/ext/libsass/src/operators.hpp +30 -0
  96. data/ext/libsass/src/output.cpp +22 -20
  97. data/ext/libsass/src/parser.cpp +719 -358
  98. data/ext/libsass/src/parser.hpp +57 -22
  99. data/ext/libsass/src/plugins.cpp +28 -10
  100. data/ext/libsass/src/position.cpp +21 -3
  101. data/ext/libsass/src/position.hpp +2 -1
  102. data/ext/libsass/src/prelexer.cpp +104 -19
  103. data/ext/libsass/src/prelexer.hpp +10 -3
  104. data/ext/libsass/src/remove_placeholders.cpp +9 -10
  105. data/ext/libsass/src/remove_placeholders.hpp +1 -5
  106. data/ext/libsass/src/sass.cpp +62 -4
  107. data/ext/libsass/src/sass.hpp +5 -2
  108. data/ext/libsass/src/sass_context.cpp +96 -58
  109. data/ext/libsass/src/sass_context.hpp +7 -5
  110. data/ext/libsass/src/sass_functions.cpp +63 -1
  111. data/ext/libsass/src/sass_functions.hpp +19 -1
  112. data/ext/libsass/src/sass_util.cpp +3 -3
  113. data/ext/libsass/src/sass_util.hpp +4 -4
  114. data/ext/libsass/src/sass_values.cpp +42 -39
  115. data/ext/libsass/src/sass_values.hpp +2 -1
  116. data/ext/libsass/src/source_map.cpp +16 -18
  117. data/ext/libsass/src/subset_map.cpp +6 -8
  118. data/ext/libsass/src/subset_map.hpp +6 -6
  119. data/ext/libsass/src/to_c.cpp +2 -2
  120. data/ext/libsass/src/to_value.cpp +8 -3
  121. data/ext/libsass/src/to_value.hpp +1 -0
  122. data/ext/libsass/src/units.cpp +349 -45
  123. data/ext/libsass/src/units.hpp +39 -22
  124. data/ext/libsass/src/utf8/checked.h +7 -0
  125. data/ext/libsass/src/utf8/unchecked.h +7 -0
  126. data/ext/libsass/src/utf8_string.cpp +1 -1
  127. data/ext/libsass/src/util.cpp +139 -45
  128. data/ext/libsass/src/util.hpp +4 -7
  129. data/ext/libsass/src/values.cpp +15 -23
  130. data/ext/libsass/win/libsass.sln +13 -2
  131. data/ext/libsass/win/libsass.sln.DotSettings +9 -0
  132. data/ext/libsass/win/libsass.targets +3 -0
  133. data/ext/libsass/win/libsass.vcxproj.filters +9 -0
  134. data/lib/sassc/version.rb +1 -1
  135. data/sassc.gemspec +1 -1
  136. data/test/native_test.rb +1 -1
  137. metadata +11 -4
@@ -18,9 +18,14 @@ if [ "x$TRAVIS_OS_NAME" == "x" ]; then export TRAVIS_OS_NAME=`uname -s | perl -n
18
18
 
19
19
  if [ "x$COVERAGE" == "xyes" ]; then
20
20
  COVERAGE_OPT="--enable-coverage"
21
- export EXTRA_CFLAGS="--coverage"
22
- export EXTRA_CXXFLAGS="--coverage"
23
- export EXTRA_LDFLAGS="--coverage"
21
+ export EXTRA_CFLAGS="-fprofile-arcs -ftest-coverage"
22
+ export EXTRA_CXXFLAGS="-fprofile-arcs -ftest-coverage"
23
+ if [ "$TRAVIS_OS_NAME" == "osx" ]; then
24
+ # osx doesn't seem to know gcov lib?
25
+ export EXTRA_LDFLAGS="--coverage"
26
+ else
27
+ export EXTRA_LDFLAGS="-lgcov --coverage"
28
+ fi
24
29
  else
25
30
  COVERAGE_OPT="--disable-coverage"
26
31
  fi
@@ -37,7 +42,7 @@ fi
37
42
  if [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then
38
43
  MAKE_OPTS="$MAKE_OPTS -j1 V=1"
39
44
  else
40
- MAKE_OPTS="$MAKE_OPTS -j3 V=1"
45
+ MAKE_OPTS="$MAKE_OPTS -j5 V=1"
41
46
  fi
42
47
 
43
48
  if [ "x$PREFIX" == "x" ]; then
@@ -109,7 +114,7 @@ then
109
114
  then
110
115
  echo "Travis rate limit on github exceeded"
111
116
  echo "Retrying via 'special purpose proxy'"
112
- JSON=$(curl -L -sS http://libsass.ocbnet.ch/libsass-spec-pr.psgi/$TRAVIS_PULL_REQUEST)
117
+ JSON=$(curl -L -sS https://github-api-reverse-proxy.herokuapp.com/repos/sass/libsass/pulls/$TRAVIS_PULL_REQUEST)
113
118
  fi
114
119
 
115
120
  RE_SPEC_PR="sass\/sass-spec(#|\/pull\/)([0-9]+)"
@@ -0,0 +1,62 @@
1
+ #!/bin/bash
2
+
3
+ PLUGIN=$1
4
+ RUBY_BIN=ruby
5
+ SASS_SPEC_PATH=sass-spec
6
+ SASSC_BIN=sassc/bin/sassc
7
+ SASS_SPEC_SPEC_DIR=plugins/libsass-${PLUGIN}/test
8
+
9
+ if [ -e ./tester ] ; then
10
+ SASSC_BIN=./tester
11
+ fi
12
+
13
+ if [ -d ./build/lib ] ; then
14
+ cp -a build/lib lib
15
+ fi
16
+
17
+ if [ "x$1" == "x" ] ; then
18
+ echo "No plugin name given"
19
+ exit 1
20
+ fi
21
+
22
+ if [ "x$COVERAGE" == "0" ] ; then
23
+ unset COVERAGE
24
+ fi
25
+
26
+ export EXTRA_CFLAGS=""
27
+ export EXTRA_CXXFLAGS=""
28
+ if [ "$TRAVIS_OS_NAME" == "osx" ]; then
29
+ # osx doesn't seem to know gcov lib?
30
+ export EXTRA_LDFLAGS="--coverage"
31
+ else
32
+ export EXTRA_LDFLAGS="-lgcov --coverage"
33
+ fi
34
+
35
+ mkdir -p plugins
36
+ if [ ! -d plugins/libsass-${PLUGIN} ] ; then
37
+ git clone https://github.com/mgreter/libsass-${PLUGIN} plugins/libsass-${PLUGIN}
38
+ fi
39
+ if [ ! -d plugins/libsass-${PLUGIN}/build ] ; then
40
+ mkdir plugins/libsass-${PLUGIN}/build
41
+ fi
42
+ RETVAL=$?; if [ "$RETVAL" != "0" ]; then exit $RETVAL; fi
43
+
44
+ cd plugins/libsass-${PLUGIN}/build
45
+ cmake -G "Unix Makefiles" -D LIBSASS_DIR="../../.." ..
46
+ RETVAL=$?; if [ "$RETVAL" != "0" ]; then exit $RETVAL; fi
47
+ make VERBOSE=1 -j2
48
+ RETVAL=$?; if [ "$RETVAL" != "0" ]; then exit $RETVAL; fi
49
+ cd ../../..
50
+
51
+ # glob only works on paths relative to imports
52
+ if [ "x$PLUGIN" == "xglob" ]; then
53
+ ${SASSC_BIN} --plugin-path plugins/libsass-${PLUGIN}/build ${SASS_SPEC_SPEC_DIR}/basic/input.scss > ${SASS_SPEC_SPEC_DIR}/basic/result.css
54
+ ${SASSC_BIN} --plugin-path plugins/libsass-${PLUGIN}/build ${SASS_SPEC_SPEC_DIR}/basic/input.scss --sourcemap > /dev/null
55
+ else
56
+ cat ${SASS_SPEC_SPEC_DIR}/basic/input.scss | ${SASSC_BIN} --plugin-path plugins/libsass-${PLUGIN}/build -I ${SASS_SPEC_SPEC_DIR}/basic > ${SASS_SPEC_SPEC_DIR}/basic/result.css
57
+ cat ${SASS_SPEC_SPEC_DIR}/basic/input.scss | ${SASSC_BIN} --plugin-path plugins/libsass-${PLUGIN}/build -I ${SASS_SPEC_SPEC_DIR}/basic --sourcemap > /dev/null
58
+ fi
59
+ RETVAL=$?; if [ "$RETVAL" != "0" ]; then exit $RETVAL; fi
60
+
61
+ diff ${SASS_SPEC_SPEC_DIR}/basic/expected_output.css ${SASS_SPEC_SPEC_DIR}/basic/result.css
62
+ RETVAL=$?; if [ "$RETVAL" != "0" ]; then exit $RETVAL; fi
@@ -3,4 +3,4 @@
3
3
  gem install minitest
4
4
  gem install minitap
5
5
 
6
- pip install --user 'requests[security]'
6
+ pip2 install --user 'requests[security]'
@@ -1,7 +1,7 @@
1
1
  #!/bin/bash
2
2
  if [ "x$COVERAGE" == "xyes" ]; then
3
- pip install --user gcovr
4
- pip install --user cpp-coveralls
3
+ pip2 install --user gcovr
4
+ pip2 install --user cpp-coveralls
5
5
  else
6
6
  echo "no dependencies to install"
7
7
  fi
@@ -15,9 +15,6 @@ if [ "x$AUTOTOOLS" == "xyes" ]; then
15
15
  sudo apt-get -qq install automake
16
16
  fi
17
17
 
18
- # https://github.com/sass/libsass/pull/2183
19
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then
20
- brew uninstall libtool
21
- brew install libtool
22
- fi
23
18
  fi
19
+
20
+ exit 0
@@ -2,6 +2,12 @@
2
2
 
3
3
  if [ "x$COVERAGE" = "xyes" ]; then
4
4
 
5
+ # find / -name "gcovr"
6
+ # find / -name "coveralls"
7
+ # this is only needed for mac os x builds!
8
+ PATH=$PATH:/Users/travis/Library/Python/2.7/bin/
9
+
10
+
5
11
  # exclude some directories from profiling (.libs is from autotools)
6
12
  export EXCLUDE_COVERAGE="--exclude plugins
7
13
  --exclude sassc/sassc.c
@@ -21,10 +27,14 @@ if [ "x$COVERAGE" = "xyes" ]; then
21
27
  --exclude src/test
22
28
  --exclude src/posix
23
29
  --exclude src/debugger.hpp"
24
- # debug via gcovr
25
- gcov -v
30
+ # debug used gcov version
31
+ # option not available on mac
32
+ if [ "$TRAVIS_OS_NAME" != "osx" ]; then
33
+ gcov -v
34
+ fi
35
+ # create summarized report
26
36
  gcovr -r .
27
- # generate and submit report to coveralls.io
37
+ # submit report to coveralls.io
28
38
  coveralls $EXCLUDE_COVERAGE --gcov-options '\-lp'
29
39
 
30
40
  else
@@ -1,4 +1,4 @@
1
- #! /bin/sh
1
+ #!/usr/bin/env sh
2
2
  # Copyright (C) 2011-2013 Free Software Foundation, Inc.
3
3
  #
4
4
  # This program is free software; you can redistribute it and/or modify
@@ -1 +1 @@
1
- $@ | tapout tap
1
+ $@ $TEST_FLAGS --tap --silent | tapout tap
@@ -34,7 +34,7 @@ include $(top_srcdir)/Makefile.conf
34
34
 
35
35
  libsass_la_SOURCES = ${CSOURCES} ${SOURCES}
36
36
 
37
- libsass_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 0:9:0
37
+ libsass_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 1:0:0
38
38
 
39
39
  if ENABLE_TESTS
40
40
  if ENABLE_COVERAGE
@@ -2,6 +2,7 @@
2
2
  #include "ast.hpp"
3
3
  #include "context.hpp"
4
4
  #include "node.hpp"
5
+ #include "eval.hpp"
5
6
  #include "extend.hpp"
6
7
  #include "emitter.hpp"
7
8
  #include "color_maps.hpp"
@@ -18,80 +19,73 @@ namespace Sass {
18
19
 
19
20
  static Null sass_null(ParserState("null"));
20
21
 
21
- bool Supports_Operator::needs_parens(Supports_Condition_Obj cond) const {
22
- if (Supports_Operator_Obj op = SASS_MEMORY_CAST(Supports_Operator, cond)) {
23
- return op->operand() != operand();
22
+ bool Wrapped_Selector::find ( bool (*f)(AST_Node_Obj) )
23
+ {
24
+ // check children first
25
+ if (selector_) {
26
+ if (selector_->find(f)) return true;
24
27
  }
25
- return SASS_MEMORY_CAST(Supports_Negation, cond) != NULL;
26
- }
27
-
28
- bool Supports_Negation::needs_parens(Supports_Condition_Obj cond) const {
29
- return SASS_MEMORY_CAST(Supports_Negation, cond) ||
30
- SASS_MEMORY_CAST(Supports_Operator, cond);
28
+ // execute last
29
+ return f(this);
31
30
  }
32
31
 
33
- size_t HashExpression::operator() (Expression_Obj ex) const {
34
- return ex ? ex->hash() : 0;
32
+ bool Selector_List::find ( bool (*f)(AST_Node_Obj) )
33
+ {
34
+ // check children first
35
+ for (Complex_Selector_Obj sel : elements()) {
36
+ if (sel->find(f)) return true;
37
+ }
38
+ // execute last
39
+ return f(this);
35
40
  }
36
41
 
37
- size_t HashSimpleSelector::operator() (Simple_Selector_Obj ex) const {
38
- return ex ? ex->hash() : 0;
42
+ bool Compound_Selector::find ( bool (*f)(AST_Node_Obj) )
43
+ {
44
+ // check children first
45
+ for (Simple_Selector_Obj sel : elements()) {
46
+ if (sel->find(f)) return true;
47
+ }
48
+ // execute last
49
+ return f(this);
39
50
  }
40
51
 
41
-
42
- bool CompareExpression::operator()(const Expression_Obj& lhs, const Expression_Obj& rhs) const {
43
- return lhs && rhs && lhs->eq(*rhs);
52
+ bool Complex_Selector::find ( bool (*f)(AST_Node_Obj) )
53
+ {
54
+ // check children first
55
+ if (head_ && head_->find(f)) return true;
56
+ if (tail_ && tail_->find(f)) return true;
57
+ // execute last
58
+ return f(this);
44
59
  }
45
60
 
46
- bool CompareSimpleSelector::operator()(Simple_Selector_Obj lhs, Simple_Selector_Obj rhs) const {
47
- return &lhs && &rhs && *lhs == *rhs;
61
+ bool Supports_Operator::needs_parens(Supports_Condition_Obj cond) const {
62
+ if (Supports_Operator_Obj op = Cast<Supports_Operator>(cond)) {
63
+ return op->operand() != operand();
64
+ }
65
+ return Cast<Supports_Negation>(cond) != NULL;
48
66
  }
49
67
 
50
- std::string & str_ltrim(std::string & str)
51
- {
52
- auto it2 = std::find_if( str.begin() , str.end() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
53
- str.erase( str.begin() , it2);
54
- return str;
68
+ bool Supports_Negation::needs_parens(Supports_Condition_Obj cond) const {
69
+ return Cast<Supports_Negation>(cond) ||
70
+ Cast<Supports_Operator>(cond);
55
71
  }
56
72
 
57
- std::string & str_rtrim(std::string & str)
73
+ void str_rtrim(std::string& str, const std::string& delimiters = " \f\n\r\t\v")
58
74
  {
59
- auto it1 = std::find_if( str.rbegin() , str.rend() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
60
- str.erase( it1.base() , str.end() );
61
- return str;
75
+ str.erase( str.find_last_not_of( delimiters ) + 1 );
62
76
  }
63
77
 
64
78
  void String_Constant::rtrim()
65
79
  {
66
- value_ = str_rtrim(value_);
67
- }
68
- void String_Constant::ltrim()
69
- {
70
- value_ = str_ltrim(value_);
71
- }
72
- void String_Constant::trim()
73
- {
74
- rtrim();
75
- ltrim();
80
+ str_rtrim(value_);
76
81
  }
77
82
 
78
83
  void String_Schema::rtrim()
79
84
  {
80
85
  if (!empty()) {
81
- if (String_Ptr str = SASS_MEMORY_CAST(String, last())) str->rtrim();
86
+ if (String_Ptr str = Cast<String>(last())) str->rtrim();
82
87
  }
83
88
  }
84
- void String_Schema::ltrim()
85
- {
86
- if (!empty()) {
87
- if (String_Ptr str = SASS_MEMORY_CAST(String, first())) str->ltrim();
88
- }
89
- }
90
- void String_Schema::trim()
91
- {
92
- rtrim();
93
- ltrim();
94
- }
95
89
 
96
90
  void Argument::set_delayed(bool delayed)
97
91
  {
@@ -111,7 +105,7 @@ namespace Sass {
111
105
  bool At_Root_Query::exclude(std::string str)
112
106
  {
113
107
  bool with = feature() && unquote(feature()->to_string()).compare("with") == 0;
114
- List_Ptr l = static_cast<List_Ptr>(&value());
108
+ List_Ptr l = static_cast<List_Ptr>(value().ptr());
115
109
  std::string v;
116
110
 
117
111
  if (with)
@@ -141,21 +135,20 @@ namespace Sass {
141
135
  pstate_.offset += pstate - pstate_ + pstate.offset;
142
136
  }
143
137
 
144
- void AST_Node::set_pstate_offset(const Offset& offset)
145
- {
146
- pstate_.offset = offset;
147
- }
148
-
149
- inline bool is_ns_eq(const std::string& l, const std::string& r)
138
+ bool Simple_Selector::is_ns_eq(const Simple_Selector& r) const
150
139
  {
151
- if (l.empty() && r.empty()) return true;
152
- else if (l.empty() && r == "*") return true;
153
- else if (r.empty() && l == "*") return true;
154
- else return l == r;
140
+ // https://github.com/sass/sass/issues/2229
141
+ if ((has_ns_ == r.has_ns_) ||
142
+ (has_ns_ && ns_.empty()) ||
143
+ (r.has_ns_ && r.ns_.empty())
144
+ ) {
145
+ if (ns_.empty() && r.ns() == "*") return false;
146
+ else if (r.ns().empty() && ns() == "*") return false;
147
+ else return ns() == r.ns();
148
+ }
149
+ return false;
155
150
  }
156
151
 
157
-
158
-
159
152
  bool Compound_Selector::operator< (const Compound_Selector& rhs) const
160
153
  {
161
154
  size_t L = std::min(length(), rhs.length());
@@ -173,7 +166,7 @@ namespace Sass {
173
166
  return length() < rhs.length();
174
167
  }
175
168
 
176
- bool Compound_Selector::has_parent_ref()
169
+ bool Compound_Selector::has_parent_ref() const
177
170
  {
178
171
  for (Simple_Selector_Obj s : *this) {
179
172
  if (s && s->has_parent_ref()) return true;
@@ -181,7 +174,7 @@ namespace Sass {
181
174
  return false;
182
175
  }
183
176
 
184
- bool Compound_Selector::has_real_parent_ref()
177
+ bool Compound_Selector::has_real_parent_ref() const
185
178
  {
186
179
  for (Simple_Selector_Obj s : *this) {
187
180
  if (s && s->has_real_parent_ref()) return true;
@@ -189,13 +182,13 @@ namespace Sass {
189
182
  return false;
190
183
  }
191
184
 
192
- bool Complex_Selector::has_parent_ref()
185
+ bool Complex_Selector::has_parent_ref() const
193
186
  {
194
187
  return (head() && head()->has_parent_ref()) ||
195
188
  (tail() && tail()->has_parent_ref());
196
189
  }
197
190
 
198
- bool Complex_Selector::has_real_parent_ref()
191
+ bool Complex_Selector::has_real_parent_ref() const
199
192
  {
200
193
  return (head() && head()->has_real_parent_ref()) ||
201
194
  (tail() && tail()->has_real_parent_ref());
@@ -206,25 +199,31 @@ namespace Sass {
206
199
  // const iterators for tails
207
200
  Complex_Selector_Ptr_Const l = this;
208
201
  Complex_Selector_Ptr_Const r = &rhs;
209
- Compound_Selector_Ptr l_h = l ? &l->head() : 0;
210
- Compound_Selector_Ptr r_h = r ? &r->head() : 0;
202
+ Compound_Selector_Ptr l_h = NULL;
203
+ Compound_Selector_Ptr r_h = NULL;
204
+ if (l) l_h = l->head();
205
+ if (r) r_h = r->head();
211
206
  // process all tails
212
207
  while (true)
213
208
  {
209
+ #ifdef DEBUG
214
210
  // skip empty ancestor first
215
211
  if (l && l->is_empty_ancestor())
216
212
  {
217
- l = &l->tail();
218
- l_h = l ? &l->head() : 0;
213
+ l_h = NULL;
214
+ l = l->tail();
215
+ if(l) l_h = l->head();
219
216
  continue;
220
217
  }
221
218
  // skip empty ancestor first
222
219
  if (r && r->is_empty_ancestor())
223
220
  {
224
- r = &r->tail();
225
- r_h = r ? &r->head() : 0;
221
+ r_h = NULL;
222
+ r = r->tail();
223
+ if (r) r_h = r->head();
226
224
  continue;
227
225
  }
226
+ #endif
228
227
  // check for valid selectors
229
228
  if (!l) return !!r;
230
229
  if (!r) return false;
@@ -235,11 +234,12 @@ namespace Sass {
235
234
  if (l->combinator() != r->combinator())
236
235
  { return l->combinator() < r->combinator(); }
237
236
  // advance to next tails
238
- l = &l->tail();
239
- r = &r->tail();
237
+ l = l->tail();
238
+ r = r->tail();
240
239
  // fetch the next headers
241
- l_h = l ? &l->head() : 0;
242
- r_h = r ? &r->head() : 0;
240
+ l_h = NULL; r_h = NULL;
241
+ if (l) l_h = l->head();
242
+ if (r) r_h = r->head();
243
243
  }
244
244
  // one side is null
245
245
  else if (!r_h) return true;
@@ -251,16 +251,16 @@ namespace Sass {
251
251
  if (l->combinator() != r->combinator())
252
252
  { return l->combinator() < r->combinator(); }
253
253
  // advance to next tails
254
- l = &l->tail();
255
- r = &r->tail();
254
+ l = l->tail();
255
+ r = r->tail();
256
256
  // fetch the next headers
257
- l_h = l ? &l->head() : 0;
258
- r_h = r ? &r->head() : 0;
257
+ l_h = NULL; r_h = NULL;
258
+ if (l) l_h = l->head();
259
+ if (r) r_h = r->head();
259
260
  }
260
261
  // heads are not equal
261
262
  else return *l_h < *r_h;
262
263
  }
263
- return true;
264
264
  }
265
265
 
266
266
  bool Complex_Selector::operator== (const Complex_Selector& rhs) const
@@ -268,25 +268,31 @@ namespace Sass {
268
268
  // const iterators for tails
269
269
  Complex_Selector_Ptr_Const l = this;
270
270
  Complex_Selector_Ptr_Const r = &rhs;
271
- Compound_Selector_Ptr l_h = l ? &l->head() : 0;
272
- Compound_Selector_Ptr r_h = r ? &r->head() : 0;
271
+ Compound_Selector_Ptr l_h = NULL;
272
+ Compound_Selector_Ptr r_h = NULL;
273
+ if (l) l_h = l->head();
274
+ if (r) r_h = r->head();
273
275
  // process all tails
274
276
  while (true)
275
277
  {
278
+ #ifdef DEBUG
276
279
  // skip empty ancestor first
277
280
  if (l && l->is_empty_ancestor())
278
281
  {
279
- l = &l->tail();
280
- l_h = l ? &l->head() : 0;
282
+ l_h = NULL;
283
+ l = l->tail();
284
+ if (l) l_h = l->head();
281
285
  continue;
282
286
  }
283
287
  // skip empty ancestor first
284
288
  if (r && r->is_empty_ancestor())
285
289
  {
286
- r = &r->tail();
287
- r_h = r ? &r->head() : 0;
290
+ r_h = NULL;
291
+ r = r->tail();
292
+ if (r) r_h = r->head();
288
293
  continue;
289
294
  }
295
+ #endif
290
296
  // check the pointers
291
297
  if (!r) return !l;
292
298
  if (!l) return !r;
@@ -297,27 +303,29 @@ namespace Sass {
297
303
  if (l->combinator() != r->combinator())
298
304
  { return l->combinator() < r->combinator(); }
299
305
  // advance to next tails
300
- l = &l->tail();
301
- r = &r->tail();
306
+ l = l->tail();
307
+ r = r->tail();
302
308
  // fetch the next heads
303
- l_h = l ? &l->head() : 0;
304
- r_h = r ? &r->head() : 0;
309
+ l_h = NULL; r_h = NULL;
310
+ if (l) l_h = l->head();
311
+ if (r) r_h = r->head();
305
312
  }
306
313
  // equals if other head is empty
307
314
  else if ((!l_h && !r_h) ||
308
315
  (!l_h && r_h->empty()) ||
309
316
  (!r_h && l_h->empty()) ||
310
- (*l_h == *r_h))
317
+ (l_h && r_h && *l_h == *r_h))
311
318
  {
312
319
  // check combinator after heads
313
320
  if (l->combinator() != r->combinator())
314
321
  { return l->combinator() == r->combinator(); }
315
322
  // advance to next tails
316
- l = &l->tail();
317
- r = &r->tail();
323
+ l = l->tail();
324
+ r = r->tail();
318
325
  // fetch the next heads
319
- l_h = l ? &l->head() : 0;
320
- r_h = r ? &r->head() : 0;
326
+ l_h = NULL; r_h = NULL;
327
+ if (l) l_h = l->head();
328
+ if (r) r_h = r->head();
321
329
  }
322
330
  // abort
323
331
  else break;
@@ -326,78 +334,105 @@ namespace Sass {
326
334
  return false;
327
335
  }
328
336
 
329
- Compound_Selector_Ptr Compound_Selector::unify_with(Compound_Selector_Ptr rhs, Context& ctx)
337
+ Compound_Selector_Ptr Compound_Selector::unify_with(Compound_Selector_Ptr rhs)
330
338
  {
331
339
  if (empty()) return rhs;
332
340
  Compound_Selector_Obj unified = SASS_MEMORY_COPY(rhs);
333
341
  for (size_t i = 0, L = length(); i < L; ++i)
334
342
  {
335
343
  if (unified.isNull()) break;
336
- unified = at(i)->unify_with(&unified, ctx);
344
+ unified = at(i)->unify_with(unified);
337
345
  }
338
346
  return unified.detach();
339
347
  }
340
348
 
341
- bool Selector::operator== (const Selector& rhs) const
349
+ bool Complex_Selector::operator== (const Selector& rhs) const
342
350
  {
343
- if (Selector_List_Ptr_Const sl = dynamic_cast<Selector_List_Ptr_Const>(this)) return *sl == rhs;
344
- if (Simple_Selector_Ptr_Const sp = dynamic_cast<Simple_Selector_Ptr_Const>(this)) return *sp == rhs;
351
+ if (const Selector_List* sl = Cast<Selector_List>(&rhs)) return *this == *sl;
352
+ if (const Simple_Selector* sp = Cast<Simple_Selector>(&rhs)) return *this == *sp;
353
+ if (const Complex_Selector* cs = Cast<Complex_Selector>(&rhs)) return *this == *cs;
354
+ if (const Compound_Selector* ch = Cast<Compound_Selector>(&rhs)) return *this == *ch;
345
355
  throw std::runtime_error("invalid selector base classes to compare");
346
- return false;
347
356
  }
348
357
 
349
- bool Selector::operator< (const Selector& rhs) const
358
+
359
+ bool Complex_Selector::operator< (const Selector& rhs) const
350
360
  {
351
- if (Selector_List_Ptr_Const sl = dynamic_cast<Selector_List_Ptr_Const>(this)) return *sl < rhs;
352
- if (Simple_Selector_Ptr_Const sp = dynamic_cast<Simple_Selector_Ptr_Const>(this)) return *sp < rhs;
361
+ if (const Selector_List* sl = Cast<Selector_List>(&rhs)) return *this < *sl;
362
+ if (const Simple_Selector* sp = Cast<Simple_Selector>(&rhs)) return *this < *sp;
363
+ if (const Complex_Selector* cs = Cast<Complex_Selector>(&rhs)) return *this < *cs;
364
+ if (const Compound_Selector* ch = Cast<Compound_Selector>(&rhs)) return *this < *ch;
365
+ throw std::runtime_error("invalid selector base classes to compare");
366
+ }
367
+
368
+ bool Compound_Selector::operator== (const Selector& rhs) const
369
+ {
370
+ if (const Selector_List* sl = Cast<Selector_List>(&rhs)) return *this == *sl;
371
+ if (const Simple_Selector* sp = Cast<Simple_Selector>(&rhs)) return *this == *sp;
372
+ if (const Complex_Selector* cs = Cast<Complex_Selector>(&rhs)) return *this == *cs;
373
+ if (const Compound_Selector* ch = Cast<Compound_Selector>(&rhs)) return *this == *ch;
374
+ throw std::runtime_error("invalid selector base classes to compare");
375
+ }
376
+
377
+ bool Compound_Selector::operator< (const Selector& rhs) const
378
+ {
379
+ if (const Selector_List* sl = Cast<Selector_List>(&rhs)) return *this < *sl;
380
+ if (const Simple_Selector* sp = Cast<Simple_Selector>(&rhs)) return *this < *sp;
381
+ if (const Complex_Selector* cs = Cast<Complex_Selector>(&rhs)) return *this < *cs;
382
+ if (const Compound_Selector* ch = Cast<Compound_Selector>(&rhs)) return *this < *ch;
383
+ throw std::runtime_error("invalid selector base classes to compare");
384
+ }
385
+
386
+ bool Selector_Schema::operator== (const Selector& rhs) const
387
+ {
388
+ if (const Selector_List* sl = Cast<Selector_List>(&rhs)) return *this == *sl;
389
+ if (const Simple_Selector* sp = Cast<Simple_Selector>(&rhs)) return *this == *sp;
390
+ if (const Complex_Selector* cs = Cast<Complex_Selector>(&rhs)) return *this == *cs;
391
+ if (const Compound_Selector* ch = Cast<Compound_Selector>(&rhs)) return *this == *ch;
392
+ throw std::runtime_error("invalid selector base classes to compare");
393
+ }
394
+
395
+ bool Selector_Schema::operator< (const Selector& rhs) const
396
+ {
397
+ if (const Selector_List* sl = Cast<Selector_List>(&rhs)) return *this < *sl;
398
+ if (const Simple_Selector* sp = Cast<Simple_Selector>(&rhs)) return *this < *sp;
399
+ if (const Complex_Selector* cs = Cast<Complex_Selector>(&rhs)) return *this < *cs;
400
+ if (const Compound_Selector* ch = Cast<Compound_Selector>(&rhs)) return *this < *ch;
353
401
  throw std::runtime_error("invalid selector base classes to compare");
354
- return false;
355
402
  }
356
403
 
357
404
  bool Simple_Selector::operator== (const Selector& rhs) const
358
405
  {
359
- if (Simple_Selector_Ptr_Const sp = dynamic_cast<Simple_Selector_Ptr_Const>(&rhs)) return *this == *sp;
406
+ if (Simple_Selector_Ptr_Const sp = Cast<Simple_Selector>(&rhs)) return *this == *sp;
360
407
  return false;
361
408
  }
362
409
 
363
410
  bool Simple_Selector::operator< (const Selector& rhs) const
364
411
  {
365
- if (Simple_Selector_Ptr_Const sp = dynamic_cast<Simple_Selector_Ptr_Const>(&rhs)) return *this < *sp;
412
+ if (Simple_Selector_Ptr_Const sp = Cast<Simple_Selector>(&rhs)) return *this < *sp;
366
413
  return false;
367
414
  }
368
415
 
369
416
  bool Simple_Selector::operator== (const Simple_Selector& rhs) const
370
417
  {
371
- Simple_Type type = simple_type();
372
- // dynamic cast is a bottleneck - use concrete type as types are final
373
- if (type == PSEUDO_SEL /* Pseudo_Selector_Ptr_Const lp = dynamic_cast<Pseudo_Selector_Ptr_Const>(this) */) {
374
- return *static_cast<Pseudo_Selector_Ptr_Const>(this) == rhs;
375
- }
376
- else if (type == WRAPPED_SEL /* Wrapped_Selector_Ptr_Const lw = dynamic_cast<Wrapped_Selector_Ptr_Const>(this) */) {
377
- return *static_cast<Wrapped_Selector_Ptr_Const>(this) == rhs;
378
- }
379
- else if (type == ATTR_SEL /* Attribute_Selector_Ptr_Const la = dynamic_cast<Attribute_Selector_Ptr_Const>(this) */) {
380
- return *static_cast<Attribute_Selector_Ptr_Const>(this) == rhs;
381
- }
418
+ // solve the double dispatch problem by using RTTI information via dynamic cast
419
+ if (const Pseudo_Selector* lhs = Cast<Pseudo_Selector>(this)) {return *lhs == rhs; }
420
+ else if (const Wrapped_Selector* lhs = Cast<Wrapped_Selector>(this)) {return *lhs == rhs; }
421
+ else if (const Element_Selector* lhs = Cast<Element_Selector>(this)) {return *lhs == rhs; }
422
+ else if (const Attribute_Selector* lhs = Cast<Attribute_Selector>(this)) {return *lhs == rhs; }
382
423
  else if (name_ == rhs.name_)
383
- { return is_ns_eq(ns_, rhs.ns_); }
424
+ { return is_ns_eq(rhs); }
384
425
  else return false;
385
426
  }
386
427
 
387
428
  bool Simple_Selector::operator< (const Simple_Selector& rhs) const
388
429
  {
389
- Simple_Type type = simple_type();
390
- // dynamic cast is a bottleneck - use concrete type as types are final
391
- if (type == PSEUDO_SEL /* Pseudo_Selector_Ptr_Const lp = dynamic_cast<Pseudo_Selector_Ptr_Const>(this) */) {
392
- return *static_cast<Pseudo_Selector_Ptr_Const>(this) < rhs;
393
- }
394
- else if (type == WRAPPED_SEL /* Wrapped_Selector_Ptr_Const lw = dynamic_cast<Wrapped_Selector_Ptr_Const>(this) */) {
395
- return *static_cast<Wrapped_Selector_Ptr_Const>(this) < rhs;
396
- }
397
- else if (type == ATTR_SEL /* Attribute_Selector_Ptr_Const la = dynamic_cast<Attribute_Selector_Ptr_Const>(this) */) {
398
- return *static_cast<Attribute_Selector_Ptr_Const>(this) < rhs;
399
- }
400
- if (is_ns_eq(ns_, rhs.ns_))
430
+ // solve the double dispatch problem by using RTTI information via dynamic cast
431
+ if (const Pseudo_Selector* lhs = Cast<Pseudo_Selector>(this)) {return *lhs < rhs; }
432
+ else if (const Wrapped_Selector* lhs = Cast<Wrapped_Selector>(this)) {return *lhs < rhs; }
433
+ else if (const Element_Selector* lhs = Cast<Element_Selector>(this)) {return *lhs < rhs; }
434
+ else if (const Attribute_Selector* lhs = Cast<Attribute_Selector>(this)) {return *lhs < rhs; }
435
+ if (is_ns_eq(rhs))
401
436
  { return name_ < rhs.name_; }
402
437
  return ns_ < rhs.ns_;
403
438
  }
@@ -405,19 +440,19 @@ namespace Sass {
405
440
  bool Selector_List::operator== (const Selector& rhs) const
406
441
  {
407
442
  // solve the double dispatch problem by using RTTI information via dynamic cast
408
- if (Selector_List_Ptr_Const ls = dynamic_cast<Selector_List_Ptr_Const>(&rhs)) { return *this == *ls; }
409
- else if (Complex_Selector_Ptr_Const ls = dynamic_cast<Complex_Selector_Ptr_Const>(&rhs)) { return *this == *ls; }
410
- else if (Compound_Selector_Ptr_Const ls = dynamic_cast<Compound_Selector_Ptr_Const>(&rhs)) { return *this == *ls; }
443
+ if (Selector_List_Ptr_Const sl = Cast<Selector_List>(&rhs)) { return *this == *sl; }
444
+ else if (Complex_Selector_Ptr_Const cpx = Cast<Complex_Selector>(&rhs)) { return *this == *cpx; }
445
+ else if (Compound_Selector_Ptr_Const cpd = Cast<Compound_Selector>(&rhs)) { return *this == *cpd; }
411
446
  // no compare method
412
447
  return this == &rhs;
413
448
  }
414
449
 
415
450
  // Selector lists can be compared to comma lists
416
- bool Selector_List::operator==(const Expression& rhs) const
451
+ bool Selector_List::operator== (const Expression& rhs) const
417
452
  {
418
453
  // solve the double dispatch problem by using RTTI information via dynamic cast
419
- if (List_Ptr_Const ls = dynamic_cast<List_Ptr_Const>(&rhs)) { return *this == *ls; }
420
- if (Selector_Ptr_Const ls = dynamic_cast<Selector_Ptr_Const>(&rhs)) { return *this == *ls; }
454
+ if (List_Ptr_Const ls = Cast<List>(&rhs)) { return *ls == *this; }
455
+ if (Selector_Ptr_Const ls = Cast<Selector>(&rhs)) { return *this == *ls; }
421
456
  // compare invalid (maybe we should error?)
422
457
  return false;
423
458
  }
@@ -431,8 +466,8 @@ namespace Sass {
431
466
  // create temporary vectors and sort them
432
467
  std::vector<Complex_Selector_Obj> l_lst = this->elements();
433
468
  std::vector<Complex_Selector_Obj> r_lst = rhs.elements();
434
- std::sort(l_lst.begin(), l_lst.end(), cmp_complex_selector());
435
- std::sort(r_lst.begin(), r_lst.end(), cmp_complex_selector());
469
+ std::sort(l_lst.begin(), l_lst.end(), OrderNodes());
470
+ std::sort(r_lst.begin(), r_lst.end(), OrderNodes());
436
471
  // process loop
437
472
  while (true)
438
473
  {
@@ -451,38 +486,38 @@ namespace Sass {
451
486
  // advance
452
487
  ++i; ++n;
453
488
  }
454
- // no mismatch
455
- return true;
489
+ // there is no break?!
456
490
  }
457
491
 
458
492
  bool Selector_List::operator< (const Selector& rhs) const
459
493
  {
460
- if (Selector_List_Ptr_Const sp = dynamic_cast<Selector_List_Ptr_Const>(&rhs)) return *this < *sp;
494
+ if (Selector_List_Ptr_Const sp = Cast<Selector_List>(&rhs)) return *this < *sp;
461
495
  return false;
462
496
  }
463
497
 
464
498
  bool Selector_List::operator< (const Selector_List& rhs) const
465
499
  {
466
- if (this->length() != rhs.length()) return false;
467
- for (size_t i = 0; i < rhs.length(); i ++) {
468
- if (!(*at(i) < *rhs.at(i))) return false;
500
+ size_t l = rhs.length();
501
+ if (length() < l) l = length();
502
+ for (size_t i = 0; i < l; i ++) {
503
+ if (*at(i) < *rhs.at(i)) return true;
469
504
  }
470
- return true;
505
+ return false;
471
506
  }
472
507
 
473
- Compound_Selector_Ptr Simple_Selector::unify_with(Compound_Selector_Ptr rhs, Context& ctx)
508
+ Compound_Selector_Ptr Simple_Selector::unify_with(Compound_Selector_Ptr rhs)
474
509
  {
475
510
  for (size_t i = 0, L = rhs->length(); i < L; ++i)
476
- { if (to_string(ctx.c_options) == rhs->at(i)->to_string(ctx.c_options)) return rhs; }
511
+ { if (to_string() == rhs->at(i)->to_string()) return rhs; }
477
512
 
478
513
  // check for pseudo elements because they are always last
479
514
  size_t i, L;
480
515
  bool found = false;
481
- if (typeid(*this) == typeid(Pseudo_Selector) || typeid(*this) == typeid(Wrapped_Selector))
516
+ if (typeid(*this) == typeid(Pseudo_Selector) || typeid(*this) == typeid(Wrapped_Selector) || typeid(*this) == typeid(Attribute_Selector))
482
517
  {
483
518
  for (i = 0, L = rhs->length(); i < L; ++i)
484
519
  {
485
- if ((SASS_MEMORY_CAST(Pseudo_Selector, (*rhs)[i]) || SASS_MEMORY_CAST(Wrapped_Selector, (*rhs)[i])) && (*rhs)[L-1]->is_pseudo_element())
520
+ if ((Cast<Pseudo_Selector>((*rhs)[i]) || Cast<Wrapped_Selector>((*rhs)[i]) || Cast<Attribute_Selector>((*rhs)[i])) && (*rhs)[L-1]->is_pseudo_element())
486
521
  { found = true; break; }
487
522
  }
488
523
  }
@@ -490,20 +525,20 @@ namespace Sass {
490
525
  {
491
526
  for (i = 0, L = rhs->length(); i < L; ++i)
492
527
  {
493
- if (SASS_MEMORY_CAST(Pseudo_Selector, (*rhs)[i]) || SASS_MEMORY_CAST(Wrapped_Selector, (*rhs)[i]))
528
+ if (Cast<Pseudo_Selector>((*rhs)[i]) || Cast<Wrapped_Selector>((*rhs)[i]) || Cast<Attribute_Selector>((*rhs)[i]))
494
529
  { found = true; break; }
495
530
  }
496
531
  }
497
532
  if (!found)
498
533
  {
499
534
  rhs->append(this);
500
- return rhs;
535
+ } else {
536
+ rhs->elements().insert(rhs->elements().begin() + i, this);
501
537
  }
502
- rhs->elements().insert(rhs->elements().begin() + i, this);
503
538
  return rhs;
504
539
  }
505
540
 
506
- Simple_Selector_Ptr Element_Selector::unify_with(Simple_Selector_Ptr rhs, Context& ctx)
541
+ Simple_Selector_Ptr Element_Selector::unify_with(Simple_Selector_Ptr rhs)
507
542
  {
508
543
  // check if ns can be extended
509
544
  // true for no ns or universal
@@ -534,7 +569,7 @@ namespace Sass {
534
569
  return this;
535
570
  }
536
571
 
537
- Compound_Selector_Ptr Element_Selector::unify_with(Compound_Selector_Ptr rhs, Context& ctx)
572
+ Compound_Selector_Ptr Element_Selector::unify_with(Compound_Selector_Ptr rhs)
538
573
  {
539
574
  // TODO: handle namespaces
540
575
 
@@ -544,18 +579,18 @@ namespace Sass {
544
579
  return rhs;
545
580
  }
546
581
 
547
- Simple_Selector_Ptr rhs_0 = &rhs->at(0);
582
+ Simple_Selector_Ptr rhs_0 = rhs->at(0);
548
583
  // otherwise, this is a tag name
549
584
  if (name() == "*")
550
585
  {
551
586
  if (typeid(*rhs_0) == typeid(Element_Selector))
552
587
  {
553
588
  // if rhs is universal, just return this tagname + rhs's qualifiers
554
- Element_Selector_Ptr ts = SASS_MEMORY_CAST_PTR(Element_Selector, rhs_0);
555
- rhs->at(0) = this->unify_with(ts, ctx);
589
+ Element_Selector_Ptr ts = Cast<Element_Selector>(rhs_0);
590
+ rhs->at(0) = this->unify_with(ts);
556
591
  return rhs;
557
592
  }
558
- else if (SASS_MEMORY_CAST_PTR(Class_Selector, rhs_0) || SASS_MEMORY_CAST_PTR(Id_Selector, rhs_0)) {
593
+ else if (Cast<Class_Selector>(rhs_0) || Cast<Id_Selector>(rhs_0)) {
559
594
  // qualifier is `.class`, so we can prefix with `ns|*.class`
560
595
  if (has_ns() && !rhs_0->has_ns()) {
561
596
  if (ns() != "*") rhs->elements().insert(rhs->begin(), this);
@@ -572,7 +607,7 @@ namespace Sass {
572
607
  // if rhs is universal, just return this tagname + rhs's qualifiers
573
608
  if (rhs_0->name() != "*" && rhs_0->ns() != "*" && rhs_0->name() != name()) return 0;
574
609
  // otherwise create new compound and unify first simple selector
575
- rhs->at(0) = this->unify_with(rhs_0, ctx);
610
+ rhs->at(0) = this->unify_with(rhs_0);
576
611
  return rhs;
577
612
 
578
613
  }
@@ -581,64 +616,61 @@ namespace Sass {
581
616
  return rhs;
582
617
  }
583
618
 
584
- Compound_Selector_Ptr Class_Selector::unify_with(Compound_Selector_Ptr rhs, Context& ctx)
619
+ Compound_Selector_Ptr Class_Selector::unify_with(Compound_Selector_Ptr rhs)
585
620
  {
586
621
  rhs->has_line_break(has_line_break());
587
- return Simple_Selector::unify_with(rhs, ctx);
622
+ return Simple_Selector::unify_with(rhs);
588
623
  }
589
624
 
590
- Compound_Selector_Ptr Id_Selector::unify_with(Compound_Selector_Ptr rhs, Context& ctx)
625
+ Compound_Selector_Ptr Id_Selector::unify_with(Compound_Selector_Ptr rhs)
591
626
  {
592
627
  for (size_t i = 0, L = rhs->length(); i < L; ++i)
593
628
  {
594
- if (Id_Selector_Ptr sel = SASS_MEMORY_CAST(Id_Selector, rhs->at(i))) {
629
+ if (Id_Selector_Ptr sel = Cast<Id_Selector>(rhs->at(i))) {
595
630
  if (sel->name() != name()) return 0;
596
631
  }
597
632
  }
598
633
  rhs->has_line_break(has_line_break());
599
- return Simple_Selector::unify_with(rhs, ctx);
634
+ return Simple_Selector::unify_with(rhs);
600
635
  }
601
636
 
602
- Compound_Selector_Ptr Pseudo_Selector::unify_with(Compound_Selector_Ptr rhs, Context& ctx)
637
+ Compound_Selector_Ptr Pseudo_Selector::unify_with(Compound_Selector_Ptr rhs)
603
638
  {
604
639
  if (is_pseudo_element())
605
640
  {
606
641
  for (size_t i = 0, L = rhs->length(); i < L; ++i)
607
642
  {
608
- if (Pseudo_Selector_Ptr sel = SASS_MEMORY_CAST(Pseudo_Selector, rhs->at(i))) {
643
+ if (Pseudo_Selector_Ptr sel = Cast<Pseudo_Selector>(rhs->at(i))) {
609
644
  if (sel->is_pseudo_element() && sel->name() != name()) return 0;
610
645
  }
611
646
  }
612
647
  }
613
- return Simple_Selector::unify_with(rhs, ctx);
648
+ return Simple_Selector::unify_with(rhs);
614
649
  }
615
650
 
616
651
  bool Attribute_Selector::operator< (const Attribute_Selector& rhs) const
617
652
  {
618
- if (is_ns_eq(ns(), rhs.ns())) {
653
+ if (is_ns_eq(rhs)) {
619
654
  if (name() == rhs.name()) {
620
655
  if (matcher() == rhs.matcher()) {
621
656
  bool no_lhs_val = value().isNull();
622
657
  bool no_rhs_val = rhs.value().isNull();
623
- if (no_lhs_val && no_rhs_val) {
624
- return true;
625
- }
626
- if (!no_lhs_val && !no_rhs_val) {
627
- return *value() < *rhs.value();
628
- }
658
+ if (no_lhs_val && no_rhs_val) return false; // equal
659
+ else if (no_lhs_val) return true; // lhs is null
660
+ else if (no_rhs_val) return false; // rhs is null
661
+ return *value() < *rhs.value(); // both are given
629
662
  } else { return matcher() < rhs.matcher(); }
630
663
  } else { return name() < rhs.name(); }
631
- }
632
- return false;
664
+ } else { return ns() < rhs.ns(); }
633
665
  }
634
666
 
635
667
  bool Attribute_Selector::operator< (const Simple_Selector& rhs) const
636
668
  {
637
- if (Attribute_Selector_Ptr_Const w = dynamic_cast<Attribute_Selector_Ptr_Const>(&rhs))
669
+ if (Attribute_Selector_Ptr_Const w = Cast<Attribute_Selector>(&rhs))
638
670
  {
639
671
  return *this < *w;
640
672
  }
641
- if (is_ns_eq(ns(), rhs.ns()))
673
+ if (is_ns_eq(rhs))
642
674
  { return name() < rhs.name(); }
643
675
  return ns() < rhs.ns();
644
676
  }
@@ -652,13 +684,13 @@ namespace Sass {
652
684
  if (no_lhs_val && no_rhs_val) {
653
685
  return (name() == rhs.name())
654
686
  && (matcher() == rhs.matcher())
655
- && (is_ns_eq(ns(), rhs.ns()));
687
+ && (is_ns_eq(rhs));
656
688
  }
657
689
  // both are defined, evaluate
658
690
  if (no_lhs_val == no_rhs_val) {
659
691
  return (name() == rhs.name())
660
692
  && (matcher() == rhs.matcher())
661
- && (is_ns_eq(ns(), rhs.ns()))
693
+ && (is_ns_eq(rhs))
662
694
  && (*value() == *rhs.value());
663
695
  }
664
696
  // not equal
@@ -668,97 +700,130 @@ namespace Sass {
668
700
 
669
701
  bool Attribute_Selector::operator== (const Simple_Selector& rhs) const
670
702
  {
671
- if (Attribute_Selector_Ptr_Const w = dynamic_cast<Attribute_Selector_Ptr_Const>(&rhs))
703
+ if (Attribute_Selector_Ptr_Const w = Cast<Attribute_Selector>(&rhs))
672
704
  {
673
- return *this == *w;
705
+ return is_ns_eq(rhs) &&
706
+ name() == rhs.name() &&
707
+ *this == *w;
708
+ }
709
+ return false;
710
+ }
711
+
712
+ bool Element_Selector::operator< (const Element_Selector& rhs) const
713
+ {
714
+ if (is_ns_eq(rhs))
715
+ { return name() < rhs.name(); }
716
+ return ns() < rhs.ns();
717
+ }
718
+
719
+ bool Element_Selector::operator< (const Simple_Selector& rhs) const
720
+ {
721
+ if (Element_Selector_Ptr_Const w = Cast<Element_Selector>(&rhs))
722
+ {
723
+ return *this < *w;
724
+ }
725
+ if (is_ns_eq(rhs))
726
+ { return name() < rhs.name(); }
727
+ return ns() < rhs.ns();
728
+ }
729
+
730
+ bool Element_Selector::operator== (const Element_Selector& rhs) const
731
+ {
732
+ return is_ns_eq(rhs) &&
733
+ name() == rhs.name();
734
+ }
735
+
736
+ bool Element_Selector::operator== (const Simple_Selector& rhs) const
737
+ {
738
+ if (Element_Selector_Ptr_Const w = Cast<Element_Selector>(&rhs))
739
+ {
740
+ return is_ns_eq(rhs) &&
741
+ name() == rhs.name() &&
742
+ *this == *w;
674
743
  }
675
- if (is_ns_eq(ns(), rhs.ns()))
676
- { return name() == rhs.name(); }
677
- return ns() == rhs.ns();
744
+ return false;
678
745
  }
679
746
 
680
747
  bool Pseudo_Selector::operator== (const Pseudo_Selector& rhs) const
681
748
  {
682
- if (is_ns_eq(ns(), rhs.ns()) && name() == rhs.name())
749
+ if (is_ns_eq(rhs) && name() == rhs.name())
683
750
  {
684
751
  String_Obj lhs_ex = expression();
685
752
  String_Obj rhs_ex = rhs.expression();
686
753
  if (rhs_ex && lhs_ex) return *lhs_ex == *rhs_ex;
687
- else return lhs_ex == rhs_ex;
754
+ else return lhs_ex.ptr() == rhs_ex.ptr();
688
755
  }
689
756
  else return false;
690
757
  }
691
758
 
692
759
  bool Pseudo_Selector::operator== (const Simple_Selector& rhs) const
693
760
  {
694
- if (Pseudo_Selector_Ptr_Const w = dynamic_cast<Pseudo_Selector_Ptr_Const>(&rhs))
761
+ if (Pseudo_Selector_Ptr_Const w = Cast<Pseudo_Selector>(&rhs))
695
762
  {
696
763
  return *this == *w;
697
764
  }
698
- if (is_ns_eq(ns(), rhs.ns()))
699
- { return name() == rhs.name(); }
700
- return ns() == rhs.ns();
765
+ return is_ns_eq(rhs) &&
766
+ name() == rhs.name();
701
767
  }
702
768
 
703
769
  bool Pseudo_Selector::operator< (const Pseudo_Selector& rhs) const
704
770
  {
705
- if (is_ns_eq(ns(), rhs.ns()) && name() == rhs.name())
771
+ if (is_ns_eq(rhs) && name() == rhs.name())
706
772
  {
707
773
  String_Obj lhs_ex = expression();
708
774
  String_Obj rhs_ex = rhs.expression();
709
775
  if (rhs_ex && lhs_ex) return *lhs_ex < *rhs_ex;
710
- else return lhs_ex < rhs_ex;
776
+ else return lhs_ex.ptr() < rhs_ex.ptr();
711
777
  }
712
- if (is_ns_eq(ns(), rhs.ns()))
778
+ if (is_ns_eq(rhs))
713
779
  { return name() < rhs.name(); }
714
780
  return ns() < rhs.ns();
715
781
  }
716
782
 
717
783
  bool Pseudo_Selector::operator< (const Simple_Selector& rhs) const
718
784
  {
719
- if (Pseudo_Selector_Ptr_Const w = dynamic_cast<Pseudo_Selector_Ptr_Const>(&rhs))
785
+ if (Pseudo_Selector_Ptr_Const w = Cast<Pseudo_Selector>(&rhs))
720
786
  {
721
787
  return *this < *w;
722
788
  }
723
- if (is_ns_eq(ns(), rhs.ns()))
789
+ if (is_ns_eq(rhs))
724
790
  { return name() < rhs.name(); }
725
791
  return ns() < rhs.ns();
726
792
  }
727
793
 
728
794
  bool Wrapped_Selector::operator== (const Wrapped_Selector& rhs) const
729
795
  {
730
- if (is_ns_eq(ns(), rhs.ns()) && name() == rhs.name())
796
+ if (is_ns_eq(rhs) && name() == rhs.name())
731
797
  { return *(selector()) == *(rhs.selector()); }
732
798
  else return false;
733
799
  }
734
800
 
735
801
  bool Wrapped_Selector::operator== (const Simple_Selector& rhs) const
736
802
  {
737
- if (Wrapped_Selector_Ptr_Const w = dynamic_cast<Wrapped_Selector_Ptr_Const>(&rhs))
803
+ if (Wrapped_Selector_Ptr_Const w = Cast<Wrapped_Selector>(&rhs))
738
804
  {
739
805
  return *this == *w;
740
806
  }
741
- if (is_ns_eq(ns(), rhs.ns()))
742
- { return name() == rhs.name(); }
743
- return ns() == rhs.ns();
807
+ return is_ns_eq(rhs) &&
808
+ name() == rhs.name();
744
809
  }
745
810
 
746
811
  bool Wrapped_Selector::operator< (const Wrapped_Selector& rhs) const
747
812
  {
748
- if (is_ns_eq(ns(), rhs.ns()) && name() == rhs.name())
813
+ if (is_ns_eq(rhs) && name() == rhs.name())
749
814
  { return *(selector()) < *(rhs.selector()); }
750
- if (is_ns_eq(ns(), rhs.ns()))
815
+ if (is_ns_eq(rhs))
751
816
  { return name() < rhs.name(); }
752
817
  return ns() < rhs.ns();
753
818
  }
754
819
 
755
820
  bool Wrapped_Selector::operator< (const Simple_Selector& rhs) const
756
821
  {
757
- if (Wrapped_Selector_Ptr_Const w = dynamic_cast<Wrapped_Selector_Ptr_Const>(&rhs))
822
+ if (Wrapped_Selector_Ptr_Const w = Cast<Wrapped_Selector>(&rhs))
758
823
  {
759
824
  return *this < *w;
760
825
  }
761
- if (is_ns_eq(ns(), rhs.ns()))
826
+ if (is_ns_eq(rhs))
762
827
  { return name() < rhs.name(); }
763
828
  return ns() < rhs.ns();
764
829
  }
@@ -767,28 +832,26 @@ namespace Sass {
767
832
  {
768
833
  if (this->name() != sub->name()) return false;
769
834
  if (this->name() == ":current") return false;
770
- if (Selector_List_Obj rhs_list = SASS_MEMORY_CAST(Selector_List, sub->selector())) {
771
- if (Selector_List_Obj lhs_list = SASS_MEMORY_CAST(Selector_List, selector())) {
835
+ if (Selector_List_Obj rhs_list = Cast<Selector_List>(sub->selector())) {
836
+ if (Selector_List_Obj lhs_list = Cast<Selector_List>(selector())) {
772
837
  return lhs_list->is_superselector_of(rhs_list);
773
838
  }
774
- error("is_superselector expected a Selector_List", sub->pstate());
775
- } else {
776
- error("is_superselector expected a Selector_List", sub->pstate());
777
839
  }
840
+ coreError("is_superselector expected a Selector_List", sub->pstate());
778
841
  return false;
779
842
  }
780
843
 
781
844
  bool Compound_Selector::is_superselector_of(Selector_List_Obj rhs, std::string wrapped)
782
845
  {
783
846
  for (Complex_Selector_Obj item : rhs->elements()) {
784
- if (is_superselector_of(&item, wrapped)) return true;
847
+ if (is_superselector_of(item, wrapped)) return true;
785
848
  }
786
849
  return false;
787
850
  }
788
851
 
789
852
  bool Compound_Selector::is_superselector_of(Complex_Selector_Obj rhs, std::string wrapped)
790
853
  {
791
- if (rhs->head()) return is_superselector_of(&rhs->head(), wrapped);
854
+ if (rhs->head()) return is_superselector_of(rhs->head(), wrapped);
792
855
  return false;
793
856
  }
794
857
 
@@ -821,6 +884,9 @@ namespace Sass {
821
884
  return false;
822
885
  }
823
886
 
887
+ // would like to replace this without stringification
888
+ // https://github.com/sass/sass/issues/2229
889
+ // SimpleSelectorSet lset, rset;
824
890
  std::set<std::string> lset, rset;
825
891
 
826
892
  if (lbase && rbase)
@@ -837,20 +903,20 @@ namespace Sass {
837
903
 
838
904
  for (size_t i = 0, iL = length(); i < iL; ++i)
839
905
  {
840
- Selector_Obj lhs = &(*this)[i];
906
+ Selector_Obj wlhs = (*this)[i];
841
907
  // very special case for wrapped matches selector
842
- if (Wrapped_Selector_Obj wrapped = SASS_MEMORY_CAST(Wrapped_Selector, lhs)) {
908
+ if (Wrapped_Selector_Obj wrapped = Cast<Wrapped_Selector>(wlhs)) {
843
909
  if (wrapped->name() == ":not") {
844
- if (Selector_List_Obj not_list = SASS_MEMORY_CAST(Selector_List, wrapped->selector())) {
910
+ if (Selector_List_Obj not_list = Cast<Selector_List>(wrapped->selector())) {
845
911
  if (not_list->is_superselector_of(rhs, wrapped->name())) return false;
846
912
  } else {
847
913
  throw std::runtime_error("wrapped not selector is not a list");
848
914
  }
849
915
  }
850
916
  if (wrapped->name() == ":matches" || wrapped->name() == ":-moz-any") {
851
- lhs = wrapped->selector();
852
- if (Selector_List_Obj list = SASS_MEMORY_CAST(Selector_List, wrapped->selector())) {
853
- if (Compound_Selector_Obj comp = SASS_MEMORY_CAST(Compound_Selector, rhs)) {
917
+ wlhs = wrapped->selector();
918
+ if (Selector_List_Obj list = Cast<Selector_List>(wrapped->selector())) {
919
+ if (Compound_Selector_Obj comp = Cast<Compound_Selector>(rhs)) {
854
920
  if (!wrapping.empty() && wrapping != wrapped->name()) return false;
855
921
  if (wrapping.empty() || wrapping != wrapped->name()) {;
856
922
  if (list->is_superselector_of(comp, wrapped->name())) return true;
@@ -858,26 +924,25 @@ namespace Sass {
858
924
  }
859
925
  }
860
926
  }
861
- Simple_Selector_Ptr rhs_sel = rhs->elements().size() > i ? &(*rhs)[i] : 0;
862
- if (Wrapped_Selector_Ptr wrapped_r = dynamic_cast<Wrapped_Selector_Ptr>(rhs_sel)) {
927
+ Simple_Selector_Ptr rhs_sel = NULL;
928
+ if (rhs->elements().size() > i) rhs_sel = (*rhs)[i];
929
+ if (Wrapped_Selector_Ptr wrapped_r = Cast<Wrapped_Selector>(rhs_sel)) {
863
930
  if (wrapped->name() == wrapped_r->name()) {
864
931
  if (wrapped->is_superselector_of(wrapped_r)) {
865
932
  continue;
866
- rset.insert(lhs->to_string());
867
-
868
933
  }}
869
934
  }
870
935
  }
871
936
  // match from here on as strings
872
- lset.insert(lhs->to_string());
937
+ lset.insert(wlhs->to_string());
873
938
  }
874
939
 
875
940
  for (size_t n = 0, nL = rhs->length(); n < nL; ++n)
876
941
  {
877
- Selector_Obj r = &(*rhs)[n];
878
- if (Wrapped_Selector_Obj wrapped = SASS_MEMORY_CAST(Wrapped_Selector, r)) {
942
+ Selector_Obj r = (*rhs)[n];
943
+ if (Wrapped_Selector_Obj wrapped = Cast<Wrapped_Selector>(r)) {
879
944
  if (wrapped->name() == ":not") {
880
- if (Selector_List_Obj ls = SASS_MEMORY_CAST(Selector_List, wrapped->selector())) {
945
+ if (Selector_List_Obj ls = Cast<Selector_List>(wrapped->selector())) {
881
946
  ls->remove_parent_selectors();
882
947
  if (is_superselector_of(ls, wrapped->name())) return false;
883
948
  }
@@ -886,7 +951,7 @@ namespace Sass {
886
951
  if (!wrapping.empty()) {
887
952
  if (wrapping != wrapped->name()) return false;
888
953
  }
889
- if (Selector_List_Obj ls = SASS_MEMORY_CAST(Selector_List, wrapped->selector())) {
954
+ if (Selector_List_Obj ls = Cast<Selector_List>(wrapped->selector())) {
890
955
  ls->remove_parent_selectors();
891
956
  return (is_superselector_of(ls, wrapped->name()));
892
957
  }
@@ -915,7 +980,7 @@ namespace Sass {
915
980
  0);
916
981
  }
917
982
 
918
- Selector_List_Ptr Complex_Selector::unify_with(Complex_Selector_Ptr other, Context& ctx)
983
+ Selector_List_Ptr Complex_Selector::unify_with(Complex_Selector_Ptr other)
919
984
  {
920
985
 
921
986
  // get last tails (on the right side)
@@ -941,7 +1006,7 @@ namespace Sass {
941
1006
  SASS_ASSERT(r_last_head, "rhs head is null");
942
1007
 
943
1008
  // get the unification of the last compound selectors
944
- Compound_Selector_Obj unified = r_last_head->unify_with(&l_last_head, ctx);
1009
+ Compound_Selector_Obj unified = r_last_head->unify_with(l_last_head);
945
1010
 
946
1011
  // abort if we could not unify heads
947
1012
  if (unified == 0) return 0;
@@ -958,28 +1023,28 @@ namespace Sass {
958
1023
  }
959
1024
 
960
1025
  // create nodes from both selectors
961
- Node lhsNode = complexSelectorToNode(this, ctx);
962
- Node rhsNode = complexSelectorToNode(other, ctx);
1026
+ Node lhsNode = complexSelectorToNode(this);
1027
+ Node rhsNode = complexSelectorToNode(other);
963
1028
 
964
1029
  // overwrite universal base
965
1030
  if (!is_universal)
966
1031
  {
967
1032
  // create some temporaries to convert to node
968
1033
  Complex_Selector_Obj fake = unified->to_complex();
969
- Node unified_node = complexSelectorToNode(&fake, ctx);
1034
+ Node unified_node = complexSelectorToNode(fake);
970
1035
  // add to permutate the list?
971
1036
  rhsNode.plus(unified_node);
972
1037
  }
973
1038
 
974
1039
  // do some magic we inherit from node and extend
975
- Node node = Extend::subweave(lhsNode, rhsNode, ctx);
976
- Selector_List_Ptr result = SASS_MEMORY_NEW(Selector_List, pstate());
1040
+ Node node = subweave(lhsNode, rhsNode);
1041
+ Selector_List_Obj result = SASS_MEMORY_NEW(Selector_List, pstate());
977
1042
  NodeDequePtr col = node.collection(); // move from collection to list
978
1043
  for (NodeDeque::iterator it = col->begin(), end = col->end(); it != end; it++)
979
- { result->append(nodeToComplexSelector(Node::naiveTrim(*it, ctx), ctx)); }
1044
+ { result->append(nodeToComplexSelector(Node::naiveTrim(*it))); }
980
1045
 
981
1046
  // only return if list has some entries
982
- return result->length() ? result : 0;
1047
+ return result->length() ? result.detach() : 0;
983
1048
 
984
1049
  }
985
1050
 
@@ -992,8 +1057,8 @@ namespace Sass {
992
1057
  // create temporary vectors and sort them
993
1058
  std::vector<Simple_Selector_Obj> l_lst = this->elements();
994
1059
  std::vector<Simple_Selector_Obj> r_lst = rhs.elements();
995
- std::sort(l_lst.begin(), l_lst.end(), cmp_simple_selector());
996
- std::sort(r_lst.begin(), r_lst.end(), cmp_simple_selector());
1060
+ std::sort(l_lst.begin(), l_lst.end(), OrderNodes());
1061
+ std::sort(r_lst.begin(), r_lst.end(), OrderNodes());
997
1062
  // process loop
998
1063
  while (true)
999
1064
  {
@@ -1012,12 +1077,7 @@ namespace Sass {
1012
1077
  // advance now
1013
1078
  ++i; ++n;
1014
1079
  }
1015
- // no mismatch
1016
- return true;
1017
- }
1018
-
1019
- bool Complex_Selector_Pointer_Compare::operator() (const Complex_Selector_Obj& pLeft, const Complex_Selector_Obj& pRight) const {
1020
- return *pLeft < *pRight;
1080
+ // there is no break?!
1021
1081
  }
1022
1082
 
1023
1083
  bool Complex_Selector::is_superselector_of(Compound_Selector_Obj rhs, std::string wrapping)
@@ -1043,7 +1103,7 @@ namespace Sass {
1043
1103
  { return false; }
1044
1104
 
1045
1105
  if (l_len == 1)
1046
- { return lhs->head()->is_superselector_of(&rhs->last()->head(), wrapping); }
1106
+ { return lhs->head()->is_superselector_of(rhs->last()->head(), wrapping); }
1047
1107
 
1048
1108
  // we have to look one tail deeper, since we cary the
1049
1109
  // combinator around for it (which is important here)
@@ -1054,7 +1114,7 @@ namespace Sass {
1054
1114
  if (lhs_tail->head() && !rhs_tail->head()) return false;
1055
1115
  if (!lhs_tail->head() && rhs_tail->head()) return false;
1056
1116
  if (lhs_tail->head() && rhs_tail->head()) {
1057
- if (!lhs_tail->head()->is_superselector_of(&rhs_tail->head())) return false;
1117
+ if (!lhs_tail->head()->is_superselector_of(rhs_tail->head())) return false;
1058
1118
  }
1059
1119
  }
1060
1120
 
@@ -1063,7 +1123,7 @@ namespace Sass {
1063
1123
  for (size_t i = 0, L = rhs->length(); i < L; ++i) {
1064
1124
  if (i == L-1)
1065
1125
  { return false; }
1066
- if (lhs->head() && marker->head() && lhs->head()->is_superselector_of(&marker->head(), wrapping))
1126
+ if (lhs->head() && marker->head() && lhs->head()->is_superselector_of(marker->head(), wrapping))
1067
1127
  { found = true; break; }
1068
1128
  marker = marker->tail();
1069
1129
  }
@@ -1089,20 +1149,15 @@ namespace Sass {
1089
1149
  { return false; }
1090
1150
  if (!(lhs->combinator() == Complex_Selector::PRECEDES ? marker->combinator() != Complex_Selector::PARENT_OF : lhs->combinator() == marker->combinator()))
1091
1151
  { return false; }
1092
- return lhs->tail()->is_superselector_of(&marker->tail());
1152
+ return lhs->tail()->is_superselector_of(marker->tail());
1093
1153
  }
1094
1154
  else if (marker->combinator() != Complex_Selector::ANCESTOR_OF)
1095
1155
  {
1096
1156
  if (marker->combinator() != Complex_Selector::PARENT_OF)
1097
1157
  { return false; }
1098
- return lhs->tail()->is_superselector_of(&marker->tail());
1158
+ return lhs->tail()->is_superselector_of(marker->tail());
1099
1159
  }
1100
- else
1101
- {
1102
- return lhs->tail()->is_superselector_of(&marker->tail());
1103
- }
1104
- // catch-all
1105
- return false;
1160
+ return lhs->tail()->is_superselector_of(marker->tail());
1106
1161
  }
1107
1162
 
1108
1163
  size_t Complex_Selector::length() const
@@ -1112,20 +1167,11 @@ namespace Sass {
1112
1167
  return 1 + tail()->length();
1113
1168
  }
1114
1169
 
1115
- Complex_Selector_Obj Complex_Selector::context(Context& ctx)
1116
- {
1117
- if (!tail()) return 0;
1118
- if (!head()) return tail()->context(ctx);
1119
- Complex_Selector_Obj cpy = SASS_MEMORY_NEW(Complex_Selector, pstate(), combinator(), head(), tail()->context(ctx));
1120
- cpy->media_block(media_block());
1121
- return cpy;
1122
- }
1123
-
1124
1170
  // append another complex selector at the end
1125
1171
  // check if we need to append some headers
1126
1172
  // then we need to check for the combinator
1127
1173
  // only then we can safely set the new tail
1128
- void Complex_Selector::append(Context& ctx, Complex_Selector_Obj ss)
1174
+ void Complex_Selector::append(Complex_Selector_Obj ss, Backtraces& traces)
1129
1175
  {
1130
1176
 
1131
1177
  Complex_Selector_Obj t = ss->tail();
@@ -1139,47 +1185,49 @@ namespace Sass {
1139
1185
  // append old headers
1140
1186
  if (h && h->length()) {
1141
1187
  if (last()->combinator() != ANCESTOR_OF && c != ANCESTOR_OF) {
1142
- error("Invalid parent selector", pstate_);
1188
+ traces.push_back(Backtrace(pstate()));
1189
+ throw Exception::InvalidParent(this, traces, ss);
1143
1190
  } else if (last()->head_ && last()->head_->length()) {
1144
1191
  Compound_Selector_Obj rh = last()->head();
1145
- size_t i = 0, L = h->length();
1146
- if (SASS_MEMORY_CAST(Element_Selector, h->first())) {
1147
- if (Class_Selector_Ptr sq = SASS_MEMORY_CAST(Class_Selector, rh->last())) {
1148
- Class_Selector_Ptr sqs = SASS_MEMORY_COPY(sq);
1192
+ size_t i;
1193
+ size_t L = h->length();
1194
+ if (Cast<Element_Selector>(h->first())) {
1195
+ if (Class_Selector_Ptr cs = Cast<Class_Selector>(rh->last())) {
1196
+ Class_Selector_Ptr sqs = SASS_MEMORY_COPY(cs);
1149
1197
  sqs->name(sqs->name() + (*h)[0]->name());
1150
1198
  sqs->pstate((*h)[0]->pstate());
1151
1199
  (*rh)[rh->length()-1] = sqs;
1152
1200
  rh->pstate(h->pstate());
1153
- for (i = 1; i < L; ++i) rh->append(&(*h)[i]);
1154
- } else if (Id_Selector_Ptr sq = SASS_MEMORY_CAST(Id_Selector, rh->last())) {
1155
- Id_Selector_Ptr sqs = SASS_MEMORY_COPY(sq);
1201
+ for (i = 1; i < L; ++i) rh->append((*h)[i]);
1202
+ } else if (Id_Selector_Ptr is = Cast<Id_Selector>(rh->last())) {
1203
+ Id_Selector_Ptr sqs = SASS_MEMORY_COPY(is);
1156
1204
  sqs->name(sqs->name() + (*h)[0]->name());
1157
1205
  sqs->pstate((*h)[0]->pstate());
1158
1206
  (*rh)[rh->length()-1] = sqs;
1159
1207
  rh->pstate(h->pstate());
1160
- for (i = 1; i < L; ++i) rh->append(&(*h)[i]);
1161
- } else if (Element_Selector_Ptr ts = SASS_MEMORY_CAST(Element_Selector, rh->last())) {
1208
+ for (i = 1; i < L; ++i) rh->append((*h)[i]);
1209
+ } else if (Element_Selector_Ptr ts = Cast<Element_Selector>(rh->last())) {
1162
1210
  Element_Selector_Ptr tss = SASS_MEMORY_COPY(ts);
1163
1211
  tss->name(tss->name() + (*h)[0]->name());
1164
1212
  tss->pstate((*h)[0]->pstate());
1165
1213
  (*rh)[rh->length()-1] = tss;
1166
1214
  rh->pstate(h->pstate());
1167
- for (i = 1; i < L; ++i) rh->append(&(*h)[i]);
1168
- } else if (Placeholder_Selector_Ptr ps = SASS_MEMORY_CAST(Placeholder_Selector, rh->last())) {
1215
+ for (i = 1; i < L; ++i) rh->append((*h)[i]);
1216
+ } else if (Placeholder_Selector_Ptr ps = Cast<Placeholder_Selector>(rh->last())) {
1169
1217
  Placeholder_Selector_Ptr pss = SASS_MEMORY_COPY(ps);
1170
1218
  pss->name(pss->name() + (*h)[0]->name());
1171
1219
  pss->pstate((*h)[0]->pstate());
1172
1220
  (*rh)[rh->length()-1] = pss;
1173
1221
  rh->pstate(h->pstate());
1174
- for (i = 1; i < L; ++i) rh->append(&(*h)[i]);
1222
+ for (i = 1; i < L; ++i) rh->append((*h)[i]);
1175
1223
  } else {
1176
- last()->head_->concat(&h);
1224
+ last()->head_->concat(h);
1177
1225
  }
1178
1226
  } else {
1179
- last()->head_->concat(&h);
1227
+ last()->head_->concat(h);
1180
1228
  }
1181
- } else {
1182
- last()->head_->concat(&h);
1229
+ } else if (last()->head_) {
1230
+ last()->head_->concat(h);
1183
1231
  }
1184
1232
  } else {
1185
1233
  // std::cerr << "has no or empty head\n";
@@ -1201,28 +1249,35 @@ namespace Sass {
1201
1249
  }
1202
1250
  }
1203
1251
 
1252
+ }
1204
1253
 
1254
+ Selector_List_Obj Selector_List::eval(Eval& eval)
1255
+ {
1256
+ Selector_List_Obj list = schema() ?
1257
+ eval(schema()) : eval(this);
1258
+ list->schema(schema());
1259
+ return list;
1205
1260
  }
1206
1261
 
1207
- Selector_List_Ptr Selector_List::resolve_parent_refs(Context& ctx, std::vector<Selector_List_Obj>& pstack, bool implicit_parent)
1262
+ Selector_List_Ptr Selector_List::resolve_parent_refs(std::vector<Selector_List_Obj>& pstack, Backtraces& traces, bool implicit_parent)
1208
1263
  {
1209
1264
  if (!this->has_parent_ref()) return this;
1210
1265
  Selector_List_Ptr ss = SASS_MEMORY_NEW(Selector_List, pstate());
1211
- Selector_List_Ptr ps = &pstack.back();
1266
+ Selector_List_Ptr ps = pstack.back();
1212
1267
  for (size_t pi = 0, pL = ps->length(); pi < pL; ++pi) {
1213
1268
  for (size_t si = 0, sL = this->length(); si < sL; ++si) {
1214
- Selector_List_Obj rv = at(si)->resolve_parent_refs(ctx, pstack, implicit_parent);
1215
- ss->concat(&rv);
1269
+ Selector_List_Obj rv = at(si)->resolve_parent_refs(pstack, traces, implicit_parent);
1270
+ ss->concat(rv);
1216
1271
  }
1217
1272
  }
1218
1273
  return ss;
1219
1274
  }
1220
1275
 
1221
- Selector_List_Ptr Complex_Selector::resolve_parent_refs(Context& ctx, std::vector<Selector_List_Obj>& pstack, bool implicit_parent)
1276
+ Selector_List_Ptr Complex_Selector::resolve_parent_refs(std::vector<Selector_List_Obj>& pstack, Backtraces& traces, bool implicit_parent)
1222
1277
  {
1223
1278
  Complex_Selector_Obj tail = this->tail();
1224
1279
  Compound_Selector_Obj head = this->head();
1225
- Selector_List_Ptr parents = &pstack.back();
1280
+ Selector_List_Ptr parents = pstack.back();
1226
1281
 
1227
1282
  if (!this->has_real_parent_ref() && !implicit_parent) {
1228
1283
  Selector_List_Ptr retval = SASS_MEMORY_NEW(Selector_List, pstate());
@@ -1231,14 +1286,14 @@ namespace Sass {
1231
1286
  }
1232
1287
 
1233
1288
  // first resolve_parent_refs the tail (which may return an expanded list)
1234
- Selector_List_Obj tails = tail ? tail->resolve_parent_refs(ctx, pstack, implicit_parent) : 0;
1289
+ Selector_List_Obj tails = tail ? tail->resolve_parent_refs(pstack, traces, implicit_parent) : 0;
1235
1290
 
1236
1291
  if (head && head->length() > 0) {
1237
1292
 
1238
1293
  Selector_List_Obj retval;
1239
1294
  // we have a parent selector in a simple compound list
1240
1295
  // mix parent complex selector into the compound list
1241
- if (SASS_MEMORY_CAST(Parent_Selector, (*head)[0])) {
1296
+ if (Cast<Parent_Selector>((*head)[0])) {
1242
1297
  retval = SASS_MEMORY_NEW(Selector_List, pstate());
1243
1298
 
1244
1299
  // it turns out that real parent references reach
@@ -1246,7 +1301,7 @@ namespace Sass {
1246
1301
  if (parents == NULL && head->has_real_parent_ref()) {
1247
1302
  int i = pstack.size() - 1;
1248
1303
  while (!parents && i > -1) {
1249
- parents = &pstack.at(i--);
1304
+ parents = pstack.at(i--);
1250
1305
  }
1251
1306
  }
1252
1307
 
@@ -1258,22 +1313,26 @@ namespace Sass {
1258
1313
  Complex_Selector_Obj parent = (*parents)[i];
1259
1314
  Complex_Selector_Obj s = SASS_MEMORY_CLONE(parent);
1260
1315
  Complex_Selector_Obj ss = SASS_MEMORY_CLONE(this);
1261
- ss->tail(t ? SASS_MEMORY_CLONE(t) : 0);
1316
+ ss->tail(t ? SASS_MEMORY_CLONE(t) : NULL);
1262
1317
  Compound_Selector_Obj h = SASS_MEMORY_COPY(head_);
1263
1318
  // remove parent selector from sequence
1264
- if (h->length()) h->erase(h->begin());
1265
- ss->head(h->length() ? &h : 0);
1266
- // adjust for parent selector (1 char)
1267
1319
  if (h->length()) {
1268
- ParserState state(h->at(0)->pstate());
1269
- state.offset.column += 1;
1270
- state.column -= 1;
1271
- (*h)[0]->pstate(state);
1320
+ h->erase(h->begin());
1321
+ ss->head(h);
1322
+ } else {
1323
+ ss->head(NULL);
1272
1324
  }
1325
+ // adjust for parent selector (1 char)
1326
+ // if (h->length()) {
1327
+ // ParserState state(h->at(0)->pstate());
1328
+ // state.offset.column += 1;
1329
+ // state.column -= 1;
1330
+ // (*h)[0]->pstate(state);
1331
+ // }
1273
1332
  // keep old parser state
1274
1333
  s->pstate(pstate());
1275
1334
  // append new tail
1276
- s->append(ctx, ss);
1335
+ s->append(ss, traces);
1277
1336
  retval->append(s);
1278
1337
  }
1279
1338
  }
@@ -1288,26 +1347,31 @@ namespace Sass {
1288
1347
  // this is only if valid if the parent has no trailing op
1289
1348
  // otherwise we cannot append more simple selectors to head
1290
1349
  if (parent->last()->combinator() != ANCESTOR_OF) {
1291
- throw Exception::InvalidParent(&parent, &ss);
1350
+ traces.push_back(Backtrace(pstate()));
1351
+ throw Exception::InvalidParent(parent, traces, ss);
1292
1352
  }
1293
- ss->tail(tail ? SASS_MEMORY_CLONE(tail) : 0);
1353
+ ss->tail(tail ? SASS_MEMORY_CLONE(tail) : NULL);
1294
1354
  Compound_Selector_Obj h = SASS_MEMORY_COPY(head_);
1295
1355
  // remove parent selector from sequence
1296
- if (h->length()) h->erase(h->begin());
1297
- ss->head(h->length() ? &h : 0);
1356
+ if (h->length()) {
1357
+ h->erase(h->begin());
1358
+ ss->head(h);
1359
+ } else {
1360
+ ss->head(NULL);
1361
+ }
1298
1362
  // \/ IMO ruby sass bug \/
1299
1363
  ss->has_line_feed(false);
1300
1364
  // adjust for parent selector (1 char)
1301
- if (h->length()) {
1302
- ParserState state(h->at(0)->pstate());
1303
- state.offset.column += 1;
1304
- state.column -= 1;
1305
- (*h)[0]->pstate(state);
1306
- }
1365
+ // if (h->length()) {
1366
+ // ParserState state(h->at(0)->pstate());
1367
+ // state.offset.column += 1;
1368
+ // state.column -= 1;
1369
+ // (*h)[0]->pstate(state);
1370
+ // }
1307
1371
  // keep old parser state
1308
1372
  s->pstate(pstate());
1309
1373
  // append new tail
1310
- s->append(ctx, &ss);
1374
+ s->append(ss, traces);
1311
1375
  retval->append(s);
1312
1376
  }
1313
1377
  }
@@ -1320,7 +1384,7 @@ namespace Sass {
1320
1384
  cpy->tail(SASS_MEMORY_CLONE(tails->at(n)));
1321
1385
  cpy->head(SASS_MEMORY_NEW(Compound_Selector, head->pstate()));
1322
1386
  for (size_t i = 1, L = this->head()->length(); i < L; ++i)
1323
- cpy->head()->append(&(*this->head())[i]);
1387
+ cpy->head()->append((*this->head())[i]);
1324
1388
  if (!cpy->head()->length()) cpy->head(0);
1325
1389
  retval->append(cpy->skip_empty_reference());
1326
1390
  }
@@ -1330,7 +1394,7 @@ namespace Sass {
1330
1394
  Complex_Selector_Obj cpy = SASS_MEMORY_CLONE(this);
1331
1395
  cpy->head(SASS_MEMORY_NEW(Compound_Selector, head->pstate()));
1332
1396
  for (size_t i = 1, L = this->head()->length(); i < L; ++i)
1333
- cpy->head()->append(&(*this->head())[i]);
1397
+ cpy->head()->append((*this->head())[i]);
1334
1398
  if (!cpy->head()->length()) cpy->head(0);
1335
1399
  retval->append(cpy->skip_empty_reference());
1336
1400
  }
@@ -1338,13 +1402,13 @@ namespace Sass {
1338
1402
  }
1339
1403
  // no parent selector in head
1340
1404
  else {
1341
- retval = this->tails(ctx, &tails);
1405
+ retval = this->tails(tails);
1342
1406
  }
1343
1407
 
1344
1408
  for (Simple_Selector_Obj ss : head->elements()) {
1345
- if (Wrapped_Selector_Ptr ws = SASS_MEMORY_CAST(Wrapped_Selector, ss)) {
1346
- if (Selector_List_Ptr sl = SASS_MEMORY_CAST(Selector_List, ws->selector())) {
1347
- if (parents) ws->selector(sl->resolve_parent_refs(ctx, pstack, implicit_parent));
1409
+ if (Wrapped_Selector_Ptr ws = Cast<Wrapped_Selector>(ss)) {
1410
+ if (Selector_List_Ptr sl = Cast<Selector_List>(ws->selector())) {
1411
+ if (parents) ws->selector(sl->resolve_parent_refs(pstack, traces, implicit_parent));
1348
1412
  }
1349
1413
  }
1350
1414
  }
@@ -1353,15 +1417,10 @@ namespace Sass {
1353
1417
 
1354
1418
  }
1355
1419
  // has no head
1356
- else {
1357
- return this->tails(ctx, &tails);
1358
- }
1359
-
1360
- // unreachable
1361
- return 0;
1420
+ return this->tails(tails);
1362
1421
  }
1363
1422
 
1364
- Selector_List_Ptr Complex_Selector::tails(Context& ctx, Selector_List_Ptr tails)
1423
+ Selector_List_Ptr Complex_Selector::tails(Selector_List_Ptr tails)
1365
1424
  {
1366
1425
  Selector_List_Ptr rv = SASS_MEMORY_NEW(Selector_List, pstate_);
1367
1426
  if (tails && tails->length()) {
@@ -1389,21 +1448,27 @@ namespace Sass {
1389
1448
  // get the head
1390
1449
  head = cur->head_;
1391
1450
  // abort (and return) if it is not a parent selector
1392
- if (!head || head->length() != 1 || !SASS_MEMORY_CAST(Parent_Selector, (*head)[0])) {
1451
+ if (!head || head->length() != 1 || !Cast<Parent_Selector>((*head)[0])) {
1393
1452
  break;
1394
1453
  }
1395
1454
  // advance to next
1396
1455
  cur = cur->tail_;
1397
1456
  }
1398
1457
  // result
1399
- return &cur;
1458
+ return cur;
1400
1459
  }
1401
1460
 
1402
1461
  // return the last tail that is defined
1403
1462
  Complex_Selector_Obj Complex_Selector::last()
1404
1463
  {
1405
- // ToDo: implement with a while loop
1406
- return tail_? tail_->last() : this;
1464
+ Complex_Selector_Ptr cur = this;
1465
+ Complex_Selector_Ptr nxt = cur;
1466
+ // loop until last
1467
+ while (nxt) {
1468
+ cur = nxt;
1469
+ nxt = cur->tail();
1470
+ }
1471
+ return cur;
1407
1472
  }
1408
1473
 
1409
1474
  Complex_Selector::Combinator Complex_Selector::clear_innermost()
@@ -1474,7 +1539,31 @@ namespace Sass {
1474
1539
  }
1475
1540
  }
1476
1541
 
1477
- bool Selector_List::has_parent_ref()
1542
+ size_t Wrapped_Selector::hash()
1543
+ {
1544
+ if (hash_ == 0) {
1545
+ hash_combine(hash_, Simple_Selector::hash());
1546
+ if (selector_) hash_combine(hash_, selector_->hash());
1547
+ }
1548
+ return hash_;
1549
+ }
1550
+ bool Wrapped_Selector::has_parent_ref() const {
1551
+ // if (has_reference()) return true;
1552
+ if (!selector()) return false;
1553
+ return selector()->has_parent_ref();
1554
+ }
1555
+ bool Wrapped_Selector::has_real_parent_ref() const {
1556
+ // if (has_reference()) return true;
1557
+ if (!selector()) return false;
1558
+ return selector()->has_real_parent_ref();
1559
+ }
1560
+ unsigned long Wrapped_Selector::specificity() const
1561
+ {
1562
+ return selector_ ? selector_->specificity() : 0;
1563
+ }
1564
+
1565
+
1566
+ bool Selector_List::has_parent_ref() const
1478
1567
  {
1479
1568
  for (Complex_Selector_Obj s : elements()) {
1480
1569
  if (s && s->has_parent_ref()) return true;
@@ -1482,7 +1571,7 @@ namespace Sass {
1482
1571
  return false;
1483
1572
  }
1484
1573
 
1485
- bool Selector_List::has_real_parent_ref()
1574
+ bool Selector_List::has_real_parent_ref() const
1486
1575
  {
1487
1576
  for (Complex_Selector_Obj s : elements()) {
1488
1577
  if (s && s->has_real_parent_ref()) return true;
@@ -1490,18 +1579,18 @@ namespace Sass {
1490
1579
  return false;
1491
1580
  }
1492
1581
 
1493
- bool Selector_Schema::has_parent_ref()
1582
+ bool Selector_Schema::has_parent_ref() const
1494
1583
  {
1495
- if (String_Schema_Obj schema = SASS_MEMORY_CAST(String_Schema, contents())) {
1496
- return schema->length() > 0 && SASS_MEMORY_CAST(Parent_Selector, schema->at(0)) != NULL;
1584
+ if (String_Schema_Obj schema = Cast<String_Schema>(contents())) {
1585
+ return schema->length() > 0 && Cast<Parent_Selector>(schema->at(0)) != NULL;
1497
1586
  }
1498
1587
  return false;
1499
1588
  }
1500
1589
 
1501
- bool Selector_Schema::has_real_parent_ref()
1590
+ bool Selector_Schema::has_real_parent_ref() const
1502
1591
  {
1503
- if (String_Schema_Obj schema = SASS_MEMORY_CAST(String_Schema, contents())) {
1504
- Parent_Selector_Obj p = SASS_MEMORY_CAST(Parent_Selector, schema->at(0));
1592
+ if (String_Schema_Obj schema = Cast<String_Schema>(contents())) {
1593
+ Parent_Selector_Obj p = Cast<Parent_Selector>(schema->at(0));
1505
1594
  return schema->length() > 0 && p && p->is_real_parent_ref();
1506
1595
  }
1507
1596
  return false;
@@ -1518,7 +1607,7 @@ namespace Sass {
1518
1607
  {
1519
1608
  // Check every rhs selector against left hand list
1520
1609
  for(size_t i = 0, L = sub->length(); i < L; ++i) {
1521
- if (!is_superselector_of(&(*sub)[i], wrapping)) return false;
1610
+ if (!is_superselector_of((*sub)[i], wrapping)) return false;
1522
1611
  }
1523
1612
  return true;
1524
1613
  }
@@ -1529,7 +1618,7 @@ namespace Sass {
1529
1618
  {
1530
1619
  // Check every rhs selector against left hand list
1531
1620
  for(size_t i = 0, L = sub->length(); i < L; ++i) {
1532
- if (!is_superselector_of(&(*sub)[i], wrapping)) return false;
1621
+ if (!is_superselector_of((*sub)[i], wrapping)) return false;
1533
1622
  }
1534
1623
  return true;
1535
1624
  }
@@ -1556,18 +1645,18 @@ namespace Sass {
1556
1645
  return false;
1557
1646
  }
1558
1647
 
1559
- Selector_List_Ptr Selector_List::unify_with(Selector_List_Ptr rhs, Context& ctx) {
1648
+ Selector_List_Ptr Selector_List::unify_with(Selector_List_Ptr rhs) {
1560
1649
  std::vector<Complex_Selector_Obj> unified_complex_selectors;
1561
1650
  // Unify all of children with RHS's children, storing the results in `unified_complex_selectors`
1562
1651
  for (size_t lhs_i = 0, lhs_L = length(); lhs_i < lhs_L; ++lhs_i) {
1563
1652
  Complex_Selector_Obj seq1 = (*this)[lhs_i];
1564
1653
  for(size_t rhs_i = 0, rhs_L = rhs->length(); rhs_i < rhs_L; ++rhs_i) {
1565
- Complex_Selector_Ptr seq2 = &rhs->at(rhs_i);
1654
+ Complex_Selector_Ptr seq2 = rhs->at(rhs_i);
1566
1655
 
1567
- Selector_List_Obj result = seq1->unify_with(seq2, ctx);
1656
+ Selector_List_Obj result = seq1->unify_with(seq2);
1568
1657
  if( result ) {
1569
1658
  for(size_t i = 0, L = result->length(); i < L; ++i) {
1570
- unified_complex_selectors.push_back( &(*result)[i] );
1659
+ unified_complex_selectors.push_back( (*result)[i] );
1571
1660
  }
1572
1661
  }
1573
1662
  }
@@ -1581,7 +1670,7 @@ namespace Sass {
1581
1670
  return final_result;
1582
1671
  }
1583
1672
 
1584
- void Selector_List::populate_extends(Selector_List_Obj extendee, Context& ctx, Subset_Map& extends)
1673
+ void Selector_List::populate_extends(Selector_List_Obj extendee, Subset_Map& extends)
1585
1674
  {
1586
1675
 
1587
1676
  Selector_List_Ptr extender = this;
@@ -1594,7 +1683,7 @@ namespace Sass {
1594
1683
  Complex_Selector_Obj pIter = complex_sel;
1595
1684
  while (pIter) {
1596
1685
  Compound_Selector_Obj pHead = pIter->head();
1597
- if (pHead && SASS_MEMORY_CAST(Parent_Selector, pHead->elements()[0]) == NULL) {
1686
+ if (pHead && Cast<Parent_Selector>(pHead->elements()[0]) == NULL) {
1598
1687
  compound_sel = pHead;
1599
1688
  break;
1600
1689
  }
@@ -1603,32 +1692,24 @@ namespace Sass {
1603
1692
  }
1604
1693
 
1605
1694
  if (!pIter->head() || pIter->tail()) {
1606
- error("nested selectors may not be extended", c->pstate());
1695
+ coreError("nested selectors may not be extended", c->pstate());
1607
1696
  }
1608
1697
 
1609
1698
  compound_sel->is_optional(extendee->is_optional());
1610
1699
 
1611
1700
  for (size_t i = 0, L = extender->length(); i < L; ++i) {
1612
- extends.put(compound_sel, std::make_pair(&(*extender)[i], &compound_sel));
1701
+ extends.put(compound_sel, std::make_pair((*extender)[i], compound_sel));
1613
1702
  }
1614
1703
  }
1615
1704
  };
1616
1705
 
1617
- std::vector<std::string> Compound_Selector::to_str_vec()
1618
- {
1619
- std::vector<std::string> result(length());
1620
- for (size_t i = 0, L = length(); i < L; ++i)
1621
- { result.push_back((*this)[i]->to_string()); }
1622
- return result;
1623
- }
1624
-
1625
1706
  void Compound_Selector::append(Simple_Selector_Ptr element)
1626
1707
  {
1627
1708
  Vectorized<Simple_Selector_Obj>::append(element);
1628
1709
  pstate_.offset += element->pstate().offset;
1629
1710
  }
1630
1711
 
1631
- Compound_Selector_Ptr Compound_Selector::minus(Compound_Selector_Ptr rhs, Context& ctx)
1712
+ Compound_Selector_Ptr Compound_Selector::minus(Compound_Selector_Ptr rhs)
1632
1713
  {
1633
1714
  Compound_Selector_Ptr result = SASS_MEMORY_NEW(Compound_Selector, pstate());
1634
1715
  // result->has_parent_reference(has_parent_reference());
@@ -1637,24 +1718,24 @@ namespace Sass {
1637
1718
  for (size_t i = 0, L = length(); i < L; ++i)
1638
1719
  {
1639
1720
  bool found = false;
1640
- std::string thisSelector((*this)[i]->to_string(ctx.c_options));
1721
+ std::string thisSelector((*this)[i]->to_string());
1641
1722
  for (size_t j = 0, M = rhs->length(); j < M; ++j)
1642
1723
  {
1643
- if (thisSelector == (*rhs)[j]->to_string(ctx.c_options))
1724
+ if (thisSelector == (*rhs)[j]->to_string())
1644
1725
  {
1645
1726
  found = true;
1646
1727
  break;
1647
1728
  }
1648
1729
  }
1649
- if (!found) result->append(&(*this)[i]);
1730
+ if (!found) result->append((*this)[i]);
1650
1731
  }
1651
1732
 
1652
1733
  return result;
1653
1734
  }
1654
1735
 
1655
- void Compound_Selector::mergeSources(SourcesSet& sources, Context& ctx)
1736
+ void Compound_Selector::mergeSources(ComplexSelectorSet& sources)
1656
1737
  {
1657
- for (SourcesSet::iterator iterator = sources.begin(), endIterator = sources.end(); iterator != endIterator; ++iterator) {
1738
+ for (ComplexSelectorSet::iterator iterator = sources.begin(), endIterator = sources.end(); iterator != endIterator; ++iterator) {
1658
1739
  this->sources_.insert(SASS_MEMORY_CLONE(*iterator));
1659
1740
  }
1660
1741
  }
@@ -1686,38 +1767,38 @@ namespace Sass {
1686
1767
  void Arguments::adjust_after_pushing(Argument_Obj a)
1687
1768
  {
1688
1769
  if (!a->name().empty()) {
1689
- if (/* has_rest_argument_ || */ has_keyword_argument_) {
1690
- error("named arguments must precede variable-length argument", a->pstate());
1770
+ if (has_keyword_argument()) {
1771
+ coreError("named arguments must precede variable-length argument", a->pstate());
1691
1772
  }
1692
- has_named_arguments_ = true;
1773
+ has_named_arguments(true);
1693
1774
  }
1694
1775
  else if (a->is_rest_argument()) {
1695
- if (has_rest_argument_) {
1696
- error("functions and mixins may only be called with one variable-length argument", a->pstate());
1776
+ if (has_rest_argument()) {
1777
+ coreError("functions and mixins may only be called with one variable-length argument", a->pstate());
1697
1778
  }
1698
1779
  if (has_keyword_argument_) {
1699
- error("only keyword arguments may follow variable arguments", a->pstate());
1780
+ coreError("only keyword arguments may follow variable arguments", a->pstate());
1700
1781
  }
1701
- has_rest_argument_ = true;
1782
+ has_rest_argument(true);
1702
1783
  }
1703
1784
  else if (a->is_keyword_argument()) {
1704
- if (has_keyword_argument_) {
1705
- error("functions and mixins may only be called with one keyword argument", a->pstate());
1785
+ if (has_keyword_argument()) {
1786
+ coreError("functions and mixins may only be called with one keyword argument", a->pstate());
1706
1787
  }
1707
- has_keyword_argument_ = true;
1788
+ has_keyword_argument(true);
1708
1789
  }
1709
1790
  else {
1710
- if (has_rest_argument_) {
1711
- error("ordinal arguments must precede variable-length arguments", a->pstate());
1791
+ if (has_rest_argument()) {
1792
+ coreError("ordinal arguments must precede variable-length arguments", a->pstate());
1712
1793
  }
1713
- if (has_named_arguments_) {
1714
- error("ordinal arguments must precede named arguments", a->pstate());
1794
+ if (has_named_arguments()) {
1795
+ coreError("ordinal arguments must precede named arguments", a->pstate());
1715
1796
  }
1716
1797
  }
1717
1798
  }
1718
1799
 
1719
1800
  bool Ruleset::is_invisible() const {
1720
- if (Selector_List_Ptr sl = SASS_MEMORY_CAST(Selector_List, selector())) {
1801
+ if (Selector_List_Ptr sl = Cast<Selector_List>(selector())) {
1721
1802
  for (size_t i = 0, L = sl->length(); i < L; ++i)
1722
1803
  if (!(*sl)[i]->has_placeholder()) return false;
1723
1804
  }
@@ -1734,367 +1815,52 @@ namespace Sass {
1734
1815
 
1735
1816
  Number::Number(ParserState pstate, double val, std::string u, bool zero)
1736
1817
  : Value(pstate),
1818
+ Units(),
1737
1819
  value_(val),
1738
1820
  zero_(zero),
1739
- numerator_units_(std::vector<std::string>()),
1740
- denominator_units_(std::vector<std::string>()),
1741
1821
  hash_(0)
1742
1822
  {
1743
- size_t l = 0, r = 0;
1823
+ size_t l = 0;
1824
+ size_t r;
1744
1825
  if (!u.empty()) {
1745
1826
  bool nominator = true;
1746
1827
  while (true) {
1747
1828
  r = u.find_first_of("*/", l);
1748
1829
  std::string unit(u.substr(l, r == std::string::npos ? r : r - l));
1749
1830
  if (!unit.empty()) {
1750
- if (nominator) numerator_units_.push_back(unit);
1751
- else denominator_units_.push_back(unit);
1831
+ if (nominator) numerators.push_back(unit);
1832
+ else denominators.push_back(unit);
1752
1833
  }
1753
1834
  if (r == std::string::npos) break;
1754
1835
  // ToDo: should error for multiple slashes
1755
1836
  // if (!nominator && u[r] == '/') error(...)
1756
1837
  if (u[r] == '/')
1757
1838
  nominator = false;
1839
+ // strange math parsing?
1840
+ // else if (u[r] == '*')
1841
+ // nominator = true;
1758
1842
  l = r + 1;
1759
1843
  }
1760
1844
  }
1761
1845
  concrete_type(NUMBER);
1762
1846
  }
1763
1847
 
1764
- std::string Number::unit() const
1765
- {
1766
- std::string u;
1767
- for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
1768
- if (i) u += '*';
1769
- u += numerator_units_[i];
1770
- }
1771
- if (!denominator_units_.empty()) u += '/';
1772
- for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
1773
- if (i) u += '*';
1774
- u += denominator_units_[i];
1775
- }
1776
- return u;
1777
- }
1778
-
1779
- bool Number::is_valid_css_unit() const
1848
+ // cancel out unnecessary units
1849
+ void Number::reduce()
1780
1850
  {
1781
- return numerator_units().size() <= 1 &&
1782
- denominator_units().size() == 0;
1851
+ // apply conversion factor
1852
+ value_ *= this->Units::reduce();
1783
1853
  }
1784
1854
 
1785
- bool Number::is_unitless() const
1786
- { return numerator_units_.empty() && denominator_units_.empty(); }
1787
-
1788
- void Number::normalize(const std::string& prefered, bool strict)
1855
+ void Number::normalize()
1789
1856
  {
1790
-
1791
- // first make sure same units cancel each other out
1792
- // it seems that a map table will fit nicely to do this
1793
- // we basically construct exponents for each unit
1794
- // has the advantage that they will be pre-sorted
1795
- std::map<std::string, int> exponents;
1796
-
1797
- // initialize by summing up occurences in unit vectors
1798
- for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) ++ exponents[numerator_units_[i]];
1799
- for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) -- exponents[denominator_units_[i]];
1800
-
1801
- // the final conversion factor
1802
- double factor = 1;
1803
-
1804
- // get the first entry of numerators
1805
- // forward it when entry is converted
1806
- std::vector<std::string>::iterator nom_it = numerator_units_.begin();
1807
- std::vector<std::string>::iterator nom_end = numerator_units_.end();
1808
- std::vector<std::string>::iterator denom_it = denominator_units_.begin();
1809
- std::vector<std::string>::iterator denom_end = denominator_units_.end();
1810
-
1811
- // main normalization loop
1812
- // should be close to optimal
1813
- while (denom_it != denom_end)
1814
- {
1815
- // get and increment afterwards
1816
- const std::string denom = *(denom_it ++);
1817
- // skip already canceled out unit
1818
- if (exponents[denom] >= 0) continue;
1819
- // skip all units we don't know how to convert
1820
- if (string_to_unit(denom) == UNKNOWN) continue;
1821
- // now search for nominator
1822
- while (nom_it != nom_end)
1823
- {
1824
- // get and increment afterwards
1825
- const std::string nom = *(nom_it ++);
1826
- // skip already canceled out unit
1827
- if (exponents[nom] <= 0) continue;
1828
- // skip all units we don't know how to convert
1829
- if (string_to_unit(nom) == UNKNOWN) continue;
1830
- // we now have two convertable units
1831
- // add factor for current conversion
1832
- factor *= conversion_factor(nom, denom, strict);
1833
- // update nominator/denominator exponent
1834
- -- exponents[nom]; ++ exponents[denom];
1835
- // inner loop done
1836
- break;
1837
- }
1838
- }
1839
-
1840
- // now we can build up the new unit arrays
1841
- numerator_units_.clear();
1842
- denominator_units_.clear();
1843
-
1844
- // build them by iterating over the exponents
1845
- for (auto exp : exponents)
1846
- {
1847
- // maybe there is more effecient way to push
1848
- // the same item multiple times to a vector?
1849
- for(size_t i = 0, S = abs(exp.second); i < S; ++i)
1850
- {
1851
- // opted to have these switches in the inner loop
1852
- // makes it more readable and should not cost much
1853
- if (!exp.first.empty()) {
1854
- if (exp.second < 0) denominator_units_.push_back(exp.first);
1855
- else if (exp.second > 0) numerator_units_.push_back(exp.first);
1856
- }
1857
- }
1858
- }
1859
-
1860
- // apply factor to value_
1861
- // best precision this way
1862
- value_ *= factor;
1863
-
1864
- // maybe convert to other unit
1865
- // easier implemented on its own
1866
- try { convert(prefered, strict); }
1867
- catch (incompatibleUnits& err)
1868
- { error(err.what(), pstate()); }
1869
- catch (...) { throw; }
1870
-
1871
- }
1872
-
1873
- // this does not cover all cases (multiple prefered units)
1874
- double Number::convert_factor(const Number& n) const
1875
- {
1876
-
1877
- // first make sure same units cancel each other out
1878
- // it seems that a map table will fit nicely to do this
1879
- // we basically construct exponents for each unit class
1880
- // std::map<std::string, int> exponents;
1881
- // initialize by summing up occurences in unit vectors
1882
- // for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) ++ exponents[unit_to_class(numerator_units_[i])];
1883
- // for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) -- exponents[unit_to_class(denominator_units_[i])];
1884
-
1885
- std::vector<std::string> l_miss_nums(0);
1886
- std::vector<std::string> l_miss_dens(0);
1887
- // create copy since we need these for state keeping
1888
- std::vector<std::string> r_nums(n.numerator_units_);
1889
- std::vector<std::string> r_dens(n.denominator_units_);
1890
-
1891
- std::vector<std::string>::const_iterator l_num_it = numerator_units_.begin();
1892
- std::vector<std::string>::const_iterator l_num_end = numerator_units_.end();
1893
-
1894
- bool l_unitless = is_unitless();
1895
- bool r_unitless = n.is_unitless();
1896
-
1897
- // overall conversion
1898
- double factor = 1;
1899
-
1900
- // process all left numerators
1901
- while (l_num_it != l_num_end)
1902
- {
1903
- // get and increment afterwards
1904
- const std::string l_num = *(l_num_it ++);
1905
-
1906
- std::vector<std::string>::iterator r_num_it = r_nums.begin();
1907
- std::vector<std::string>::iterator r_num_end = r_nums.end();
1908
-
1909
- bool found = false;
1910
- // search for compatible numerator
1911
- while (r_num_it != r_num_end)
1912
- {
1913
- // get and increment afterwards
1914
- const std::string r_num = *(r_num_it);
1915
- // get possible converstion factor for units
1916
- double conversion = conversion_factor(l_num, r_num, false);
1917
- // skip incompatible numerator
1918
- if (conversion == 0) {
1919
- ++ r_num_it;
1920
- continue;
1921
- }
1922
- // apply to global factor
1923
- factor *= conversion;
1924
- // remove item from vector
1925
- r_nums.erase(r_num_it);
1926
- // found numerator
1927
- found = true;
1928
- break;
1929
- }
1930
- // maybe we did not find any
1931
- // left numerator is leftover
1932
- if (!found) l_miss_nums.push_back(l_num);
1933
- }
1934
-
1935
- std::vector<std::string>::const_iterator l_den_it = denominator_units_.begin();
1936
- std::vector<std::string>::const_iterator l_den_end = denominator_units_.end();
1937
-
1938
- // process all left denominators
1939
- while (l_den_it != l_den_end)
1940
- {
1941
- // get and increment afterwards
1942
- const std::string l_den = *(l_den_it ++);
1943
-
1944
- std::vector<std::string>::iterator r_den_it = r_dens.begin();
1945
- std::vector<std::string>::iterator r_den_end = r_dens.end();
1946
-
1947
- bool found = false;
1948
- // search for compatible denominator
1949
- while (r_den_it != r_den_end)
1950
- {
1951
- // get and increment afterwards
1952
- const std::string r_den = *(r_den_it);
1953
- // get possible converstion factor for units
1954
- double conversion = conversion_factor(l_den, r_den, false);
1955
- // skip incompatible denominator
1956
- if (conversion == 0) {
1957
- ++ r_den_it;
1958
- continue;
1959
- }
1960
- // apply to global factor
1961
- factor *= conversion;
1962
- // remove item from vector
1963
- r_dens.erase(r_den_it);
1964
- // found denominator
1965
- found = true;
1966
- break;
1967
- }
1968
- // maybe we did not find any
1969
- // left denominator is leftover
1970
- if (!found) l_miss_dens.push_back(l_den);
1971
- }
1972
-
1973
- // check left-overs (ToDo: might cancel out)
1974
- if (l_miss_nums.size() > 0 && !r_unitless) {
1975
- throw Exception::IncompatibleUnits(n, *this);
1976
- }
1977
- if (l_miss_dens.size() > 0 && !r_unitless) {
1978
- throw Exception::IncompatibleUnits(n, *this);
1979
- }
1980
- if (r_nums.size() > 0 && !l_unitless) {
1981
- throw Exception::IncompatibleUnits(n, *this);
1982
- }
1983
- if (r_dens.size() > 0 && !l_unitless) {
1984
- throw Exception::IncompatibleUnits(n, *this);
1985
- }
1986
-
1987
- return factor;
1988
- }
1989
-
1990
- // this does not cover all cases (multiple prefered units)
1991
- bool Number::convert(const std::string& prefered, bool strict)
1992
- {
1993
- // no conversion if unit is empty
1994
- if (prefered.empty()) return true;
1995
-
1996
- // first make sure same units cancel each other out
1997
- // it seems that a map table will fit nicely to do this
1998
- // we basically construct exponents for each unit
1999
- // has the advantage that they will be pre-sorted
2000
- std::map<std::string, int> exponents;
2001
-
2002
- // initialize by summing up occurences in unit vectors
2003
- for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) ++ exponents[numerator_units_[i]];
2004
- for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) -- exponents[denominator_units_[i]];
2005
-
2006
- // the final conversion factor
2007
- double factor = 1;
2008
-
2009
- std::vector<std::string>::iterator denom_it = denominator_units_.begin();
2010
- std::vector<std::string>::iterator denom_end = denominator_units_.end();
2011
-
2012
- // main normalization loop
2013
- // should be close to optimal
2014
- while (denom_it != denom_end)
2015
- {
2016
- // get and increment afterwards
2017
- const std::string denom = *(denom_it ++);
2018
- // check if conversion is needed
2019
- if (denom == prefered) continue;
2020
- // skip already canceled out unit
2021
- if (exponents[denom] >= 0) continue;
2022
- // skip all units we don't know how to convert
2023
- if (string_to_unit(denom) == UNKNOWN) continue;
2024
- // we now have two convertable units
2025
- // add factor for current conversion
2026
- factor *= conversion_factor(denom, prefered, strict);
2027
- // update nominator/denominator exponent
2028
- ++ exponents[denom]; -- exponents[prefered];
2029
- }
2030
-
2031
- std::vector<std::string>::iterator nom_it = numerator_units_.begin();
2032
- std::vector<std::string>::iterator nom_end = numerator_units_.end();
2033
-
2034
- // now search for nominator
2035
- while (nom_it != nom_end)
2036
- {
2037
- // get and increment afterwards
2038
- const std::string nom = *(nom_it ++);
2039
- // check if conversion is needed
2040
- if (nom == prefered) continue;
2041
- // skip already canceled out unit
2042
- if (exponents[nom] <= 0) continue;
2043
- // skip all units we don't know how to convert
2044
- if (string_to_unit(nom) == UNKNOWN) continue;
2045
- // we now have two convertable units
2046
- // add factor for current conversion
2047
- factor *= conversion_factor(nom, prefered, strict);
2048
- // update nominator/denominator exponent
2049
- -- exponents[nom]; ++ exponents[prefered];
2050
- }
2051
-
2052
- // now we can build up the new unit arrays
2053
- numerator_units_.clear();
2054
- denominator_units_.clear();
2055
-
2056
- // build them by iterating over the exponents
2057
- for (auto exp : exponents)
2058
- {
2059
- // maybe there is more effecient way to push
2060
- // the same item multiple times to a vector?
2061
- for(size_t i = 0, S = abs(exp.second); i < S; ++i)
2062
- {
2063
- // opted to have these switches in the inner loop
2064
- // makes it more readable and should not cost much
2065
- if (!exp.first.empty()) {
2066
- if (exp.second < 0) denominator_units_.push_back(exp.first);
2067
- else if (exp.second > 0) numerator_units_.push_back(exp.first);
2068
- }
2069
- }
2070
- }
2071
-
2072
- // apply factor to value_
2073
- // best precision this way
2074
- value_ *= factor;
2075
-
2076
- // success?
2077
- return true;
2078
-
2079
- }
2080
-
2081
- // useful for making one number compatible with another
2082
- std::string Number::find_convertible_unit() const
2083
- {
2084
- for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
2085
- std::string u(numerator_units_[i]);
2086
- if (string_to_unit(u) != UNKNOWN) return u;
2087
- }
2088
- for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
2089
- std::string u(denominator_units_[i]);
2090
- if (string_to_unit(u) != UNKNOWN) return u;
2091
- }
2092
- return std::string();
1857
+ // apply conversion factor
1858
+ value_ *= this->Units::normalize();
2093
1859
  }
2094
1860
 
2095
1861
  bool Custom_Warning::operator== (const Expression& rhs) const
2096
1862
  {
2097
- if (Custom_Warning_Ptr_Const r = dynamic_cast<Custom_Warning_Ptr_Const>(&rhs)) {
1863
+ if (Custom_Warning_Ptr_Const r = Cast<Custom_Warning>(&rhs)) {
2098
1864
  return message() == r->message();
2099
1865
  }
2100
1866
  return false;
@@ -2102,67 +1868,59 @@ namespace Sass {
2102
1868
 
2103
1869
  bool Custom_Error::operator== (const Expression& rhs) const
2104
1870
  {
2105
- if (Custom_Error_Ptr_Const r = dynamic_cast<Custom_Error_Ptr_Const>(&rhs)) {
1871
+ if (Custom_Error_Ptr_Const r = Cast<Custom_Error>(&rhs)) {
2106
1872
  return message() == r->message();
2107
1873
  }
2108
1874
  return false;
2109
1875
  }
2110
1876
 
2111
- bool Number::eq (const Expression& rhs) const
1877
+ bool Number::operator== (const Expression& rhs) const
2112
1878
  {
2113
- if (Number_Ptr_Const r = dynamic_cast<Number_Ptr_Const>(&rhs)) {
2114
- size_t lhs_units = numerator_units_.size() + denominator_units_.size();
2115
- size_t rhs_units = r->numerator_units_.size() + r->denominator_units_.size();
2116
- if (!lhs_units && !rhs_units) {
2117
- return std::fabs(value() - r->value()) < NUMBER_EPSILON;
2118
- }
2119
- return (numerator_units_ == r->numerator_units_) &&
2120
- (denominator_units_ == r->denominator_units_) &&
2121
- std::fabs(value() - r->value()) < NUMBER_EPSILON;
1879
+ if (auto rhsnr = Cast<Number>(&rhs)) {
1880
+ return *this == *rhsnr;
2122
1881
  }
2123
1882
  return false;
2124
1883
  }
2125
1884
 
2126
- bool Number::operator== (const Expression& rhs) const
1885
+ bool Number::operator== (const Number& rhs) const
2127
1886
  {
2128
- if (Number_Ptr_Const r = dynamic_cast<Number_Ptr_Const>(&rhs)) {
2129
- size_t lhs_units = numerator_units_.size() + denominator_units_.size();
2130
- size_t rhs_units = r->numerator_units_.size() + r->denominator_units_.size();
2131
- // unitless and only having one unit seems equivalent (will change in future)
2132
- if (!lhs_units || !rhs_units) {
2133
- return std::fabs(value() - r->value()) < NUMBER_EPSILON;
2134
- }
2135
- return (numerator_units_ == r->numerator_units_) &&
2136
- (denominator_units_ == r->denominator_units_) &&
2137
- std::fabs(value() - r->value()) < NUMBER_EPSILON;
1887
+ Number l(*this), r(rhs); l.reduce(); r.reduce();
1888
+ size_t lhs_units = l.numerators.size() + l.denominators.size();
1889
+ size_t rhs_units = r.numerators.size() + r.denominators.size();
1890
+ // unitless and only having one unit seems equivalent (will change in future)
1891
+ if (!lhs_units || !rhs_units) {
1892
+ return NEAR_EQUAL(l.value(), r.value());
2138
1893
  }
2139
- return false;
1894
+ l.normalize(); r.normalize();
1895
+ Units &lhs_unit = l, &rhs_unit = r;
1896
+ return lhs_unit == rhs_unit &&
1897
+ NEAR_EQUAL(l.value(), r.value());
2140
1898
  }
2141
1899
 
2142
1900
  bool Number::operator< (const Number& rhs) const
2143
1901
  {
2144
- size_t lhs_units = numerator_units_.size() + denominator_units_.size();
2145
- size_t rhs_units = rhs.numerator_units_.size() + rhs.denominator_units_.size();
1902
+ Number l(*this), r(rhs); l.reduce(); r.reduce();
1903
+ size_t lhs_units = l.numerators.size() + l.denominators.size();
1904
+ size_t rhs_units = r.numerators.size() + r.denominators.size();
2146
1905
  // unitless and only having one unit seems equivalent (will change in future)
2147
1906
  if (!lhs_units || !rhs_units) {
2148
- return value() < rhs.value();
1907
+ return l.value() < r.value();
2149
1908
  }
2150
-
2151
- Number tmp_r(&rhs); // copy
2152
- tmp_r.normalize(find_convertible_unit());
2153
- std::string l_unit(unit());
2154
- std::string r_unit(tmp_r.unit());
2155
- if (unit() != tmp_r.unit()) {
2156
- error("cannot compare numbers with incompatible units", pstate());
1909
+ l.normalize(); r.normalize();
1910
+ Units &lhs_unit = l, &rhs_unit = r;
1911
+ if (!(lhs_unit == rhs_unit)) {
1912
+ /* ToDo: do we always get usefull backtraces? */
1913
+ throw Exception::IncompatibleUnits(rhs, *this);
2157
1914
  }
2158
- return value() < tmp_r.value();
1915
+ return lhs_unit < rhs_unit ||
1916
+ l.value() < r.value();
2159
1917
  }
2160
1918
 
2161
1919
  bool String_Quoted::operator== (const Expression& rhs) const
2162
1920
  {
2163
- if (String_Quoted_Ptr_Const qstr = dynamic_cast<String_Quoted_Ptr_Const>(&rhs)) {
1921
+ if (String_Quoted_Ptr_Const qstr = Cast<String_Quoted>(&rhs)) {
2164
1922
  return (value() == qstr->value());
2165
- } else if (String_Constant_Ptr_Const cstr = dynamic_cast<String_Constant_Ptr_Const>(&rhs)) {
1923
+ } else if (String_Constant_Ptr_Const cstr = Cast<String_Constant>(&rhs)) {
2166
1924
  return (value() == cstr->value());
2167
1925
  }
2168
1926
  return false;
@@ -2174,9 +1932,9 @@ namespace Sass {
2174
1932
 
2175
1933
  bool String_Constant::operator== (const Expression& rhs) const
2176
1934
  {
2177
- if (String_Quoted_Ptr_Const qstr = dynamic_cast<String_Quoted_Ptr_Const>(&rhs)) {
1935
+ if (String_Quoted_Ptr_Const qstr = Cast<String_Quoted>(&rhs)) {
2178
1936
  return (value() == qstr->value());
2179
- } else if (String_Constant_Ptr_Const cstr = dynamic_cast<String_Constant_Ptr_Const>(&rhs)) {
1937
+ } else if (String_Constant_Ptr_Const cstr = Cast<String_Constant>(&rhs)) {
2180
1938
  return (value() == cstr->value());
2181
1939
  }
2182
1940
  return false;
@@ -2193,7 +1951,7 @@ namespace Sass {
2193
1951
 
2194
1952
  bool String_Schema::operator== (const Expression& rhs) const
2195
1953
  {
2196
- if (String_Schema_Ptr_Const r = dynamic_cast<String_Schema_Ptr_Const>(&rhs)) {
1954
+ if (String_Schema_Ptr_Const r = Cast<String_Schema>(&rhs)) {
2197
1955
  if (length() != r->length()) return false;
2198
1956
  for (size_t i = 0, L = length(); i < L; ++i) {
2199
1957
  Expression_Obj rv = (*r)[i];
@@ -2208,7 +1966,7 @@ namespace Sass {
2208
1966
 
2209
1967
  bool Boolean::operator== (const Expression& rhs) const
2210
1968
  {
2211
- if (Boolean_Ptr_Const r = dynamic_cast<Boolean_Ptr_Const>(&rhs)) {
1969
+ if (Boolean_Ptr_Const r = Cast<Boolean>(&rhs)) {
2212
1970
  return (value() == r->value());
2213
1971
  }
2214
1972
  return false;
@@ -2216,7 +1974,7 @@ namespace Sass {
2216
1974
 
2217
1975
  bool Color::operator== (const Expression& rhs) const
2218
1976
  {
2219
- if (Color_Ptr_Const r = dynamic_cast<Color_Ptr_Const>(&rhs)) {
1977
+ if (Color_Ptr_Const r = Cast<Color>(&rhs)) {
2220
1978
  return r_ == r->r() &&
2221
1979
  g_ == r->g() &&
2222
1980
  b_ == r->b() &&
@@ -2227,9 +1985,10 @@ namespace Sass {
2227
1985
 
2228
1986
  bool List::operator== (const Expression& rhs) const
2229
1987
  {
2230
- if (List_Ptr_Const r = dynamic_cast<List_Ptr_Const>(&rhs)) {
1988
+ if (List_Ptr_Const r = Cast<List>(&rhs)) {
2231
1989
  if (length() != r->length()) return false;
2232
1990
  if (separator() != r->separator()) return false;
1991
+ if (is_bracketed() != r->is_bracketed()) return false;
2233
1992
  for (size_t i = 0, L = length(); i < L; ++i) {
2234
1993
  Expression_Obj rv = r->at(i);
2235
1994
  Expression_Obj lv = this->at(i);
@@ -2243,7 +2002,7 @@ namespace Sass {
2243
2002
 
2244
2003
  bool Map::operator== (const Expression& rhs) const
2245
2004
  {
2246
- if (Map_Ptr_Const r = dynamic_cast<Map_Ptr_Const>(&rhs)) {
2005
+ if (Map_Ptr_Const r = Cast<Map>(&rhs)) {
2247
2006
  if (length() != r->length()) return false;
2248
2007
  for (auto key : keys()) {
2249
2008
  Expression_Obj lv = at(key);
@@ -2261,13 +2020,23 @@ namespace Sass {
2261
2020
  return rhs.concrete_type() == NULL_VAL;
2262
2021
  }
2263
2022
 
2023
+ bool Function::operator== (const Expression& rhs) const
2024
+ {
2025
+ if (Function_Ptr_Const r = Cast<Function>(&rhs)) {
2026
+ Definition_Ptr_Const d1 = Cast<Definition>(definition());
2027
+ Definition_Ptr_Const d2 = Cast<Definition>(r->definition());
2028
+ return d1 && d2 && d1 == d2 && is_css() == r->is_css();
2029
+ }
2030
+ return false;
2031
+ }
2032
+
2264
2033
  size_t List::size() const {
2265
2034
  if (!is_arglist_) return length();
2266
2035
  // arglist expects a list of arguments
2267
2036
  // so we need to break before keywords
2268
2037
  for (size_t i = 0, L = length(); i < L; ++i) {
2269
2038
  Expression_Obj obj = this->at(i);
2270
- if (Argument* arg = dynamic_cast<Argument*>(&obj)) {
2039
+ if (Argument_Ptr arg = Cast<Argument>(obj)) {
2271
2040
  if (!arg->name().empty()) return i;
2272
2041
  }
2273
2042
  }
@@ -2290,7 +2059,7 @@ namespace Sass {
2290
2059
  return is_interpolant() || (right() && right()->is_right_interpolant());
2291
2060
  }
2292
2061
 
2293
- std::string AST_Node::to_string(Sass_Inspect_Options opt) const
2062
+ const std::string AST_Node::to_string(Sass_Inspect_Options opt) const
2294
2063
  {
2295
2064
  Sass_Output_Options out(opt);
2296
2065
  Emitter emitter(out);
@@ -2301,7 +2070,7 @@ namespace Sass {
2301
2070
  return i.get_buffer();
2302
2071
  }
2303
2072
 
2304
- std::string AST_Node::to_string() const
2073
+ const std::string AST_Node::to_string() const
2305
2074
  {
2306
2075
  return to_string({ NESTED, 5 });
2307
2076
  }
@@ -2316,33 +2085,40 @@ namespace Sass {
2316
2085
  return quote(value_, '*');
2317
2086
  }
2318
2087
 
2088
+ bool Declaration::is_invisible() const
2089
+ {
2090
+ if (is_custom_property()) return false;
2091
+
2092
+ return !(value_ && value_->concrete_type() != Expression::NULL_VAL);
2093
+ }
2094
+
2319
2095
  //////////////////////////////////////////////////////////////////////////////////////////
2320
2096
  // Additional method on Lists to retrieve values directly or from an encompassed Argument.
2321
2097
  //////////////////////////////////////////////////////////////////////////////////////////
2322
2098
  Expression_Obj List::value_at_index(size_t i) {
2323
2099
  Expression_Obj obj = this->at(i);
2324
2100
  if (is_arglist_) {
2325
- if (Argument* arg = dynamic_cast<Argument*>(&obj)) {
2101
+ if (Argument_Ptr arg = Cast<Argument>(obj)) {
2326
2102
  return arg->value();
2327
2103
  } else {
2328
- return &obj;
2104
+ return obj;
2329
2105
  }
2330
2106
  } else {
2331
- return &obj;
2107
+ return obj;
2332
2108
  }
2333
2109
  }
2334
2110
 
2335
2111
  //////////////////////////////////////////////////////////////////////////////////////////
2336
2112
  // Convert map to (key, value) list.
2337
2113
  //////////////////////////////////////////////////////////////////////////////////////////
2338
- List_Obj Map::to_list(Context& ctx, ParserState& pstate) {
2114
+ List_Obj Map::to_list(ParserState& pstate) {
2339
2115
  List_Obj ret = SASS_MEMORY_NEW(List, pstate, length(), SASS_COMMA);
2340
2116
 
2341
2117
  for (auto key : keys()) {
2342
2118
  List_Obj l = SASS_MEMORY_NEW(List, pstate, 2);
2343
- l->append(&key);
2119
+ l->append(key);
2344
2120
  l->append(at(key));
2345
- ret->append(&l);
2121
+ ret->append(l);
2346
2122
  }
2347
2123
 
2348
2124
  return ret;
@@ -2396,6 +2172,7 @@ namespace Sass {
2396
2172
  IMPLEMENT_AST_OPERATORS(Custom_Error);
2397
2173
  IMPLEMENT_AST_OPERATORS(List);
2398
2174
  IMPLEMENT_AST_OPERATORS(Map);
2175
+ IMPLEMENT_AST_OPERATORS(Function);
2399
2176
  IMPLEMENT_AST_OPERATORS(Number);
2400
2177
  IMPLEMENT_AST_OPERATORS(Binary_Expression);
2401
2178
  IMPLEMENT_AST_OPERATORS(String_Schema);
@@ -2439,7 +2216,6 @@ namespace Sass {
2439
2216
  IMPLEMENT_AST_OPERATORS(Function_Call_Schema);
2440
2217
  IMPLEMENT_AST_OPERATORS(Block);
2441
2218
  IMPLEMENT_AST_OPERATORS(Content);
2442
- IMPLEMENT_AST_OPERATORS(Textual);
2443
2219
  IMPLEMENT_AST_OPERATORS(Trace);
2444
2220
  IMPLEMENT_AST_OPERATORS(Keyframe_Rule);
2445
2221
  IMPLEMENT_AST_OPERATORS(Bubble);
@@ -2447,5 +2223,4 @@ namespace Sass {
2447
2223
  IMPLEMENT_AST_OPERATORS(Placeholder_Selector);
2448
2224
  IMPLEMENT_AST_OPERATORS(Definition);
2449
2225
  IMPLEMENT_AST_OPERATORS(Declaration);
2450
-
2451
2226
  }