sassc 2.0.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.gitmodules +1 -1
- data/.travis.yml +9 -3
- data/CHANGELOG.md +36 -0
- data/CODE_OF_CONDUCT.md +1 -1
- data/README.md +1 -1
- data/Rakefile +43 -7
- data/ext/depend +4 -0
- data/ext/extconf.rb +92 -0
- data/ext/libsass/VERSION +1 -0
- data/ext/libsass/include/sass/base.h +9 -1
- data/ext/libsass/include/sass/context.h +5 -1
- data/ext/libsass/src/MurmurHash2.hpp +91 -0
- data/ext/libsass/src/ast.cpp +755 -2028
- data/ext/libsass/src/ast.hpp +492 -2477
- data/ext/libsass/src/{to_c.cpp → ast2c.cpp} +22 -16
- data/ext/libsass/src/ast2c.hpp +39 -0
- data/ext/libsass/src/ast_def_macros.hpp +70 -10
- data/ext/libsass/src/ast_fwd_decl.cpp +5 -3
- data/ext/libsass/src/ast_fwd_decl.hpp +107 -296
- data/ext/libsass/src/ast_helpers.hpp +292 -0
- data/ext/libsass/src/ast_sel_cmp.cpp +396 -0
- data/ext/libsass/src/ast_sel_super.cpp +539 -0
- data/ext/libsass/src/ast_sel_unify.cpp +275 -0
- data/ext/libsass/src/ast_sel_weave.cpp +616 -0
- data/ext/libsass/src/ast_selectors.cpp +1043 -0
- data/ext/libsass/src/ast_selectors.hpp +522 -0
- data/ext/libsass/src/ast_supports.cpp +114 -0
- data/ext/libsass/src/ast_supports.hpp +121 -0
- data/ext/libsass/src/ast_values.cpp +1154 -0
- data/ext/libsass/src/ast_values.hpp +498 -0
- data/ext/libsass/src/backtrace.cpp +11 -7
- data/ext/libsass/src/backtrace.hpp +5 -5
- data/ext/libsass/src/base64vlq.cpp +5 -2
- data/ext/libsass/src/base64vlq.hpp +1 -1
- data/ext/libsass/src/bind.cpp +35 -34
- data/ext/libsass/src/bind.hpp +3 -1
- data/ext/libsass/src/c2ast.cpp +64 -0
- data/ext/libsass/src/c2ast.hpp +14 -0
- data/ext/libsass/src/cencode.c +4 -6
- data/ext/libsass/src/check_nesting.cpp +83 -88
- data/ext/libsass/src/check_nesting.hpp +39 -34
- data/ext/libsass/src/color_maps.cpp +168 -164
- data/ext/libsass/src/color_maps.hpp +152 -160
- data/ext/libsass/src/constants.cpp +20 -0
- data/ext/libsass/src/constants.hpp +19 -0
- data/ext/libsass/src/context.cpp +104 -121
- data/ext/libsass/src/context.hpp +43 -55
- data/ext/libsass/src/cssize.cpp +103 -188
- data/ext/libsass/src/cssize.hpp +45 -51
- data/ext/libsass/src/dart_helpers.hpp +199 -0
- data/ext/libsass/src/debugger.hpp +524 -361
- data/ext/libsass/src/emitter.cpp +26 -26
- data/ext/libsass/src/emitter.hpp +20 -18
- data/ext/libsass/src/environment.cpp +41 -27
- data/ext/libsass/src/environment.hpp +33 -22
- data/ext/libsass/src/error_handling.cpp +92 -94
- data/ext/libsass/src/error_handling.hpp +73 -50
- data/ext/libsass/src/eval.cpp +380 -515
- data/ext/libsass/src/eval.hpp +64 -57
- data/ext/libsass/src/eval_selectors.cpp +75 -0
- data/ext/libsass/src/expand.cpp +322 -263
- data/ext/libsass/src/expand.hpp +55 -39
- data/ext/libsass/src/extender.cpp +1188 -0
- data/ext/libsass/src/extender.hpp +399 -0
- data/ext/libsass/src/extension.cpp +43 -0
- data/ext/libsass/src/extension.hpp +89 -0
- data/ext/libsass/src/file.cpp +134 -88
- data/ext/libsass/src/file.hpp +28 -37
- data/ext/libsass/src/fn_colors.cpp +596 -0
- data/ext/libsass/src/fn_colors.hpp +85 -0
- data/ext/libsass/src/fn_lists.cpp +285 -0
- data/ext/libsass/src/fn_lists.hpp +34 -0
- data/ext/libsass/src/fn_maps.cpp +94 -0
- data/ext/libsass/src/fn_maps.hpp +30 -0
- data/ext/libsass/src/fn_miscs.cpp +244 -0
- data/ext/libsass/src/fn_miscs.hpp +40 -0
- data/ext/libsass/src/fn_numbers.cpp +227 -0
- data/ext/libsass/src/fn_numbers.hpp +45 -0
- data/ext/libsass/src/fn_selectors.cpp +205 -0
- data/ext/libsass/src/fn_selectors.hpp +35 -0
- data/ext/libsass/src/fn_strings.cpp +268 -0
- data/ext/libsass/src/fn_strings.hpp +34 -0
- data/ext/libsass/src/fn_utils.cpp +158 -0
- data/ext/libsass/src/fn_utils.hpp +62 -0
- data/ext/libsass/src/inspect.cpp +253 -266
- data/ext/libsass/src/inspect.hpp +72 -74
- data/ext/libsass/src/json.cpp +2 -2
- data/ext/libsass/src/lexer.cpp +25 -84
- data/ext/libsass/src/lexer.hpp +5 -16
- data/ext/libsass/src/listize.cpp +27 -43
- data/ext/libsass/src/listize.hpp +14 -11
- data/ext/libsass/src/mapping.hpp +1 -0
- data/ext/libsass/src/memory.hpp +12 -0
- data/ext/libsass/src/memory/allocator.cpp +48 -0
- data/ext/libsass/src/memory/allocator.hpp +138 -0
- data/ext/libsass/src/memory/config.hpp +20 -0
- data/ext/libsass/src/memory/memory_pool.hpp +186 -0
- data/ext/libsass/src/memory/shared_ptr.cpp +33 -0
- data/ext/libsass/src/memory/shared_ptr.hpp +332 -0
- data/ext/libsass/src/operation.hpp +193 -143
- data/ext/libsass/src/operators.cpp +56 -29
- data/ext/libsass/src/operators.hpp +11 -11
- data/ext/libsass/src/ordered_map.hpp +112 -0
- data/ext/libsass/src/output.cpp +59 -75
- data/ext/libsass/src/output.hpp +15 -22
- data/ext/libsass/src/parser.cpp +662 -818
- data/ext/libsass/src/parser.hpp +96 -100
- data/ext/libsass/src/parser_selectors.cpp +189 -0
- data/ext/libsass/src/permutate.hpp +164 -0
- data/ext/libsass/src/plugins.cpp +12 -8
- data/ext/libsass/src/plugins.hpp +8 -8
- data/ext/libsass/src/position.cpp +10 -26
- data/ext/libsass/src/position.hpp +44 -21
- data/ext/libsass/src/prelexer.cpp +14 -8
- data/ext/libsass/src/prelexer.hpp +9 -9
- data/ext/libsass/src/remove_placeholders.cpp +59 -57
- data/ext/libsass/src/remove_placeholders.hpp +20 -18
- data/ext/libsass/src/sass.cpp +25 -18
- data/ext/libsass/src/sass.hpp +22 -14
- data/ext/libsass/src/sass2scss.cpp +49 -18
- data/ext/libsass/src/sass_context.cpp +104 -132
- data/ext/libsass/src/sass_context.hpp +2 -2
- data/ext/libsass/src/sass_functions.cpp +7 -4
- data/ext/libsass/src/sass_functions.hpp +1 -1
- data/ext/libsass/src/sass_values.cpp +26 -21
- data/ext/libsass/src/settings.hpp +19 -0
- data/ext/libsass/src/source.cpp +69 -0
- data/ext/libsass/src/source.hpp +95 -0
- data/ext/libsass/src/source_data.hpp +32 -0
- data/ext/libsass/src/source_map.cpp +27 -20
- data/ext/libsass/src/source_map.hpp +14 -11
- data/ext/libsass/src/stylesheet.cpp +22 -0
- data/ext/libsass/src/stylesheet.hpp +57 -0
- data/ext/libsass/src/to_value.cpp +24 -22
- data/ext/libsass/src/to_value.hpp +18 -22
- data/ext/libsass/src/units.cpp +28 -22
- data/ext/libsass/src/units.hpp +9 -8
- data/ext/libsass/src/utf8/checked.h +12 -10
- data/ext/libsass/src/utf8/core.h +3 -0
- data/ext/libsass/src/utf8_string.cpp +12 -10
- data/ext/libsass/src/utf8_string.hpp +7 -6
- data/ext/libsass/src/util.cpp +97 -107
- data/ext/libsass/src/util.hpp +74 -30
- data/ext/libsass/src/util_string.cpp +125 -0
- data/ext/libsass/src/util_string.hpp +73 -0
- data/ext/libsass/src/values.cpp +33 -24
- data/ext/libsass/src/values.hpp +2 -2
- data/lib/sassc.rb +24 -0
- data/lib/sassc/engine.rb +7 -5
- data/lib/sassc/functions_handler.rb +11 -13
- data/lib/sassc/native.rb +10 -9
- data/lib/sassc/native/native_functions_api.rb +0 -5
- data/lib/sassc/script.rb +4 -6
- data/lib/sassc/version.rb +1 -1
- data/sassc.gemspec +32 -12
- data/test/engine_test.rb +32 -2
- data/test/functions_test.rb +38 -1
- data/test/native_test.rb +4 -4
- metadata +95 -109
- data/ext/Rakefile +0 -3
- data/ext/libsass/.editorconfig +0 -15
- data/ext/libsass/.gitattributes +0 -2
- data/ext/libsass/.github/CONTRIBUTING.md +0 -65
- data/ext/libsass/.github/ISSUE_TEMPLATE.md +0 -54
- data/ext/libsass/.gitignore +0 -85
- data/ext/libsass/.travis.yml +0 -64
- data/ext/libsass/COPYING +0 -25
- data/ext/libsass/GNUmakefile.am +0 -88
- data/ext/libsass/INSTALL +0 -1
- data/ext/libsass/LICENSE +0 -25
- data/ext/libsass/Makefile +0 -351
- data/ext/libsass/Makefile.conf +0 -55
- data/ext/libsass/Readme.md +0 -104
- data/ext/libsass/SECURITY.md +0 -10
- data/ext/libsass/appveyor.yml +0 -91
- data/ext/libsass/configure.ac +0 -138
- data/ext/libsass/contrib/libsass.spec +0 -66
- data/ext/libsass/docs/README.md +0 -20
- data/ext/libsass/docs/api-context-example.md +0 -45
- data/ext/libsass/docs/api-context-internal.md +0 -163
- data/ext/libsass/docs/api-context.md +0 -295
- data/ext/libsass/docs/api-doc.md +0 -215
- data/ext/libsass/docs/api-function-example.md +0 -67
- data/ext/libsass/docs/api-function-internal.md +0 -8
- data/ext/libsass/docs/api-function.md +0 -74
- data/ext/libsass/docs/api-importer-example.md +0 -112
- data/ext/libsass/docs/api-importer-internal.md +0 -20
- data/ext/libsass/docs/api-importer.md +0 -86
- data/ext/libsass/docs/api-value-example.md +0 -55
- data/ext/libsass/docs/api-value-internal.md +0 -76
- data/ext/libsass/docs/api-value.md +0 -154
- data/ext/libsass/docs/build-on-darwin.md +0 -27
- data/ext/libsass/docs/build-on-gentoo.md +0 -55
- data/ext/libsass/docs/build-on-windows.md +0 -139
- data/ext/libsass/docs/build-shared-library.md +0 -35
- data/ext/libsass/docs/build-with-autotools.md +0 -78
- data/ext/libsass/docs/build-with-makefiles.md +0 -68
- data/ext/libsass/docs/build-with-mingw.md +0 -107
- data/ext/libsass/docs/build-with-visual-studio.md +0 -90
- data/ext/libsass/docs/build.md +0 -97
- data/ext/libsass/docs/compatibility-plan.md +0 -48
- data/ext/libsass/docs/contributing.md +0 -17
- data/ext/libsass/docs/custom-functions-internal.md +0 -122
- data/ext/libsass/docs/dev-ast-memory.md +0 -223
- data/ext/libsass/docs/implementations.md +0 -56
- data/ext/libsass/docs/plugins.md +0 -47
- data/ext/libsass/docs/setup-environment.md +0 -68
- data/ext/libsass/docs/source-map-internals.md +0 -51
- data/ext/libsass/docs/trace.md +0 -26
- data/ext/libsass/docs/triage.md +0 -17
- data/ext/libsass/docs/unicode.md +0 -39
- data/ext/libsass/extconf.rb +0 -6
- data/ext/libsass/include/sass/version.h.in +0 -12
- data/ext/libsass/m4/.gitkeep +0 -0
- data/ext/libsass/m4/m4-ax_cxx_compile_stdcxx_11.m4 +0 -167
- data/ext/libsass/res/resource.rc +0 -35
- data/ext/libsass/script/bootstrap +0 -13
- data/ext/libsass/script/branding +0 -10
- data/ext/libsass/script/ci-build-libsass +0 -134
- data/ext/libsass/script/ci-build-plugin +0 -62
- data/ext/libsass/script/ci-install-compiler +0 -6
- data/ext/libsass/script/ci-install-deps +0 -20
- data/ext/libsass/script/ci-report-coverage +0 -42
- data/ext/libsass/script/spec +0 -5
- data/ext/libsass/script/tap-driver +0 -652
- data/ext/libsass/script/tap-runner +0 -1
- data/ext/libsass/script/test-leaks.pl +0 -103
- data/ext/libsass/src/GNUmakefile.am +0 -54
- data/ext/libsass/src/extend.cpp +0 -2130
- data/ext/libsass/src/extend.hpp +0 -86
- data/ext/libsass/src/functions.cpp +0 -2234
- data/ext/libsass/src/functions.hpp +0 -198
- data/ext/libsass/src/memory/SharedPtr.cpp +0 -114
- data/ext/libsass/src/memory/SharedPtr.hpp +0 -206
- data/ext/libsass/src/node.cpp +0 -319
- data/ext/libsass/src/node.hpp +0 -118
- data/ext/libsass/src/paths.hpp +0 -71
- data/ext/libsass/src/sass_util.cpp +0 -149
- data/ext/libsass/src/sass_util.hpp +0 -256
- data/ext/libsass/src/subset_map.cpp +0 -55
- data/ext/libsass/src/subset_map.hpp +0 -76
- data/ext/libsass/src/support/libsass.pc.in +0 -11
- data/ext/libsass/src/to_c.hpp +0 -39
- data/ext/libsass/test/test_node.cpp +0 -94
- data/ext/libsass/test/test_paths.cpp +0 -28
- data/ext/libsass/test/test_selector_difference.cpp +0 -25
- data/ext/libsass/test/test_specificity.cpp +0 -25
- data/ext/libsass/test/test_subset_map.cpp +0 -472
- data/ext/libsass/test/test_superselector.cpp +0 -69
- data/ext/libsass/test/test_unification.cpp +0 -31
- data/ext/libsass/version.sh +0 -10
- data/ext/libsass/win/libsass.sln +0 -39
- data/ext/libsass/win/libsass.sln.DotSettings +0 -9
- data/ext/libsass/win/libsass.targets +0 -118
- data/ext/libsass/win/libsass.vcxproj +0 -188
- data/ext/libsass/win/libsass.vcxproj.filters +0 -357
- data/lib/sassc/native/lib_c.rb +0 -21
- data/lib/tasks/libsass.rb +0 -33
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
// sass.hpp must go before all system headers to get the
|
|
2
|
+
// __EXTENSIONS__ fix on Solaris.
|
|
3
|
+
#include "sass.hpp"
|
|
4
|
+
|
|
5
|
+
#include "ast.hpp"
|
|
6
|
+
|
|
7
|
+
namespace Sass {
|
|
8
|
+
|
|
9
|
+
// ##########################################################################
|
|
10
|
+
// Returns the contents of a [SelectorList] that matches only
|
|
11
|
+
// elements that are matched by both [complex1] and [complex2].
|
|
12
|
+
// If no such list can be produced, returns `null`.
|
|
13
|
+
// ##########################################################################
|
|
14
|
+
// ToDo: fine-tune API to avoid unnecessary wrapper allocations
|
|
15
|
+
// ##########################################################################
|
|
16
|
+
sass::vector<sass::vector<SelectorComponentObj>> unifyComplex(
|
|
17
|
+
const sass::vector<sass::vector<SelectorComponentObj>>& complexes)
|
|
18
|
+
{
|
|
19
|
+
|
|
20
|
+
SASS_ASSERT(!complexes.empty(), "Can't unify empty list");
|
|
21
|
+
if (complexes.size() == 1) return complexes;
|
|
22
|
+
|
|
23
|
+
CompoundSelectorObj unifiedBase = SASS_MEMORY_NEW(CompoundSelector, SourceSpan("[phony]"));
|
|
24
|
+
for (auto complex : complexes) {
|
|
25
|
+
SelectorComponentObj base = complex.back();
|
|
26
|
+
if (CompoundSelector * comp = base->getCompound()) {
|
|
27
|
+
if (unifiedBase->empty()) {
|
|
28
|
+
unifiedBase->concat(comp);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
for (SimpleSelectorObj simple : comp->elements()) {
|
|
32
|
+
unifiedBase = simple->unifyWith(unifiedBase);
|
|
33
|
+
if (unifiedBase.isNull()) return {};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
return {};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
sass::vector<sass::vector<SelectorComponentObj>> complexesWithoutBases;
|
|
43
|
+
for (size_t i = 0; i < complexes.size(); i += 1) {
|
|
44
|
+
sass::vector<SelectorComponentObj> sel = complexes[i];
|
|
45
|
+
sel.pop_back(); // remove last item (base) from the list
|
|
46
|
+
complexesWithoutBases.push_back(std::move(sel));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
complexesWithoutBases.back().push_back(unifiedBase);
|
|
50
|
+
|
|
51
|
+
return weave(complexesWithoutBases);
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
// EO unifyComplex
|
|
55
|
+
|
|
56
|
+
// ##########################################################################
|
|
57
|
+
// Returns a [CompoundSelector] that matches only elements
|
|
58
|
+
// that are matched by both [compound1] and [compound2].
|
|
59
|
+
// If no such selector can be produced, returns `null`.
|
|
60
|
+
// ##########################################################################
|
|
61
|
+
CompoundSelector* CompoundSelector::unifyWith(CompoundSelector* rhs)
|
|
62
|
+
{
|
|
63
|
+
if (empty()) return rhs;
|
|
64
|
+
CompoundSelectorObj unified = SASS_MEMORY_COPY(rhs);
|
|
65
|
+
for (const SimpleSelectorObj& sel : elements()) {
|
|
66
|
+
unified = sel->unifyWith(unified);
|
|
67
|
+
if (unified.isNull()) break;
|
|
68
|
+
}
|
|
69
|
+
return unified.detach();
|
|
70
|
+
}
|
|
71
|
+
// EO CompoundSelector::unifyWith(CompoundSelector*)
|
|
72
|
+
|
|
73
|
+
// ##########################################################################
|
|
74
|
+
// Returns the compoments of a [CompoundSelector] that matches only elements
|
|
75
|
+
// matched by both this and [compound]. By default, this just returns a copy
|
|
76
|
+
// of [compound] with this selector added to the end, or returns the original
|
|
77
|
+
// array if this selector already exists in it. Returns `null` if unification
|
|
78
|
+
// is impossible—for example, if there are multiple ID selectors.
|
|
79
|
+
// ##########################################################################
|
|
80
|
+
// This is implemented in `selector/simple.dart` as `SimpleSelector::unify`
|
|
81
|
+
// ##########################################################################
|
|
82
|
+
CompoundSelector* SimpleSelector::unifyWith(CompoundSelector* rhs)
|
|
83
|
+
{
|
|
84
|
+
|
|
85
|
+
if (rhs->length() == 1) {
|
|
86
|
+
if (rhs->get(0)->is_universal()) {
|
|
87
|
+
CompoundSelector* this_compound = SASS_MEMORY_NEW(CompoundSelector, pstate());
|
|
88
|
+
this_compound->append(SASS_MEMORY_COPY(this));
|
|
89
|
+
CompoundSelector* unified = rhs->get(0)->unifyWith(this_compound);
|
|
90
|
+
if (unified == nullptr || unified != this_compound) delete this_compound;
|
|
91
|
+
return unified;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
for (const SimpleSelectorObj& sel : rhs->elements()) {
|
|
95
|
+
if (*this == *sel) {
|
|
96
|
+
return rhs;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
CompoundSelectorObj result = SASS_MEMORY_NEW(CompoundSelector, rhs->pstate());
|
|
101
|
+
|
|
102
|
+
bool addedThis = false;
|
|
103
|
+
for (auto simple : rhs->elements()) {
|
|
104
|
+
// Make sure pseudo selectors always come last.
|
|
105
|
+
if (!addedThis && simple->getPseudoSelector()) {
|
|
106
|
+
result->append(this);
|
|
107
|
+
addedThis = true;
|
|
108
|
+
}
|
|
109
|
+
result->append(simple);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (!addedThis) {
|
|
113
|
+
result->append(this);
|
|
114
|
+
}
|
|
115
|
+
return result.detach();
|
|
116
|
+
|
|
117
|
+
}
|
|
118
|
+
// EO SimpleSelector::unifyWith(CompoundSelector*)
|
|
119
|
+
|
|
120
|
+
// ##########################################################################
|
|
121
|
+
// This is implemented in `selector/type.dart` as `PseudoSelector::unify`
|
|
122
|
+
// ##########################################################################
|
|
123
|
+
CompoundSelector* TypeSelector::unifyWith(CompoundSelector* rhs)
|
|
124
|
+
{
|
|
125
|
+
if (rhs->empty()) {
|
|
126
|
+
rhs->append(this);
|
|
127
|
+
return rhs;
|
|
128
|
+
}
|
|
129
|
+
TypeSelector* type = Cast<TypeSelector>(rhs->at(0));
|
|
130
|
+
if (type != nullptr) {
|
|
131
|
+
SimpleSelector* unified = unifyWith(type);
|
|
132
|
+
if (unified == nullptr) {
|
|
133
|
+
return nullptr;
|
|
134
|
+
}
|
|
135
|
+
rhs->elements()[0] = unified;
|
|
136
|
+
}
|
|
137
|
+
else if (!is_universal() || (has_ns_ && ns_ != "*")) {
|
|
138
|
+
rhs->insert(rhs->begin(), this);
|
|
139
|
+
}
|
|
140
|
+
return rhs;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ##########################################################################
|
|
144
|
+
// This is implemented in `selector/id.dart` as `PseudoSelector::unify`
|
|
145
|
+
// ##########################################################################
|
|
146
|
+
CompoundSelector* IDSelector::unifyWith(CompoundSelector* rhs)
|
|
147
|
+
{
|
|
148
|
+
for (const SimpleSelector* sel : rhs->elements()) {
|
|
149
|
+
if (const IDSelector* id_sel = Cast<IDSelector>(sel)) {
|
|
150
|
+
if (id_sel->name() != name()) return nullptr;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return SimpleSelector::unifyWith(rhs);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ##########################################################################
|
|
157
|
+
// This is implemented in `selector/pseudo.dart` as `PseudoSelector::unify`
|
|
158
|
+
// ##########################################################################
|
|
159
|
+
CompoundSelector* PseudoSelector::unifyWith(CompoundSelector* compound)
|
|
160
|
+
{
|
|
161
|
+
|
|
162
|
+
if (compound->length() == 1 && compound->first()->is_universal()) {
|
|
163
|
+
// std::cerr << "implement universal pseudo\n";
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
for (const SimpleSelectorObj& sel : compound->elements()) {
|
|
167
|
+
if (*this == *sel) {
|
|
168
|
+
return compound;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
CompoundSelectorObj result = SASS_MEMORY_NEW(CompoundSelector, compound->pstate());
|
|
173
|
+
|
|
174
|
+
bool addedThis = false;
|
|
175
|
+
for (auto simple : compound->elements()) {
|
|
176
|
+
// Make sure pseudo selectors always come last.
|
|
177
|
+
if (PseudoSelectorObj pseudo = simple->getPseudoSelector()) {
|
|
178
|
+
if (pseudo->isElement()) {
|
|
179
|
+
// A given compound selector may only contain one pseudo element. If
|
|
180
|
+
// [compound] has a different one than [this], unification fails.
|
|
181
|
+
if (isElement()) {
|
|
182
|
+
return {};
|
|
183
|
+
}
|
|
184
|
+
// Otherwise, this is a pseudo selector and
|
|
185
|
+
// should come before pseduo elements.
|
|
186
|
+
result->append(this);
|
|
187
|
+
addedThis = true;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
result->append(simple);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (!addedThis) {
|
|
194
|
+
result->append(this);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return result.detach();
|
|
198
|
+
|
|
199
|
+
}
|
|
200
|
+
// EO PseudoSelector::unifyWith(CompoundSelector*
|
|
201
|
+
|
|
202
|
+
// ##########################################################################
|
|
203
|
+
// This is implemented in `extend/functions.dart` as `unifyUniversalAndElement`
|
|
204
|
+
// Returns a [SimpleSelector] that matches only elements that are matched by
|
|
205
|
+
// both [selector1] and [selector2], which must both be either [UniversalSelector]s
|
|
206
|
+
// or [TypeSelector]s. If no such selector can be produced, returns `null`.
|
|
207
|
+
// Note: libsass handles universal selector directly within the type selector
|
|
208
|
+
// ##########################################################################
|
|
209
|
+
SimpleSelector* TypeSelector::unifyWith(const SimpleSelector* rhs)
|
|
210
|
+
{
|
|
211
|
+
bool rhs_ns = false;
|
|
212
|
+
if (!(is_ns_eq(*rhs) || rhs->is_universal_ns())) {
|
|
213
|
+
if (!is_universal_ns()) {
|
|
214
|
+
return nullptr;
|
|
215
|
+
}
|
|
216
|
+
rhs_ns = true;
|
|
217
|
+
}
|
|
218
|
+
bool rhs_name = false;
|
|
219
|
+
if (!(name_ == rhs->name() || rhs->is_universal())) {
|
|
220
|
+
if (!(is_universal())) {
|
|
221
|
+
return nullptr;
|
|
222
|
+
}
|
|
223
|
+
rhs_name = true;
|
|
224
|
+
}
|
|
225
|
+
if (rhs_ns) {
|
|
226
|
+
ns(rhs->ns());
|
|
227
|
+
has_ns(rhs->has_ns());
|
|
228
|
+
}
|
|
229
|
+
if (rhs_name) name(rhs->name());
|
|
230
|
+
return this;
|
|
231
|
+
}
|
|
232
|
+
// EO TypeSelector::unifyWith(const SimpleSelector*)
|
|
233
|
+
|
|
234
|
+
// ##########################################################################
|
|
235
|
+
// Unify two complex selectors. Internally calls `unifyComplex`
|
|
236
|
+
// and then wraps the result in newly create ComplexSelectors.
|
|
237
|
+
// ##########################################################################
|
|
238
|
+
SelectorList* ComplexSelector::unifyWith(ComplexSelector* rhs)
|
|
239
|
+
{
|
|
240
|
+
SelectorListObj list = SASS_MEMORY_NEW(SelectorList, pstate());
|
|
241
|
+
sass::vector<sass::vector<SelectorComponentObj>> rv =
|
|
242
|
+
unifyComplex({ elements(), rhs->elements() });
|
|
243
|
+
for (sass::vector<SelectorComponentObj> items : rv) {
|
|
244
|
+
ComplexSelectorObj sel = SASS_MEMORY_NEW(ComplexSelector, pstate());
|
|
245
|
+
sel->elements() = std::move(items);
|
|
246
|
+
list->append(sel);
|
|
247
|
+
}
|
|
248
|
+
return list.detach();
|
|
249
|
+
}
|
|
250
|
+
// EO ComplexSelector::unifyWith(ComplexSelector*)
|
|
251
|
+
|
|
252
|
+
// ##########################################################################
|
|
253
|
+
// only called from the sass function `selector-unify`
|
|
254
|
+
// ##########################################################################
|
|
255
|
+
SelectorList* SelectorList::unifyWith(SelectorList* rhs)
|
|
256
|
+
{
|
|
257
|
+
SelectorList* slist = SASS_MEMORY_NEW(SelectorList, pstate());
|
|
258
|
+
// Unify all of children with RHS's children,
|
|
259
|
+
// storing the results in `unified_complex_selectors`
|
|
260
|
+
for (ComplexSelectorObj& seq1 : elements()) {
|
|
261
|
+
for (ComplexSelectorObj& seq2 : rhs->elements()) {
|
|
262
|
+
if (SelectorListObj unified = seq1->unifyWith(seq2)) {
|
|
263
|
+
std::move(unified->begin(), unified->end(),
|
|
264
|
+
std::inserter(slist->elements(), slist->end()));
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return slist;
|
|
269
|
+
}
|
|
270
|
+
// EO SelectorList::unifyWith(SelectorList*)
|
|
271
|
+
|
|
272
|
+
// ##########################################################################
|
|
273
|
+
// ##########################################################################
|
|
274
|
+
|
|
275
|
+
}
|
|
@@ -0,0 +1,616 @@
|
|
|
1
|
+
// sass.hpp must go before all system headers to get the
|
|
2
|
+
// __EXTENSIONS__ fix on Solaris.
|
|
3
|
+
#include "sass.hpp"
|
|
4
|
+
|
|
5
|
+
#include "ast.hpp"
|
|
6
|
+
#include "permutate.hpp"
|
|
7
|
+
#include "dart_helpers.hpp"
|
|
8
|
+
|
|
9
|
+
namespace Sass {
|
|
10
|
+
|
|
11
|
+
// ##########################################################################
|
|
12
|
+
// Returns whether or not [compound] contains a `::root` selector.
|
|
13
|
+
// ##########################################################################
|
|
14
|
+
bool hasRoot(const CompoundSelector* compound)
|
|
15
|
+
{
|
|
16
|
+
// Libsass does not yet know the root selector
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
// EO hasRoot
|
|
20
|
+
|
|
21
|
+
// ##########################################################################
|
|
22
|
+
// Returns whether a [CompoundSelector] may contain only
|
|
23
|
+
// one simple selector of the same type as [simple].
|
|
24
|
+
// ##########################################################################
|
|
25
|
+
bool isUnique(const SimpleSelector* simple)
|
|
26
|
+
{
|
|
27
|
+
if (Cast<IDSelector>(simple)) return true;
|
|
28
|
+
if (const PseudoSelector * pseudo = Cast<PseudoSelector>(simple)) {
|
|
29
|
+
if (pseudo->is_pseudo_element()) return true;
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
// EO isUnique
|
|
34
|
+
|
|
35
|
+
// ##########################################################################
|
|
36
|
+
// Returns whether [complex1] and [complex2] need to be unified to
|
|
37
|
+
// produce a valid combined selector. This is necessary when both
|
|
38
|
+
// selectors contain the same unique simple selector, such as an ID.
|
|
39
|
+
// ##########################################################################
|
|
40
|
+
bool mustUnify(
|
|
41
|
+
const sass::vector<SelectorComponentObj>& complex1,
|
|
42
|
+
const sass::vector<SelectorComponentObj>& complex2)
|
|
43
|
+
{
|
|
44
|
+
|
|
45
|
+
sass::vector<const SimpleSelector*> uniqueSelectors1;
|
|
46
|
+
for (const SelectorComponent* component : complex1) {
|
|
47
|
+
if (const CompoundSelector * compound = component->getCompound()) {
|
|
48
|
+
for (const SimpleSelector* sel : compound->elements()) {
|
|
49
|
+
if (isUnique(sel)) {
|
|
50
|
+
uniqueSelectors1.push_back(sel);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (uniqueSelectors1.empty()) return false;
|
|
56
|
+
|
|
57
|
+
// ToDo: unsure if this is correct
|
|
58
|
+
for (const SelectorComponent* component : complex2) {
|
|
59
|
+
if (const CompoundSelector * compound = component->getCompound()) {
|
|
60
|
+
for (const SimpleSelector* sel : compound->elements()) {
|
|
61
|
+
if (isUnique(sel)) {
|
|
62
|
+
for (auto check : uniqueSelectors1) {
|
|
63
|
+
if (*check == *sel) return true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return false;
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
// EO isUnique
|
|
74
|
+
|
|
75
|
+
// ##########################################################################
|
|
76
|
+
// Helper function used by `weaveParents`
|
|
77
|
+
// ##########################################################################
|
|
78
|
+
bool cmpGroups(
|
|
79
|
+
const sass::vector<SelectorComponentObj>& group1,
|
|
80
|
+
const sass::vector<SelectorComponentObj>& group2,
|
|
81
|
+
sass::vector<SelectorComponentObj>& select)
|
|
82
|
+
{
|
|
83
|
+
|
|
84
|
+
if (group1.size() == group2.size() && std::equal(group1.begin(), group1.end(), group2.begin(), PtrObjEqualityFn<SelectorComponent>)) {
|
|
85
|
+
select = group1;
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (!Cast<CompoundSelector>(group1.front())) {
|
|
90
|
+
select = {};
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
if (!Cast<CompoundSelector>(group2.front())) {
|
|
94
|
+
select = {};
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (complexIsParentSuperselector(group1, group2)) {
|
|
99
|
+
select = group2;
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
if (complexIsParentSuperselector(group2, group1)) {
|
|
103
|
+
select = group1;
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!mustUnify(group1, group2)) {
|
|
108
|
+
select = {};
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
sass::vector<sass::vector<SelectorComponentObj>> unified
|
|
113
|
+
= unifyComplex({ group1, group2 });
|
|
114
|
+
if (unified.empty()) return false;
|
|
115
|
+
if (unified.size() > 1) return false;
|
|
116
|
+
select = unified.front();
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
// EO cmpGroups
|
|
120
|
+
|
|
121
|
+
// ##########################################################################
|
|
122
|
+
// Helper function used by `weaveParents`
|
|
123
|
+
// ##########################################################################
|
|
124
|
+
template <class T>
|
|
125
|
+
bool checkForEmptyChild(const T& item) {
|
|
126
|
+
return item.empty();
|
|
127
|
+
}
|
|
128
|
+
// EO checkForEmptyChild
|
|
129
|
+
|
|
130
|
+
// ##########################################################################
|
|
131
|
+
// Helper function used by `weaveParents`
|
|
132
|
+
// ##########################################################################
|
|
133
|
+
bool cmpChunkForEmptySequence(
|
|
134
|
+
const sass::vector<sass::vector<SelectorComponentObj>>& seq,
|
|
135
|
+
const sass::vector<SelectorComponentObj>& group)
|
|
136
|
+
{
|
|
137
|
+
return seq.empty();
|
|
138
|
+
}
|
|
139
|
+
// EO cmpChunkForEmptySequence
|
|
140
|
+
|
|
141
|
+
// ##########################################################################
|
|
142
|
+
// Helper function used by `weaveParents`
|
|
143
|
+
// ##########################################################################
|
|
144
|
+
bool cmpChunkForParentSuperselector(
|
|
145
|
+
const sass::vector<sass::vector<SelectorComponentObj>>& seq,
|
|
146
|
+
const sass::vector<SelectorComponentObj>& group)
|
|
147
|
+
{
|
|
148
|
+
return seq.empty() || complexIsParentSuperselector(seq.front(), group);
|
|
149
|
+
}
|
|
150
|
+
// EO cmpChunkForParentSuperselector
|
|
151
|
+
|
|
152
|
+
// ##########################################################################
|
|
153
|
+
// Returns all orderings of initial subseqeuences of [queue1] and [queue2].
|
|
154
|
+
// The [done] callback is used to determine the extent of the initial
|
|
155
|
+
// subsequences. It's called with each queue until it returns `true`.
|
|
156
|
+
// Destructively removes the initial subsequences of [queue1] and [queue2].
|
|
157
|
+
// For example, given `(A B C | D E)` and `(1 2 | 3 4 5)` (with `|` denoting
|
|
158
|
+
// the boundary of the initial subsequence), this would return `[(A B C 1 2),
|
|
159
|
+
// (1 2 A B C)]`. The queues would then contain `(D E)` and `(3 4 5)`.
|
|
160
|
+
// ##########################################################################
|
|
161
|
+
template <class T>
|
|
162
|
+
sass::vector<sass::vector<T>> getChunks(
|
|
163
|
+
sass::vector<T>& queue1, sass::vector<T>& queue2,
|
|
164
|
+
const T& group, bool(*done)(const sass::vector<T>&, const T&)
|
|
165
|
+
) {
|
|
166
|
+
|
|
167
|
+
sass::vector<T> chunk1;
|
|
168
|
+
while (!done(queue1, group)) {
|
|
169
|
+
chunk1.push_back(queue1.front());
|
|
170
|
+
queue1.erase(queue1.begin());
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
sass::vector<T> chunk2;
|
|
174
|
+
while (!done(queue2, group)) {
|
|
175
|
+
chunk2.push_back(queue2.front());
|
|
176
|
+
queue2.erase(queue2.begin());
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (chunk1.empty() && chunk2.empty()) return {};
|
|
180
|
+
else if (chunk1.empty()) return { chunk2 };
|
|
181
|
+
else if (chunk2.empty()) return { chunk1 };
|
|
182
|
+
|
|
183
|
+
sass::vector<T> choice1(chunk1), choice2(chunk2);
|
|
184
|
+
std::move(std::begin(chunk2), std::end(chunk2),
|
|
185
|
+
std::inserter(choice1, std::end(choice1)));
|
|
186
|
+
std::move(std::begin(chunk1), std::end(chunk1),
|
|
187
|
+
std::inserter(choice2, std::end(choice2)));
|
|
188
|
+
return { choice1, choice2 };
|
|
189
|
+
}
|
|
190
|
+
// EO getChunks
|
|
191
|
+
|
|
192
|
+
// ##########################################################################
|
|
193
|
+
// If the first element of [queue] has a `::root`
|
|
194
|
+
// selector, removes and returns that element.
|
|
195
|
+
// ##########################################################################
|
|
196
|
+
CompoundSelectorObj getFirstIfRoot(sass::vector<SelectorComponentObj>& queue) {
|
|
197
|
+
if (queue.empty()) return {};
|
|
198
|
+
SelectorComponent* first = queue.front();
|
|
199
|
+
if (CompoundSelector* sel = Cast<CompoundSelector>(first)) {
|
|
200
|
+
if (!hasRoot(sel)) return {};
|
|
201
|
+
queue.erase(queue.begin());
|
|
202
|
+
return sel;
|
|
203
|
+
}
|
|
204
|
+
return {};
|
|
205
|
+
}
|
|
206
|
+
// EO getFirstIfRoot
|
|
207
|
+
|
|
208
|
+
// ##########################################################################
|
|
209
|
+
// Returns [complex], grouped into sub-lists such that no sub-list
|
|
210
|
+
// contains two adjacent [ComplexSelector]s. For example,
|
|
211
|
+
// `(A B > C D + E ~ > G)` is grouped into `[(A) (B > C) (D + E ~ > G)]`.
|
|
212
|
+
// ##########################################################################
|
|
213
|
+
sass::vector<sass::vector<SelectorComponentObj>> groupSelectors(
|
|
214
|
+
const sass::vector<SelectorComponentObj>& components)
|
|
215
|
+
{
|
|
216
|
+
bool lastWasCompound = false;
|
|
217
|
+
sass::vector<SelectorComponentObj> group;
|
|
218
|
+
sass::vector<sass::vector<SelectorComponentObj>> groups;
|
|
219
|
+
for (size_t i = 0; i < components.size(); i += 1) {
|
|
220
|
+
if (CompoundSelector* compound = components[i]->getCompound()) {
|
|
221
|
+
if (lastWasCompound) {
|
|
222
|
+
groups.push_back(group);
|
|
223
|
+
group.clear();
|
|
224
|
+
}
|
|
225
|
+
group.push_back(compound);
|
|
226
|
+
lastWasCompound = true;
|
|
227
|
+
}
|
|
228
|
+
else if (SelectorCombinator* combinator = components[i]->getCombinator()) {
|
|
229
|
+
group.push_back(combinator);
|
|
230
|
+
lastWasCompound = false;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (!group.empty()) {
|
|
234
|
+
groups.push_back(group);
|
|
235
|
+
}
|
|
236
|
+
return groups;
|
|
237
|
+
}
|
|
238
|
+
// EO groupSelectors
|
|
239
|
+
|
|
240
|
+
// ##########################################################################
|
|
241
|
+
// Extracts leading [Combinator]s from [components1] and [components2]
|
|
242
|
+
// and merges them together into a single list of combinators.
|
|
243
|
+
// If there are no combinators to be merged, returns an empty list.
|
|
244
|
+
// If the combinators can't be merged, returns `null`.
|
|
245
|
+
// ##########################################################################
|
|
246
|
+
bool mergeInitialCombinators(
|
|
247
|
+
sass::vector<SelectorComponentObj>& components1,
|
|
248
|
+
sass::vector<SelectorComponentObj>& components2,
|
|
249
|
+
sass::vector<SelectorComponentObj>& result)
|
|
250
|
+
{
|
|
251
|
+
|
|
252
|
+
sass::vector<SelectorComponentObj> combinators1;
|
|
253
|
+
while (!components1.empty() && Cast<SelectorCombinator>(components1.front())) {
|
|
254
|
+
SelectorCombinatorObj front = Cast<SelectorCombinator>(components1.front());
|
|
255
|
+
components1.erase(components1.begin());
|
|
256
|
+
combinators1.push_back(front);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
sass::vector<SelectorComponentObj> combinators2;
|
|
260
|
+
while (!components2.empty() && Cast<SelectorCombinator>(components2.front())) {
|
|
261
|
+
SelectorCombinatorObj front = Cast<SelectorCombinator>(components2.front());
|
|
262
|
+
components2.erase(components2.begin());
|
|
263
|
+
combinators2.push_back(front);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// If neither sequence of combinators is a subsequence
|
|
267
|
+
// of the other, they cannot be merged successfully.
|
|
268
|
+
sass::vector<SelectorComponentObj> LCS = lcs<SelectorComponentObj>(combinators1, combinators2);
|
|
269
|
+
|
|
270
|
+
if (ListEquality(LCS, combinators1, PtrObjEqualityFn<SelectorComponent>)) {
|
|
271
|
+
result = combinators2;
|
|
272
|
+
return true;
|
|
273
|
+
}
|
|
274
|
+
if (ListEquality(LCS, combinators2, PtrObjEqualityFn<SelectorComponent>)) {
|
|
275
|
+
result = combinators1;
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return false;
|
|
280
|
+
|
|
281
|
+
}
|
|
282
|
+
// EO mergeInitialCombinators
|
|
283
|
+
|
|
284
|
+
// ##########################################################################
|
|
285
|
+
// Extracts trailing [Combinator]s, and the selectors to which they apply,
|
|
286
|
+
// from [components1] and [components2] and merges them together into a
|
|
287
|
+
// single list. If there are no combinators to be merged, returns an
|
|
288
|
+
// empty list. If the sequences can't be merged, returns `null`.
|
|
289
|
+
// ##########################################################################
|
|
290
|
+
bool mergeFinalCombinators(
|
|
291
|
+
sass::vector<SelectorComponentObj>& components1,
|
|
292
|
+
sass::vector<SelectorComponentObj>& components2,
|
|
293
|
+
sass::vector<sass::vector<sass::vector<SelectorComponentObj>>>& result)
|
|
294
|
+
{
|
|
295
|
+
|
|
296
|
+
if (components1.empty() || !Cast<SelectorCombinator>(components1.back())) {
|
|
297
|
+
if (components2.empty() || !Cast<SelectorCombinator>(components2.back())) {
|
|
298
|
+
return true;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
sass::vector<SelectorComponentObj> combinators1;
|
|
303
|
+
while (!components1.empty() && Cast<SelectorCombinator>(components1.back())) {
|
|
304
|
+
SelectorCombinatorObj back = Cast<SelectorCombinator>(components1.back());
|
|
305
|
+
components1.erase(components1.end() - 1);
|
|
306
|
+
combinators1.push_back(back);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
sass::vector<SelectorComponentObj> combinators2;
|
|
310
|
+
while (!components2.empty() && Cast<SelectorCombinator>(components2.back())) {
|
|
311
|
+
SelectorCombinatorObj back = Cast<SelectorCombinator>(components2.back());
|
|
312
|
+
components2.erase(components2.end() - 1);
|
|
313
|
+
combinators2.push_back(back);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// reverse now as we used push_back (faster than new alloc)
|
|
317
|
+
std::reverse(combinators1.begin(), combinators1.end());
|
|
318
|
+
std::reverse(combinators2.begin(), combinators2.end());
|
|
319
|
+
|
|
320
|
+
if (combinators1.size() > 1 || combinators2.size() > 1) {
|
|
321
|
+
// If there are multiple combinators, something hacky's going on. If one
|
|
322
|
+
// is a supersequence of the other, use that, otherwise give up.
|
|
323
|
+
auto LCS = lcs<SelectorComponentObj>(combinators1, combinators2);
|
|
324
|
+
if (ListEquality(LCS, combinators1, PtrObjEqualityFn<SelectorComponent>)) {
|
|
325
|
+
result.push_back({ combinators2 });
|
|
326
|
+
}
|
|
327
|
+
else if (ListEquality(LCS, combinators2, PtrObjEqualityFn<SelectorComponent>)) {
|
|
328
|
+
result.push_back({ combinators1 });
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
return true;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// This code looks complicated, but it's actually just a bunch of special
|
|
337
|
+
// cases for interactions between different combinators.
|
|
338
|
+
SelectorCombinatorObj combinator1, combinator2;
|
|
339
|
+
if (!combinators1.empty()) combinator1 = combinators1.back();
|
|
340
|
+
if (!combinators2.empty()) combinator2 = combinators2.back();
|
|
341
|
+
|
|
342
|
+
if (!combinator1.isNull() && !combinator2.isNull()) {
|
|
343
|
+
|
|
344
|
+
CompoundSelector* compound1 = Cast<CompoundSelector>(components1.back());
|
|
345
|
+
CompoundSelector* compound2 = Cast<CompoundSelector>(components2.back());
|
|
346
|
+
|
|
347
|
+
components1.pop_back();
|
|
348
|
+
components2.pop_back();
|
|
349
|
+
|
|
350
|
+
if (combinator1->isGeneralCombinator() && combinator2->isGeneralCombinator()) {
|
|
351
|
+
|
|
352
|
+
if (compound1->isSuperselectorOf(compound2)) {
|
|
353
|
+
result.push_back({ { compound2, combinator2 } });
|
|
354
|
+
}
|
|
355
|
+
else if (compound2->isSuperselectorOf(compound1)) {
|
|
356
|
+
result.push_back({ { compound1, combinator1 } });
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
sass::vector<sass::vector<SelectorComponentObj>> choices;
|
|
360
|
+
choices.push_back({ compound1, combinator1, compound2, combinator2 });
|
|
361
|
+
choices.push_back({ compound2, combinator2, compound1, combinator1 });
|
|
362
|
+
if (CompoundSelector* unified = compound1->unifyWith(compound2)) {
|
|
363
|
+
choices.push_back({ unified, combinator1 });
|
|
364
|
+
}
|
|
365
|
+
result.push_back(choices);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
else if ((combinator1->isGeneralCombinator() && combinator2->isAdjacentCombinator()) ||
|
|
369
|
+
(combinator1->isAdjacentCombinator() && combinator2->isGeneralCombinator())) {
|
|
370
|
+
|
|
371
|
+
CompoundSelector* followingSiblingSelector = combinator1->isGeneralCombinator() ? compound1 : compound2;
|
|
372
|
+
CompoundSelector* nextSiblingSelector = combinator1->isGeneralCombinator() ? compound2 : compound1;
|
|
373
|
+
SelectorCombinator* followingSiblingCombinator = combinator1->isGeneralCombinator() ? combinator1 : combinator2;
|
|
374
|
+
SelectorCombinator* nextSiblingCombinator = combinator1->isGeneralCombinator() ? combinator2 : combinator1;
|
|
375
|
+
|
|
376
|
+
if (followingSiblingSelector->isSuperselectorOf(nextSiblingSelector)) {
|
|
377
|
+
result.push_back({ { nextSiblingSelector, nextSiblingCombinator } });
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
CompoundSelectorObj unified = compound1->unifyWith(compound2);
|
|
381
|
+
sass::vector<sass::vector<SelectorComponentObj>> items;
|
|
382
|
+
|
|
383
|
+
if (!unified.isNull()) {
|
|
384
|
+
items.push_back({
|
|
385
|
+
unified, nextSiblingCombinator
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
items.insert(items.begin(), {
|
|
390
|
+
followingSiblingSelector,
|
|
391
|
+
followingSiblingCombinator,
|
|
392
|
+
nextSiblingSelector,
|
|
393
|
+
nextSiblingCombinator,
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
result.push_back(items);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
}
|
|
400
|
+
else if (combinator1->isChildCombinator() && (combinator2->isAdjacentCombinator() || combinator2->isGeneralCombinator())) {
|
|
401
|
+
result.push_back({ { compound2, combinator2 } });
|
|
402
|
+
components1.push_back(compound1);
|
|
403
|
+
components1.push_back(combinator1);
|
|
404
|
+
}
|
|
405
|
+
else if (combinator2->isChildCombinator() && (combinator1->isAdjacentCombinator() || combinator1->isGeneralCombinator())) {
|
|
406
|
+
result.push_back({ { compound1, combinator1 } });
|
|
407
|
+
components2.push_back(compound2);
|
|
408
|
+
components2.push_back(combinator2);
|
|
409
|
+
}
|
|
410
|
+
else if (*combinator1 == *combinator2) {
|
|
411
|
+
CompoundSelectorObj unified = compound1->unifyWith(compound2);
|
|
412
|
+
if (unified.isNull()) return false;
|
|
413
|
+
result.push_back({ { unified, combinator1 } });
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
return mergeFinalCombinators(components1, components2, result);
|
|
420
|
+
|
|
421
|
+
}
|
|
422
|
+
else if (!combinator1.isNull()) {
|
|
423
|
+
|
|
424
|
+
if (combinator1->isChildCombinator() && !components2.empty()) {
|
|
425
|
+
const CompoundSelector* back1 = Cast<CompoundSelector>(components1.back());
|
|
426
|
+
const CompoundSelector* back2 = Cast<CompoundSelector>(components2.back());
|
|
427
|
+
if (back1 && back2 && back2->isSuperselectorOf(back1)) {
|
|
428
|
+
components2.pop_back();
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
result.push_back({ { components1.back(), combinator1 } });
|
|
433
|
+
|
|
434
|
+
components1.pop_back();
|
|
435
|
+
|
|
436
|
+
return mergeFinalCombinators(components1, components2, result);
|
|
437
|
+
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
if (combinator2->isChildCombinator() && !components1.empty()) {
|
|
441
|
+
const CompoundSelector* back1 = Cast<CompoundSelector>(components1.back());
|
|
442
|
+
const CompoundSelector* back2 = Cast<CompoundSelector>(components2.back());
|
|
443
|
+
if (back1 && back2 && back1->isSuperselectorOf(back2)) {
|
|
444
|
+
components1.pop_back();
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
result.push_back({ { components2.back(), combinator2 } });
|
|
449
|
+
|
|
450
|
+
components2.pop_back();
|
|
451
|
+
|
|
452
|
+
return mergeFinalCombinators(components1, components2, result);
|
|
453
|
+
|
|
454
|
+
}
|
|
455
|
+
// EO mergeFinalCombinators
|
|
456
|
+
|
|
457
|
+
// ##########################################################################
|
|
458
|
+
// Expands "parenthesized selectors" in [complexes]. That is, if
|
|
459
|
+
// we have `.A .B {@extend .C}` and `.D .C {...}`, this conceptually
|
|
460
|
+
// expands into `.D .C, .D (.A .B)`, and this function translates
|
|
461
|
+
// `.D (.A .B)` into `.D .A .B, .A .D .B`. For thoroughness, `.A.D .B`
|
|
462
|
+
// would also be required, but including merged selectors results in
|
|
463
|
+
// exponential output for very little gain. The selector `.D (.A .B)`
|
|
464
|
+
// is represented as the list `[[.D], [.A, .B]]`.
|
|
465
|
+
// ##########################################################################
|
|
466
|
+
sass::vector<sass::vector<SelectorComponentObj>> weave(
|
|
467
|
+
const sass::vector<sass::vector<SelectorComponentObj>>& complexes) {
|
|
468
|
+
|
|
469
|
+
sass::vector<sass::vector<SelectorComponentObj>> prefixes;
|
|
470
|
+
|
|
471
|
+
prefixes.push_back(complexes.at(0));
|
|
472
|
+
|
|
473
|
+
for (size_t i = 1; i < complexes.size(); i += 1) {
|
|
474
|
+
|
|
475
|
+
if (complexes[i].empty()) {
|
|
476
|
+
continue;
|
|
477
|
+
}
|
|
478
|
+
const sass::vector<SelectorComponentObj>& complex = complexes[i];
|
|
479
|
+
SelectorComponent* target = complex.back();
|
|
480
|
+
if (complex.size() == 1) {
|
|
481
|
+
for (auto& prefix : prefixes) {
|
|
482
|
+
prefix.push_back(target);
|
|
483
|
+
}
|
|
484
|
+
continue;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
sass::vector<SelectorComponentObj> parents(complex);
|
|
488
|
+
|
|
489
|
+
parents.pop_back();
|
|
490
|
+
|
|
491
|
+
sass::vector<sass::vector<SelectorComponentObj>> newPrefixes;
|
|
492
|
+
for (sass::vector<SelectorComponentObj> prefix : prefixes) {
|
|
493
|
+
sass::vector<sass::vector<SelectorComponentObj>>
|
|
494
|
+
parentPrefixes = weaveParents(prefix, parents);
|
|
495
|
+
if (parentPrefixes.empty()) continue;
|
|
496
|
+
for (auto& parentPrefix : parentPrefixes) {
|
|
497
|
+
parentPrefix.push_back(target);
|
|
498
|
+
newPrefixes.push_back(parentPrefix);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
prefixes = newPrefixes;
|
|
502
|
+
|
|
503
|
+
}
|
|
504
|
+
return prefixes;
|
|
505
|
+
|
|
506
|
+
}
|
|
507
|
+
// EO weave
|
|
508
|
+
|
|
509
|
+
// ##########################################################################
|
|
510
|
+
// Interweaves [parents1] and [parents2] as parents of the same target
|
|
511
|
+
// selector. Returns all possible orderings of the selectors in the
|
|
512
|
+
// inputs (including using unification) that maintain the relative
|
|
513
|
+
// ordering of the input. For example, given `.foo .bar` and `.baz .bang`,
|
|
514
|
+
// this would return `.foo .bar .baz .bang`, `.foo .bar.baz .bang`,
|
|
515
|
+
// `.foo .baz .bar .bang`, `.foo .baz .bar.bang`, `.foo .baz .bang .bar`,
|
|
516
|
+
// and so on until `.baz .bang .foo .bar`. Semantically, for selectors A
|
|
517
|
+
// and B, this returns all selectors `AB_i` such that the union over all i
|
|
518
|
+
// of elements matched by `AB_i X` is identical to the intersection of all
|
|
519
|
+
// elements matched by `A X` and all elements matched by `B X`. Some `AB_i`
|
|
520
|
+
// are elided to reduce the size of the output.
|
|
521
|
+
// ##########################################################################
|
|
522
|
+
sass::vector<sass::vector<SelectorComponentObj>> weaveParents(
|
|
523
|
+
sass::vector<SelectorComponentObj> queue1,
|
|
524
|
+
sass::vector<SelectorComponentObj> queue2)
|
|
525
|
+
{
|
|
526
|
+
|
|
527
|
+
sass::vector<SelectorComponentObj> leads;
|
|
528
|
+
sass::vector<sass::vector<sass::vector<SelectorComponentObj>>> trails;
|
|
529
|
+
if (!mergeInitialCombinators(queue1, queue2, leads)) return {};
|
|
530
|
+
if (!mergeFinalCombinators(queue1, queue2, trails)) return {};
|
|
531
|
+
// list comes out in reverse order for performance
|
|
532
|
+
std::reverse(trails.begin(), trails.end());
|
|
533
|
+
|
|
534
|
+
// Make sure there's at most one `:root` in the output.
|
|
535
|
+
// Note: does not yet do anything in libsass (no root selector)
|
|
536
|
+
CompoundSelectorObj root1 = getFirstIfRoot(queue1);
|
|
537
|
+
CompoundSelectorObj root2 = getFirstIfRoot(queue2);
|
|
538
|
+
|
|
539
|
+
if (!root1.isNull() && !root2.isNull()) {
|
|
540
|
+
CompoundSelectorObj root = root1->unifyWith(root2);
|
|
541
|
+
if (root.isNull()) return {}; // null
|
|
542
|
+
queue1.insert(queue1.begin(), root);
|
|
543
|
+
queue2.insert(queue2.begin(), root);
|
|
544
|
+
}
|
|
545
|
+
else if (!root1.isNull()) {
|
|
546
|
+
queue2.insert(queue2.begin(), root1);
|
|
547
|
+
}
|
|
548
|
+
else if (!root2.isNull()) {
|
|
549
|
+
queue1.insert(queue1.begin(), root2);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// group into sub-lists so no sub-list contains two adjacent ComplexSelectors.
|
|
553
|
+
sass::vector<sass::vector<SelectorComponentObj>> groups1 = groupSelectors(queue1);
|
|
554
|
+
sass::vector<sass::vector<SelectorComponentObj>> groups2 = groupSelectors(queue2);
|
|
555
|
+
|
|
556
|
+
// The main array to store our choices that will be permutated
|
|
557
|
+
sass::vector<sass::vector<sass::vector<SelectorComponentObj>>> choices;
|
|
558
|
+
|
|
559
|
+
// append initial combinators
|
|
560
|
+
choices.push_back({ leads });
|
|
561
|
+
|
|
562
|
+
sass::vector<sass::vector<SelectorComponentObj>> LCS =
|
|
563
|
+
lcs<sass::vector<SelectorComponentObj>>(groups1, groups2, cmpGroups);
|
|
564
|
+
|
|
565
|
+
for (auto group : LCS) {
|
|
566
|
+
|
|
567
|
+
// Create junks from groups1 and groups2
|
|
568
|
+
sass::vector<sass::vector<sass::vector<SelectorComponentObj>>>
|
|
569
|
+
chunks = getChunks<sass::vector<SelectorComponentObj>>(
|
|
570
|
+
groups1, groups2, group, cmpChunkForParentSuperselector);
|
|
571
|
+
|
|
572
|
+
// Create expanded array by flattening chunks2 inner
|
|
573
|
+
sass::vector<sass::vector<SelectorComponentObj>>
|
|
574
|
+
expanded = flattenInner(chunks);
|
|
575
|
+
|
|
576
|
+
// Prepare data structures
|
|
577
|
+
choices.push_back(expanded);
|
|
578
|
+
choices.push_back({ group });
|
|
579
|
+
if (!groups1.empty()) {
|
|
580
|
+
groups1.erase(groups1.begin());
|
|
581
|
+
}
|
|
582
|
+
if (!groups2.empty()) {
|
|
583
|
+
groups2.erase(groups2.begin());
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// Create junks from groups1 and groups2
|
|
589
|
+
sass::vector<sass::vector<sass::vector<SelectorComponentObj>>>
|
|
590
|
+
chunks = getChunks<sass::vector<SelectorComponentObj>>(
|
|
591
|
+
groups1, groups2, {}, cmpChunkForEmptySequence);
|
|
592
|
+
|
|
593
|
+
// Append chunks with inner arrays flattened
|
|
594
|
+
choices.emplace_back(flattenInner(chunks));
|
|
595
|
+
|
|
596
|
+
// append all trailing selectors to choices
|
|
597
|
+
std::move(std::begin(trails), std::end(trails),
|
|
598
|
+
std::inserter(choices, std::end(choices)));
|
|
599
|
+
|
|
600
|
+
// move all non empty items to the front, then erase the trailing ones
|
|
601
|
+
choices.erase(std::remove_if(choices.begin(), choices.end(), checkForEmptyChild
|
|
602
|
+
<sass::vector<sass::vector<SelectorComponentObj>>>), choices.end());
|
|
603
|
+
|
|
604
|
+
// permutate all possible paths through selectors
|
|
605
|
+
sass::vector<sass::vector<SelectorComponentObj>>
|
|
606
|
+
results = flattenInner(permutate(choices));
|
|
607
|
+
|
|
608
|
+
return results;
|
|
609
|
+
|
|
610
|
+
}
|
|
611
|
+
// EO weaveParents
|
|
612
|
+
|
|
613
|
+
// ##########################################################################
|
|
614
|
+
// ##########################################################################
|
|
615
|
+
|
|
616
|
+
}
|