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
data/ext/libsass/src/output.hpp
CHANGED
|
@@ -11,13 +11,6 @@
|
|
|
11
11
|
namespace Sass {
|
|
12
12
|
class Context;
|
|
13
13
|
|
|
14
|
-
// Refactor to make it generic to find linefeed (look behind)
|
|
15
|
-
inline bool ends_with(std::string const & value, std::string const & ending)
|
|
16
|
-
{
|
|
17
|
-
if (ending.size() > value.size()) return false;
|
|
18
|
-
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
|
|
19
|
-
}
|
|
20
|
-
|
|
21
14
|
class Output : public Inspect {
|
|
22
15
|
protected:
|
|
23
16
|
using Inspect::operator();
|
|
@@ -27,25 +20,25 @@ namespace Sass {
|
|
|
27
20
|
virtual ~Output();
|
|
28
21
|
|
|
29
22
|
protected:
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
sass::string charset;
|
|
24
|
+
sass::vector<AST_Node*> top_nodes;
|
|
32
25
|
|
|
33
26
|
public:
|
|
34
27
|
OutputBuffer get_buffer(void);
|
|
35
28
|
|
|
36
|
-
virtual void operator()(
|
|
37
|
-
virtual void operator()(
|
|
38
|
-
virtual void operator()(
|
|
39
|
-
virtual void operator()(
|
|
40
|
-
virtual void operator()(
|
|
41
|
-
virtual void operator()(
|
|
42
|
-
virtual void operator()(
|
|
43
|
-
virtual void operator()(
|
|
44
|
-
virtual void operator()(
|
|
45
|
-
virtual void operator()(
|
|
46
|
-
virtual void operator()(
|
|
47
|
-
|
|
48
|
-
void fallback_impl(
|
|
29
|
+
virtual void operator()(Map*);
|
|
30
|
+
virtual void operator()(StyleRule*);
|
|
31
|
+
virtual void operator()(SupportsRule*);
|
|
32
|
+
virtual void operator()(CssMediaRule*);
|
|
33
|
+
virtual void operator()(AtRule*);
|
|
34
|
+
virtual void operator()(Keyframe_Rule*);
|
|
35
|
+
virtual void operator()(Import*);
|
|
36
|
+
virtual void operator()(Comment*);
|
|
37
|
+
virtual void operator()(Number*);
|
|
38
|
+
virtual void operator()(String_Quoted*);
|
|
39
|
+
virtual void operator()(String_Constant*);
|
|
40
|
+
|
|
41
|
+
void fallback_impl(AST_Node* n);
|
|
49
42
|
|
|
50
43
|
};
|
|
51
44
|
|
data/ext/libsass/src/parser.cpp
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
|
+
// sass.hpp must go before all system headers to get the
|
|
2
|
+
// __EXTENSIONS__ fix on Solaris.
|
|
1
3
|
#include "sass.hpp"
|
|
4
|
+
|
|
2
5
|
#include "parser.hpp"
|
|
3
|
-
#include "file.hpp"
|
|
4
|
-
#include "inspect.hpp"
|
|
5
|
-
#include "constants.hpp"
|
|
6
|
-
#include "util.hpp"
|
|
7
|
-
#include "prelexer.hpp"
|
|
8
6
|
#include "color_maps.hpp"
|
|
9
|
-
#include "
|
|
10
|
-
#include "error_handling.hpp"
|
|
7
|
+
#include "util_string.hpp"
|
|
11
8
|
|
|
12
9
|
// Notes about delayed: some ast nodes can have delayed evaluation so
|
|
13
10
|
// they can preserve their original semantics if needed. This is most
|
|
@@ -21,57 +18,46 @@
|
|
|
21
18
|
// Another case with delayed values are colors. In compressed mode
|
|
22
19
|
// only processed values get compressed (other are left as written).
|
|
23
20
|
|
|
24
|
-
#include <cstdlib>
|
|
25
|
-
#include <iostream>
|
|
26
|
-
#include <vector>
|
|
27
|
-
#include <typeinfo>
|
|
28
21
|
|
|
29
22
|
namespace Sass {
|
|
30
23
|
using namespace Constants;
|
|
31
24
|
using namespace Prelexer;
|
|
32
25
|
|
|
33
|
-
Parser Parser::from_c_str(const char* beg, Context& ctx, Backtraces traces, ParserState pstate, const char* source)
|
|
34
|
-
{
|
|
35
|
-
pstate.offset.column = 0;
|
|
36
|
-
pstate.offset.line = 0;
|
|
37
|
-
Parser p(ctx, pstate, traces);
|
|
38
|
-
p.source = source ? source : beg;
|
|
39
|
-
p.position = beg ? beg : p.source;
|
|
40
|
-
p.end = p.position + strlen(p.position);
|
|
41
|
-
Block_Obj root = SASS_MEMORY_NEW(Block, pstate);
|
|
42
|
-
p.block_stack.push_back(root);
|
|
43
|
-
root->is_root(true);
|
|
44
|
-
return p;
|
|
45
|
-
}
|
|
46
26
|
|
|
47
|
-
Parser
|
|
27
|
+
Parser::Parser(SourceData* source, Context& ctx, Backtraces traces, bool allow_parent) :
|
|
28
|
+
SourceSpan(source),
|
|
29
|
+
ctx(ctx),
|
|
30
|
+
source(source),
|
|
31
|
+
begin(source->begin()),
|
|
32
|
+
position(source->begin()),
|
|
33
|
+
end(source->end()),
|
|
34
|
+
before_token(0, 0),
|
|
35
|
+
after_token(0, 0),
|
|
36
|
+
pstate(source->getSourceSpan()),
|
|
37
|
+
traces(traces),
|
|
38
|
+
indentation(0),
|
|
39
|
+
nestings(0),
|
|
40
|
+
allow_parent(allow_parent)
|
|
48
41
|
{
|
|
49
|
-
pstate.offset.column = 0;
|
|
50
|
-
pstate.offset.line = 0;
|
|
51
|
-
Parser p(ctx, pstate, traces);
|
|
52
|
-
p.source = source ? source : beg;
|
|
53
|
-
p.position = beg ? beg : p.source;
|
|
54
|
-
p.end = end ? end : p.position + strlen(p.position);
|
|
55
42
|
Block_Obj root = SASS_MEMORY_NEW(Block, pstate);
|
|
56
|
-
|
|
43
|
+
stack.push_back(Scope::Root);
|
|
44
|
+
block_stack.push_back(root);
|
|
57
45
|
root->is_root(true);
|
|
58
|
-
return p;
|
|
59
46
|
}
|
|
60
47
|
|
|
61
|
-
|
|
48
|
+
void Parser::advanceToNextToken() {
|
|
62
49
|
lex < css_comments >(false);
|
|
63
50
|
// advance to position
|
|
64
|
-
pstate += pstate.offset;
|
|
51
|
+
pstate.position += pstate.offset;
|
|
65
52
|
pstate.offset.column = 0;
|
|
66
53
|
pstate.offset.line = 0;
|
|
67
54
|
}
|
|
68
55
|
|
|
69
|
-
|
|
56
|
+
SelectorListObj Parser::parse_selector(SourceData* source, Context& ctx, Backtraces traces, bool allow_parent)
|
|
70
57
|
{
|
|
71
|
-
Parser p
|
|
72
|
-
// ToDo: ruby sass errors on parent references
|
|
58
|
+
Parser p(source, ctx, traces, allow_parent);
|
|
73
59
|
// ToDo: remap the source-map entries somehow
|
|
74
|
-
return p.
|
|
60
|
+
return p.parseSelectorList(false);
|
|
75
61
|
}
|
|
76
62
|
|
|
77
63
|
bool Parser::peek_newline(const char* start)
|
|
@@ -80,18 +66,6 @@ namespace Sass {
|
|
|
80
66
|
&& ! peek_css<exactly<'{'>>(start);
|
|
81
67
|
}
|
|
82
68
|
|
|
83
|
-
Parser Parser::from_token(Token t, Context& ctx, Backtraces traces, ParserState pstate, const char* source)
|
|
84
|
-
{
|
|
85
|
-
Parser p(ctx, pstate, traces);
|
|
86
|
-
p.source = source ? source : t.begin;
|
|
87
|
-
p.position = t.begin ? t.begin : p.source;
|
|
88
|
-
p.end = t.end ? t.end : p.position + strlen(p.position);
|
|
89
|
-
Block_Obj root = SASS_MEMORY_NEW(Block, pstate);
|
|
90
|
-
p.block_stack.push_back(root);
|
|
91
|
-
root->is_root(true);
|
|
92
|
-
return p;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
69
|
/* main entry point to parse root block */
|
|
96
70
|
Block_Obj Parser::parse()
|
|
97
71
|
{
|
|
@@ -104,7 +78,7 @@ namespace Sass {
|
|
|
104
78
|
|
|
105
79
|
// report invalid utf8
|
|
106
80
|
if (it != end) {
|
|
107
|
-
pstate += Offset::init(position, it);
|
|
81
|
+
pstate.position += Offset::init(position, it);
|
|
108
82
|
traces.push_back(Backtrace(pstate));
|
|
109
83
|
throw Exception::InvalidSass(pstate, traces, "Invalid UTF-8 sequence");
|
|
110
84
|
}
|
|
@@ -115,7 +89,7 @@ namespace Sass {
|
|
|
115
89
|
// check seems a bit esoteric but works
|
|
116
90
|
if (ctx.resources.size() == 1) {
|
|
117
91
|
// apply headers only on very first include
|
|
118
|
-
ctx.apply_custom_headers(root,
|
|
92
|
+
ctx.apply_custom_headers(root, getPath(), pstate);
|
|
119
93
|
}
|
|
120
94
|
|
|
121
95
|
// parse children nodes
|
|
@@ -258,16 +232,23 @@ namespace Sass {
|
|
|
258
232
|
else if (lex < kwd_extend >(true)) {
|
|
259
233
|
Lookahead lookahead = lookahead_for_include(position);
|
|
260
234
|
if (!lookahead.found) css_error("Invalid CSS", " after ", ": expected selector, was ");
|
|
261
|
-
|
|
235
|
+
SelectorListObj target;
|
|
262
236
|
if (!lookahead.has_interpolants) {
|
|
263
|
-
|
|
237
|
+
LOCAL_FLAG(allow_parent, false);
|
|
238
|
+
auto selector = parseSelectorList(true);
|
|
239
|
+
auto extender = SASS_MEMORY_NEW(ExtendRule, pstate, selector);
|
|
240
|
+
extender->isOptional(selector && selector->is_optional());
|
|
241
|
+
block->append(extender);
|
|
264
242
|
}
|
|
265
243
|
else {
|
|
266
|
-
|
|
267
|
-
|
|
244
|
+
LOCAL_FLAG(allow_parent, false);
|
|
245
|
+
auto selector = parse_selector_schema(lookahead.found, true);
|
|
246
|
+
auto extender = SASS_MEMORY_NEW(ExtendRule, pstate, selector);
|
|
247
|
+
// A schema is not optional yet, check once it is evaluated
|
|
248
|
+
// extender->isOptional(selector && selector->is_optional());
|
|
249
|
+
block->append(extender);
|
|
268
250
|
}
|
|
269
251
|
|
|
270
|
-
block->append(SASS_MEMORY_NEW(Extension, pstate, target));
|
|
271
252
|
}
|
|
272
253
|
|
|
273
254
|
// selector may contain interpolations which need delayed evaluation
|
|
@@ -280,7 +261,7 @@ namespace Sass {
|
|
|
280
261
|
}
|
|
281
262
|
|
|
282
263
|
// parse multiple specific keyword directives
|
|
283
|
-
else if (lex < kwd_media >(true)) { block->append(
|
|
264
|
+
else if (lex < kwd_media >(true)) { block->append(parseMediaRule()); }
|
|
284
265
|
else if (lex < kwd_at_root >(true)) { block->append(parse_at_root_block()); }
|
|
285
266
|
else if (lex < kwd_include_directive >(true)) { block->append(parse_include_directive()); }
|
|
286
267
|
else if (lex < kwd_content_directive >(true)) { block->append(parse_content_directive()); }
|
|
@@ -291,9 +272,9 @@ namespace Sass {
|
|
|
291
272
|
// ignore the @charset directive for now
|
|
292
273
|
else if (lex< kwd_charset_directive >(true)) { parse_charset_directive(); }
|
|
293
274
|
|
|
275
|
+
else if (lex < exactly < else_kwd >>(true)) { error("Invalid CSS: @else must come after @if"); }
|
|
276
|
+
|
|
294
277
|
// generic at keyword (keep last)
|
|
295
|
-
else if (lex< re_special_directive >(true)) { block->append(parse_special_directive()); }
|
|
296
|
-
else if (lex< re_prefixed_directive >(true)) { block->append(parse_prefixed_directive()); }
|
|
297
278
|
else if (lex< at_keyword >(true)) { block->append(parse_directive()); }
|
|
298
279
|
|
|
299
280
|
else if (is_root && stack.back() != Scope::AtRoot /* && block->is_root() */) {
|
|
@@ -328,33 +309,33 @@ namespace Sass {
|
|
|
328
309
|
Import_Obj Parser::parse_import()
|
|
329
310
|
{
|
|
330
311
|
Import_Obj imp = SASS_MEMORY_NEW(Import, pstate);
|
|
331
|
-
|
|
312
|
+
sass::vector<std::pair<sass::string,Function_Call_Obj>> to_import;
|
|
332
313
|
bool first = true;
|
|
333
314
|
do {
|
|
334
315
|
while (lex< block_comment >());
|
|
335
316
|
if (lex< quoted_string >()) {
|
|
336
|
-
to_import.push_back(std::pair<
|
|
317
|
+
to_import.push_back(std::pair<sass::string,Function_Call_Obj>(sass::string(lexed), {}));
|
|
337
318
|
}
|
|
338
319
|
else if (lex< uri_prefix >()) {
|
|
339
320
|
Arguments_Obj args = SASS_MEMORY_NEW(Arguments, pstate);
|
|
340
|
-
Function_Call_Obj result = SASS_MEMORY_NEW(Function_Call, pstate, "url", args);
|
|
321
|
+
Function_Call_Obj result = SASS_MEMORY_NEW(Function_Call, pstate, sass::string("url"), args);
|
|
341
322
|
|
|
342
323
|
if (lex< quoted_string >()) {
|
|
343
|
-
|
|
324
|
+
ExpressionObj quoted_url = parse_string();
|
|
344
325
|
args->append(SASS_MEMORY_NEW(Argument, quoted_url->pstate(), quoted_url));
|
|
345
326
|
}
|
|
346
327
|
else if (String_Obj string_url = parse_url_function_argument()) {
|
|
347
328
|
args->append(SASS_MEMORY_NEW(Argument, string_url->pstate(), string_url));
|
|
348
329
|
}
|
|
349
330
|
else if (peek < skip_over_scopes < exactly < '(' >, exactly < ')' > > >(position)) {
|
|
350
|
-
|
|
331
|
+
ExpressionObj braced_url = parse_list(); // parse_interpolated_chunk(lexed);
|
|
351
332
|
args->append(SASS_MEMORY_NEW(Argument, braced_url->pstate(), braced_url));
|
|
352
333
|
}
|
|
353
334
|
else {
|
|
354
335
|
error("malformed URL");
|
|
355
336
|
}
|
|
356
337
|
if (!lex< exactly<')'> >()) error("URI is missing ')'");
|
|
357
|
-
to_import.push_back(std::pair<
|
|
338
|
+
to_import.push_back(std::pair<sass::string, Function_Call_Obj>("", result));
|
|
358
339
|
}
|
|
359
340
|
else {
|
|
360
341
|
if (first) error("@import directive requires a url or quoted path");
|
|
@@ -373,9 +354,9 @@ namespace Sass {
|
|
|
373
354
|
imp->urls().push_back(location.second);
|
|
374
355
|
}
|
|
375
356
|
// check if custom importers want to take over the handling
|
|
376
|
-
else if (!ctx.call_importers(unquote(location.first),
|
|
357
|
+
else if (!ctx.call_importers(unquote(location.first), getPath(), pstate, imp)) {
|
|
377
358
|
// nobody wants it, so we do our import
|
|
378
|
-
ctx.import_url(imp, location.first,
|
|
359
|
+
ctx.import_url(imp, location.first, getPath());
|
|
379
360
|
}
|
|
380
361
|
}
|
|
381
362
|
|
|
@@ -384,12 +365,12 @@ namespace Sass {
|
|
|
384
365
|
|
|
385
366
|
Definition_Obj Parser::parse_definition(Definition::Type which_type)
|
|
386
367
|
{
|
|
387
|
-
|
|
368
|
+
sass::string which_str(lexed);
|
|
388
369
|
if (!lex< identifier >()) error("invalid name in " + which_str + " definition");
|
|
389
|
-
|
|
370
|
+
sass::string name(Util::normalize_underscores(lexed));
|
|
390
371
|
if (which_type == Definition::FUNCTION && (name == "and" || name == "or" || name == "not"))
|
|
391
372
|
{ error("Invalid function name \"" + name + "\"."); }
|
|
392
|
-
|
|
373
|
+
SourceSpan source_position_of_def = pstate;
|
|
393
374
|
Parameters_Obj params = parse_parameters();
|
|
394
375
|
if (which_type == Definition::MIXIN) stack.push_back(Scope::Mixin);
|
|
395
376
|
else stack.push_back(Scope::Function);
|
|
@@ -423,9 +404,9 @@ namespace Sass {
|
|
|
423
404
|
}
|
|
424
405
|
while (lex< alternatives < spaces, block_comment > >());
|
|
425
406
|
lex < variable >();
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
407
|
+
sass::string name(Util::normalize_underscores(lexed));
|
|
408
|
+
SourceSpan pos = pstate;
|
|
409
|
+
ExpressionObj val;
|
|
429
410
|
bool is_rest = false;
|
|
430
411
|
while (lex< alternatives < spaces, block_comment > >());
|
|
431
412
|
if (lex< exactly<':'> >()) { // there's a default value
|
|
@@ -469,17 +450,17 @@ namespace Sass {
|
|
|
469
450
|
Argument_Obj arg;
|
|
470
451
|
if (peek_css< sequence < variable, optional_css_comments, exactly<':'> > >()) {
|
|
471
452
|
lex_css< variable >();
|
|
472
|
-
|
|
473
|
-
|
|
453
|
+
sass::string name(Util::normalize_underscores(lexed));
|
|
454
|
+
SourceSpan p = pstate;
|
|
474
455
|
lex_css< exactly<':'> >();
|
|
475
|
-
|
|
456
|
+
ExpressionObj val = parse_space_list();
|
|
476
457
|
arg = SASS_MEMORY_NEW(Argument, p, val, name);
|
|
477
458
|
}
|
|
478
459
|
else {
|
|
479
460
|
bool is_arglist = false;
|
|
480
461
|
bool is_keyword = false;
|
|
481
|
-
|
|
482
|
-
|
|
462
|
+
ExpressionObj val = parse_space_list();
|
|
463
|
+
List* l = Cast<List>(val);
|
|
483
464
|
if (lex_css< exactly< ellipsis > >()) {
|
|
484
465
|
if (val->concrete_type() == Expression::MAP || (
|
|
485
466
|
(l != NULL && l->separator() == SASS_HASH)
|
|
@@ -493,13 +474,13 @@ namespace Sass {
|
|
|
493
474
|
|
|
494
475
|
Assignment_Obj Parser::parse_assignment()
|
|
495
476
|
{
|
|
496
|
-
|
|
497
|
-
|
|
477
|
+
sass::string name(Util::normalize_underscores(lexed));
|
|
478
|
+
SourceSpan var_source_position = pstate;
|
|
498
479
|
if (!lex< exactly<':'> >()) error("expected ':' after " + name + " in assignment statement");
|
|
499
480
|
if (peek_css< alternatives < exactly<';'>, end_of_file > >()) {
|
|
500
481
|
css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
|
|
501
482
|
}
|
|
502
|
-
|
|
483
|
+
ExpressionObj val;
|
|
503
484
|
Lookahead lookahead = lookahead_for_value(position);
|
|
504
485
|
if (lookahead.has_interpolants && lookahead.found) {
|
|
505
486
|
val = parse_value_schema(lookahead.found);
|
|
@@ -516,7 +497,7 @@ namespace Sass {
|
|
|
516
497
|
}
|
|
517
498
|
|
|
518
499
|
// a ruleset connects a selector and a block
|
|
519
|
-
|
|
500
|
+
StyleRuleObj Parser::parse_ruleset(Lookahead lookahead)
|
|
520
501
|
{
|
|
521
502
|
NESTING_GUARD(nestings);
|
|
522
503
|
// inherit is_root from parent block
|
|
@@ -525,12 +506,15 @@ namespace Sass {
|
|
|
525
506
|
// make sure to move up the the last position
|
|
526
507
|
lex < optional_css_whitespace >(false, true);
|
|
527
508
|
// create the connector object (add parts later)
|
|
528
|
-
|
|
509
|
+
StyleRuleObj ruleset = SASS_MEMORY_NEW(StyleRule, pstate);
|
|
529
510
|
// parse selector static or as schema to be evaluated later
|
|
530
|
-
if (lookahead.parsable)
|
|
511
|
+
if (lookahead.parsable) {
|
|
512
|
+
ruleset->selector(parseSelectorList(false));
|
|
513
|
+
}
|
|
531
514
|
else {
|
|
532
|
-
|
|
533
|
-
|
|
515
|
+
SelectorListObj list = SASS_MEMORY_NEW(SelectorList, pstate);
|
|
516
|
+
auto sc = parse_selector_schema(lookahead.position, false);
|
|
517
|
+
ruleset->schema(sc);
|
|
534
518
|
ruleset->selector(list);
|
|
535
519
|
}
|
|
536
520
|
// then parse the inner block
|
|
@@ -556,21 +540,20 @@ namespace Sass {
|
|
|
556
540
|
lex< optional_spaces >();
|
|
557
541
|
const char* i = position;
|
|
558
542
|
// selector schema re-uses string schema implementation
|
|
559
|
-
|
|
543
|
+
String_Schema* schema = SASS_MEMORY_NEW(String_Schema, pstate);
|
|
560
544
|
// the selector schema is pretty much just a wrapper for the string schema
|
|
561
545
|
Selector_Schema_Obj selector_schema = SASS_MEMORY_NEW(Selector_Schema, pstate, schema);
|
|
562
546
|
selector_schema->connect_parent(chroot == false);
|
|
563
|
-
selector_schema->media_block(last_media_block);
|
|
564
547
|
|
|
565
548
|
// process until end
|
|
566
549
|
while (i < end_of_selector) {
|
|
567
|
-
// try to parse
|
|
550
|
+
// try to parse multiple interpolants
|
|
568
551
|
if (const char* p = find_first_in_interval< exactly<hash_lbrace>, block_comment >(i, end_of_selector)) {
|
|
569
552
|
// accumulate the preceding segment if the position has advanced
|
|
570
553
|
if (i < p) {
|
|
571
|
-
|
|
554
|
+
sass::string parsed(i, p);
|
|
572
555
|
String_Constant_Obj str = SASS_MEMORY_NEW(String_Constant, pstate, parsed);
|
|
573
|
-
pstate += Offset(parsed);
|
|
556
|
+
pstate.position += Offset(parsed);
|
|
574
557
|
str->update_pstate(pstate);
|
|
575
558
|
schema->append(str);
|
|
576
559
|
}
|
|
@@ -583,15 +566,16 @@ namespace Sass {
|
|
|
583
566
|
css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
|
|
584
567
|
}
|
|
585
568
|
// pass inner expression to the parser to resolve nested interpolations
|
|
586
|
-
|
|
587
|
-
|
|
569
|
+
LocalOption<const char*> partEnd(end, j);
|
|
570
|
+
LocalOption<const char*> partBeg(position, p + 2);
|
|
571
|
+
ExpressionObj interpolant = parse_list();
|
|
588
572
|
// set status on the list expression
|
|
589
573
|
interpolant->is_interpolant(true);
|
|
590
574
|
// schema->has_interpolants(true);
|
|
591
575
|
// add to the string schema
|
|
592
576
|
schema->append(interpolant);
|
|
593
577
|
// advance parser state
|
|
594
|
-
pstate.add(p+2, j);
|
|
578
|
+
pstate.position.add(p+2, j);
|
|
595
579
|
// advance position
|
|
596
580
|
i = j;
|
|
597
581
|
}
|
|
@@ -600,9 +584,9 @@ namespace Sass {
|
|
|
600
584
|
else {
|
|
601
585
|
// make sure to add the last bits of the string up to the end (if any)
|
|
602
586
|
if (i < end_of_selector) {
|
|
603
|
-
|
|
587
|
+
sass::string parsed(i, end_of_selector);
|
|
604
588
|
String_Constant_Obj str = SASS_MEMORY_NEW(String_Constant, pstate, parsed);
|
|
605
|
-
pstate += Offset(parsed);
|
|
589
|
+
pstate.position += Offset(parsed);
|
|
606
590
|
str->update_pstate(pstate);
|
|
607
591
|
i = end_of_selector;
|
|
608
592
|
schema->append(str);
|
|
@@ -619,7 +603,7 @@ namespace Sass {
|
|
|
619
603
|
selector_schema->update_pstate(pstate);
|
|
620
604
|
schema->update_pstate(pstate);
|
|
621
605
|
|
|
622
|
-
after_token = before_token = pstate;
|
|
606
|
+
after_token = before_token = pstate.position;
|
|
623
607
|
|
|
624
608
|
// return parsed result
|
|
625
609
|
return selector_schema.detach();
|
|
@@ -643,239 +627,49 @@ namespace Sass {
|
|
|
643
627
|
// lex identifier into `lexed` var
|
|
644
628
|
lex_identifier(); // may error out
|
|
645
629
|
// normalize underscores to hyphens
|
|
646
|
-
|
|
630
|
+
sass::string name(Util::normalize_underscores(lexed));
|
|
647
631
|
// create the initial mixin call object
|
|
648
|
-
Mixin_Call_Obj call = SASS_MEMORY_NEW(Mixin_Call, pstate, name,
|
|
632
|
+
Mixin_Call_Obj call = SASS_MEMORY_NEW(Mixin_Call, pstate, name, Arguments_Obj{});
|
|
649
633
|
// parse mandatory arguments
|
|
650
634
|
call->arguments(parse_arguments());
|
|
635
|
+
// parse using and optional block parameters
|
|
636
|
+
bool has_parameters = lex< kwd_using >() != nullptr;
|
|
637
|
+
|
|
638
|
+
if (has_parameters) {
|
|
639
|
+
if (!peek< exactly<'('> >()) css_error("Invalid CSS", " after ", ": expected \"(\", was ");
|
|
640
|
+
} else {
|
|
641
|
+
if (peek< exactly<'('> >()) css_error("Invalid CSS", " after ", ": expected \";\", was ");
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
if (has_parameters) call->block_parameters(parse_parameters());
|
|
645
|
+
|
|
651
646
|
// parse optional block
|
|
652
647
|
if (peek < exactly <'{'> >()) {
|
|
653
648
|
call->block(parse_block());
|
|
654
649
|
}
|
|
650
|
+
else if (has_parameters) {
|
|
651
|
+
css_error("Invalid CSS", " after ", ": expected \"{\", was ");
|
|
652
|
+
}
|
|
655
653
|
// return ast node
|
|
656
654
|
return call.detach();
|
|
657
655
|
}
|
|
658
656
|
// EO parse_include_directive
|
|
659
657
|
|
|
660
|
-
// parse a list of complex selectors
|
|
661
|
-
// this is the main entry point for most
|
|
662
|
-
Selector_List_Obj Parser::parse_selector_list(bool chroot)
|
|
663
|
-
{
|
|
664
|
-
bool reloop;
|
|
665
|
-
bool had_linefeed = false;
|
|
666
|
-
NESTING_GUARD(nestings);
|
|
667
|
-
Complex_Selector_Obj sel;
|
|
668
|
-
Selector_List_Obj group = SASS_MEMORY_NEW(Selector_List, pstate);
|
|
669
|
-
group->media_block(last_media_block);
|
|
670
|
-
|
|
671
|
-
if (peek_css< alternatives < end_of_file, exactly <'{'>, exactly <','> > >()) {
|
|
672
|
-
css_error("Invalid CSS", " after ", ": expected selector, was ");
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
do {
|
|
676
|
-
reloop = false;
|
|
677
|
-
|
|
678
|
-
had_linefeed = had_linefeed || peek_newline();
|
|
679
|
-
|
|
680
|
-
if (peek_css< alternatives < class_char < selector_list_delims > > >())
|
|
681
|
-
break; // in case there are superfluous commas at the end
|
|
682
|
-
|
|
683
|
-
// now parse the complex selector
|
|
684
|
-
sel = parse_complex_selector(chroot);
|
|
685
|
-
|
|
686
|
-
if (!sel) return group.detach();
|
|
687
|
-
|
|
688
|
-
sel->has_line_feed(had_linefeed);
|
|
689
658
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
while (peek_css< exactly<','> >())
|
|
693
|
-
{
|
|
694
|
-
lex< css_comments >(false);
|
|
695
|
-
// consume everything up and including the comma separator
|
|
696
|
-
reloop = lex< exactly<','> >() != 0;
|
|
697
|
-
// remember line break (also between some commas)
|
|
698
|
-
had_linefeed = had_linefeed || peek_newline();
|
|
699
|
-
// remember line break (also between some commas)
|
|
700
|
-
}
|
|
701
|
-
group->append(sel);
|
|
702
|
-
}
|
|
703
|
-
while (reloop);
|
|
704
|
-
while (lex_css< kwd_optional >()) {
|
|
705
|
-
group->is_optional(true);
|
|
706
|
-
}
|
|
707
|
-
// update for end position
|
|
708
|
-
group->update_pstate(pstate);
|
|
709
|
-
if (sel) sel->last()->has_line_break(false);
|
|
710
|
-
return group.detach();
|
|
711
|
-
}
|
|
712
|
-
// EO parse_selector_list
|
|
713
|
-
|
|
714
|
-
// a complex selector combines a compound selector with another
|
|
715
|
-
// complex selector, with one of four combinator operations.
|
|
716
|
-
// the compound selector (head) is optional, since the combinator
|
|
717
|
-
// can come first in the whole selector sequence (like `> DIV').
|
|
718
|
-
Complex_Selector_Obj Parser::parse_complex_selector(bool chroot)
|
|
719
|
-
{
|
|
720
|
-
|
|
721
|
-
NESTING_GUARD(nestings);
|
|
722
|
-
String_Obj reference = 0;
|
|
723
|
-
lex < block_comment >();
|
|
724
|
-
advanceToNextToken();
|
|
725
|
-
Complex_Selector_Obj sel = SASS_MEMORY_NEW(Complex_Selector, pstate);
|
|
726
|
-
|
|
727
|
-
if (peek < end_of_file >()) return 0;
|
|
728
|
-
|
|
729
|
-
// parse the left hand side
|
|
730
|
-
Compound_Selector_Obj lhs;
|
|
731
|
-
// special case if it starts with combinator ([+~>])
|
|
732
|
-
if (!peek_css< class_char < selector_combinator_ops > >()) {
|
|
733
|
-
// parse the left hand side
|
|
734
|
-
lhs = parse_compound_selector();
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
// parse combinator between lhs and rhs
|
|
739
|
-
Complex_Selector::Combinator combinator = Complex_Selector::ANCESTOR_OF;
|
|
740
|
-
if (lex< exactly<'+'> >()) combinator = Complex_Selector::ADJACENT_TO;
|
|
741
|
-
else if (lex< exactly<'~'> >()) combinator = Complex_Selector::PRECEDES;
|
|
742
|
-
else if (lex< exactly<'>'> >()) combinator = Complex_Selector::PARENT_OF;
|
|
743
|
-
else if (lex< sequence < exactly<'/'>, negate < exactly < '*' > > > >()) {
|
|
744
|
-
// comments are allowed, but not spaces?
|
|
745
|
-
combinator = Complex_Selector::REFERENCE;
|
|
746
|
-
if (!lex < re_reference_combinator >()) return 0;
|
|
747
|
-
reference = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
|
|
748
|
-
if (!lex < exactly < '/' > >()) return 0; // ToDo: error msg?
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
if (!lhs && combinator == Complex_Selector::ANCESTOR_OF) return 0;
|
|
752
|
-
|
|
753
|
-
// lex < block_comment >();
|
|
754
|
-
sel->head(lhs);
|
|
755
|
-
sel->combinator(combinator);
|
|
756
|
-
sel->media_block(last_media_block);
|
|
757
|
-
|
|
758
|
-
if (combinator == Complex_Selector::REFERENCE) sel->reference(reference);
|
|
759
|
-
// has linfeed after combinator?
|
|
760
|
-
sel->has_line_break(peek_newline());
|
|
761
|
-
// sel->has_line_feed(has_line_feed);
|
|
762
|
-
|
|
763
|
-
// check if we got the abort condition (ToDo: optimize)
|
|
764
|
-
if (!peek_css< class_char < complex_selector_delims > >()) {
|
|
765
|
-
// parse next selector in sequence
|
|
766
|
-
sel->tail(parse_complex_selector(true));
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
// add a parent selector if we are not in a root
|
|
770
|
-
// also skip adding parent ref if we only have refs
|
|
771
|
-
if (!sel->has_parent_ref() && !chroot) {
|
|
772
|
-
// create the objects to wrap parent selector reference
|
|
773
|
-
Compound_Selector_Obj head = SASS_MEMORY_NEW(Compound_Selector, pstate);
|
|
774
|
-
Parent_Selector_Ptr parent = SASS_MEMORY_NEW(Parent_Selector, pstate, false);
|
|
775
|
-
parent->media_block(last_media_block);
|
|
776
|
-
head->media_block(last_media_block);
|
|
777
|
-
// add simple selector
|
|
778
|
-
head->append(parent);
|
|
779
|
-
// selector may not have any head yet
|
|
780
|
-
if (!sel->head()) { sel->head(head); }
|
|
781
|
-
// otherwise we need to create a new complex selector and set the old one as its tail
|
|
782
|
-
else {
|
|
783
|
-
sel = SASS_MEMORY_NEW(Complex_Selector, pstate, Complex_Selector::ANCESTOR_OF, head, sel);
|
|
784
|
-
sel->media_block(last_media_block);
|
|
785
|
-
}
|
|
786
|
-
// peek for linefeed and remember result on head
|
|
787
|
-
// if (peek_newline()) head->has_line_break(true);
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
sel->update_pstate(pstate);
|
|
791
|
-
// complex selector
|
|
792
|
-
return sel;
|
|
793
|
-
}
|
|
794
|
-
// EO parse_complex_selector
|
|
795
|
-
|
|
796
|
-
// parse one compound selector, which is basically
|
|
797
|
-
// a list of simple selectors (directly adjacent)
|
|
798
|
-
// lex them exactly (without skipping white-space)
|
|
799
|
-
Compound_Selector_Obj Parser::parse_compound_selector()
|
|
800
|
-
{
|
|
801
|
-
// init an empty compound selector wrapper
|
|
802
|
-
Compound_Selector_Obj seq = SASS_MEMORY_NEW(Compound_Selector, pstate);
|
|
803
|
-
seq->media_block(last_media_block);
|
|
804
|
-
|
|
805
|
-
// skip initial white-space
|
|
806
|
-
lex< css_whitespace >();
|
|
807
|
-
|
|
808
|
-
// parse list
|
|
809
|
-
while (true)
|
|
810
|
-
{
|
|
811
|
-
// remove all block comments (don't skip white-space)
|
|
812
|
-
lex< delimited_by< slash_star, star_slash, false > >(false);
|
|
813
|
-
// parse functional
|
|
814
|
-
if (match < re_pseudo_selector >())
|
|
815
|
-
{
|
|
816
|
-
seq->append(parse_simple_selector());
|
|
817
|
-
}
|
|
818
|
-
// parse parent selector
|
|
819
|
-
else if (lex< exactly<'&'> >(false))
|
|
820
|
-
{
|
|
821
|
-
// this produces a linefeed!?
|
|
822
|
-
seq->has_parent_reference(true);
|
|
823
|
-
seq->append(SASS_MEMORY_NEW(Parent_Selector, pstate));
|
|
824
|
-
// parent selector only allowed at start
|
|
825
|
-
// upcoming Sass may allow also trailing
|
|
826
|
-
if (seq->length() > 1) {
|
|
827
|
-
ParserState state(pstate);
|
|
828
|
-
Simple_Selector_Obj cur = (*seq)[seq->length()-1];
|
|
829
|
-
Simple_Selector_Obj prev = (*seq)[seq->length()-2];
|
|
830
|
-
std::string sel(prev->to_string({ NESTED, 5 }));
|
|
831
|
-
std::string found(cur->to_string({ NESTED, 5 }));
|
|
832
|
-
if (lex < identifier >()) { found += std::string(lexed); }
|
|
833
|
-
error("Invalid CSS after \"" + sel + "\": expected \"{\", was \"" + found + "\"\n\n"
|
|
834
|
-
"\"" + found + "\" may only be used at the beginning of a compound selector.", state);
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
// parse type selector
|
|
838
|
-
else if (lex< re_type_selector >(false))
|
|
839
|
-
{
|
|
840
|
-
seq->append(SASS_MEMORY_NEW(Element_Selector, pstate, lexed));
|
|
841
|
-
}
|
|
842
|
-
// peek for abort conditions
|
|
843
|
-
else if (peek< spaces >()) break;
|
|
844
|
-
else if (peek< end_of_file >()) { break; }
|
|
845
|
-
else if (peek_css < class_char < selector_combinator_ops > >()) break;
|
|
846
|
-
else if (peek_css < class_char < complex_selector_delims > >()) break;
|
|
847
|
-
// otherwise parse another simple selector
|
|
848
|
-
else {
|
|
849
|
-
Simple_Selector_Obj sel = parse_simple_selector();
|
|
850
|
-
if (!sel) return 0;
|
|
851
|
-
seq->append(sel);
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
if (seq && !peek_css<alternatives<end_of_file,exactly<'{'>>>()) {
|
|
856
|
-
seq->has_line_break(peek_newline());
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
// EO while true
|
|
860
|
-
return seq;
|
|
861
|
-
|
|
862
|
-
}
|
|
863
|
-
// EO parse_compound_selector
|
|
864
|
-
|
|
865
|
-
Simple_Selector_Obj Parser::parse_simple_selector()
|
|
659
|
+
SimpleSelectorObj Parser::parse_simple_selector()
|
|
866
660
|
{
|
|
867
661
|
lex < css_comments >(false);
|
|
868
662
|
if (lex< class_name >()) {
|
|
869
|
-
return SASS_MEMORY_NEW(
|
|
663
|
+
return SASS_MEMORY_NEW(ClassSelector, pstate, lexed);
|
|
870
664
|
}
|
|
871
665
|
else if (lex< id_name >()) {
|
|
872
|
-
return SASS_MEMORY_NEW(
|
|
666
|
+
return SASS_MEMORY_NEW(IDSelector, pstate, lexed);
|
|
873
667
|
}
|
|
874
668
|
else if (lex< alternatives < variable, number, static_reference_combinator > >()) {
|
|
875
|
-
return SASS_MEMORY_NEW(
|
|
669
|
+
return SASS_MEMORY_NEW(TypeSelector, pstate, lexed);
|
|
876
670
|
}
|
|
877
671
|
else if (peek< pseudo_not >()) {
|
|
878
|
-
return
|
|
672
|
+
return parse_negated_selector2();
|
|
879
673
|
}
|
|
880
674
|
else if (peek< re_pseudo_selector >()) {
|
|
881
675
|
return parse_pseudo_selector();
|
|
@@ -887,86 +681,117 @@ namespace Sass {
|
|
|
887
681
|
return parse_attribute_selector();
|
|
888
682
|
}
|
|
889
683
|
else if (lex< placeholder >()) {
|
|
890
|
-
|
|
891
|
-
sel->media_block(last_media_block);
|
|
892
|
-
return sel;
|
|
684
|
+
return SASS_MEMORY_NEW(PlaceholderSelector, pstate, lexed);
|
|
893
685
|
}
|
|
894
686
|
else {
|
|
895
687
|
css_error("Invalid CSS", " after ", ": expected selector, was ");
|
|
896
688
|
}
|
|
897
689
|
// failed
|
|
898
|
-
return
|
|
690
|
+
return {};
|
|
899
691
|
}
|
|
900
692
|
|
|
901
|
-
|
|
693
|
+
PseudoSelectorObj Parser::parse_negated_selector2()
|
|
902
694
|
{
|
|
903
695
|
lex< pseudo_not >();
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
696
|
+
sass::string name(lexed);
|
|
697
|
+
SourceSpan nsource_position = pstate;
|
|
698
|
+
SelectorListObj negated = parseSelectorList(true);
|
|
907
699
|
if (!lex< exactly<')'> >()) {
|
|
908
700
|
error("negated selector is missing ')'");
|
|
909
701
|
}
|
|
910
702
|
name.erase(name.size() - 1);
|
|
911
|
-
|
|
703
|
+
|
|
704
|
+
PseudoSelector* sel = SASS_MEMORY_NEW(PseudoSelector, nsource_position, name.substr(1));
|
|
705
|
+
sel->selector(negated);
|
|
706
|
+
return sel;
|
|
912
707
|
}
|
|
913
708
|
|
|
709
|
+
// Helper to clean binominal string
|
|
710
|
+
bool BothAreSpaces(char lhs, char rhs) { return isspace(lhs) && isspace(rhs); }
|
|
711
|
+
|
|
914
712
|
// a pseudo selector often starts with one or two colons
|
|
915
713
|
// it can contain more selectors inside parentheses
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
714
|
+
SimpleSelectorObj Parser::parse_pseudo_selector() {
|
|
715
|
+
|
|
716
|
+
// Lex one or two colon characters
|
|
717
|
+
if (lex<pseudo_prefix>()) {
|
|
718
|
+
sass::string colons(lexed);
|
|
719
|
+
// Check if it is a pseudo element
|
|
720
|
+
bool element = colons.size() == 2;
|
|
721
|
+
|
|
722
|
+
if (lex< sequence<
|
|
723
|
+
// we keep the space within the name, strange enough
|
|
724
|
+
// ToDo: refactor output to schedule the space for it
|
|
725
|
+
// or do we really want to keep the real white-space?
|
|
726
|
+
sequence< identifier, optional < block_comment >, exactly<'('> >
|
|
727
|
+
> >())
|
|
728
|
+
{
|
|
929
729
|
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
return SASS_MEMORY_NEW(Pseudo_Selector, p, name, expr);
|
|
730
|
+
sass::string name(lexed);
|
|
731
|
+
name.erase(name.size() - 1);
|
|
732
|
+
SourceSpan p = pstate;
|
|
733
|
+
|
|
734
|
+
// specially parse nth-child pseudo selectors
|
|
735
|
+
if (lex_css < sequence < binomial, word_boundary >>()) {
|
|
736
|
+
sass::string parsed(lexed); // always compacting binominals (as dart-sass)
|
|
737
|
+
parsed.erase(std::unique(parsed.begin(), parsed.end(), BothAreSpaces), parsed.end());
|
|
738
|
+
String_Constant_Obj arg = SASS_MEMORY_NEW(String_Constant, pstate, parsed);
|
|
739
|
+
PseudoSelector* pseudo = SASS_MEMORY_NEW(PseudoSelector, p, name, element);
|
|
740
|
+
if (lex < sequence < css_whitespace, insensitive < of_kwd >>>(false)) {
|
|
741
|
+
pseudo->selector(parseSelectorList(true));
|
|
742
|
+
}
|
|
743
|
+
pseudo->argument(arg);
|
|
744
|
+
if (lex_css< exactly<')'> >()) {
|
|
745
|
+
return pseudo;
|
|
746
|
+
}
|
|
948
747
|
}
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
748
|
+
else {
|
|
749
|
+
if (peek_css< exactly<')'>>() && Util::equalsLiteral("nth-", name.substr(0, 4))) {
|
|
750
|
+
css_error("Invalid CSS", " after ", ": expected An+B expression, was ");
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
sass::string unvendored = Util::unvendor(name);
|
|
754
|
+
|
|
755
|
+
if (unvendored == "not" || unvendored == "matches" || unvendored == "current" || unvendored == "any" || unvendored == "has" || unvendored == "host" || unvendored == "host-context" || unvendored == "slotted") {
|
|
756
|
+
if (SelectorListObj wrapped = parseSelectorList(true)) {
|
|
757
|
+
if (wrapped && lex_css< exactly<')'> >()) {
|
|
758
|
+
PseudoSelector* pseudo = SASS_MEMORY_NEW(PseudoSelector, p, name, element);
|
|
759
|
+
pseudo->selector(wrapped);
|
|
760
|
+
return pseudo;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
} else {
|
|
764
|
+
String_Schema_Obj arg = parse_css_variable_value();
|
|
765
|
+
PseudoSelector* pseudo = SASS_MEMORY_NEW(PseudoSelector, p, name, element);
|
|
766
|
+
pseudo->argument(arg);
|
|
767
|
+
|
|
768
|
+
if (lex_css< exactly<')'> >()) {
|
|
769
|
+
return pseudo;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
953
772
|
}
|
|
773
|
+
|
|
954
774
|
}
|
|
775
|
+
// EO if pseudo selector
|
|
955
776
|
|
|
956
|
-
|
|
957
|
-
|
|
777
|
+
else if (lex < sequence< optional < pseudo_prefix >, identifier > >()) {
|
|
778
|
+
return SASS_MEMORY_NEW(PseudoSelector, pstate, lexed, element);
|
|
779
|
+
}
|
|
780
|
+
else if (lex < pseudo_prefix >()) {
|
|
781
|
+
css_error("Invalid CSS", " after ", ": expected pseudoclass or pseudoelement, was ");
|
|
782
|
+
}
|
|
958
783
|
|
|
959
|
-
else if (lex < sequence< optional < pseudo_prefix >, identifier > >()) {
|
|
960
|
-
return SASS_MEMORY_NEW(Pseudo_Selector, pstate, lexed);
|
|
961
784
|
}
|
|
962
|
-
else
|
|
963
|
-
|
|
785
|
+
else {
|
|
786
|
+
lex < identifier >(); // needed for error message?
|
|
787
|
+
css_error("Invalid CSS", " after ", ": expected selector, was ");
|
|
964
788
|
}
|
|
965
789
|
|
|
790
|
+
|
|
966
791
|
css_error("Invalid CSS", " after ", ": expected \")\", was ");
|
|
967
792
|
|
|
968
793
|
// unreachable statement
|
|
969
|
-
return
|
|
794
|
+
return {};
|
|
970
795
|
}
|
|
971
796
|
|
|
972
797
|
const char* Parser::re_attr_sensitive_close(const char* src)
|
|
@@ -979,25 +804,25 @@ namespace Sass {
|
|
|
979
804
|
return sequence < insensitive<'i'>, re_attr_sensitive_close >(src);
|
|
980
805
|
}
|
|
981
806
|
|
|
982
|
-
|
|
807
|
+
AttributeSelectorObj Parser::parse_attribute_selector()
|
|
983
808
|
{
|
|
984
|
-
|
|
809
|
+
SourceSpan p = pstate;
|
|
985
810
|
if (!lex_css< attribute_name >()) error("invalid attribute name in attribute selector");
|
|
986
|
-
|
|
811
|
+
sass::string name(lexed);
|
|
987
812
|
if (lex_css< re_attr_sensitive_close >()) {
|
|
988
|
-
return SASS_MEMORY_NEW(
|
|
813
|
+
return SASS_MEMORY_NEW(AttributeSelector, p, name, "", String_Obj{});
|
|
989
814
|
}
|
|
990
815
|
else if (lex_css< re_attr_insensitive_close >()) {
|
|
991
816
|
char modifier = lexed.begin[0];
|
|
992
|
-
return SASS_MEMORY_NEW(
|
|
817
|
+
return SASS_MEMORY_NEW(AttributeSelector, p, name, "", String_Obj{}, modifier);
|
|
993
818
|
}
|
|
994
819
|
if (!lex_css< alternatives< exact_match, class_match, dash_match,
|
|
995
820
|
prefix_match, suffix_match, substring_match > >()) {
|
|
996
821
|
error("invalid operator in attribute selector for " + name);
|
|
997
822
|
}
|
|
998
|
-
|
|
823
|
+
sass::string matcher(lexed);
|
|
999
824
|
|
|
1000
|
-
String_Obj value
|
|
825
|
+
String_Obj value;
|
|
1001
826
|
if (lex_css< identifier >()) {
|
|
1002
827
|
value = SASS_MEMORY_NEW(String_Constant, p, lexed);
|
|
1003
828
|
}
|
|
@@ -1009,18 +834,18 @@ namespace Sass {
|
|
|
1009
834
|
}
|
|
1010
835
|
|
|
1011
836
|
if (lex_css< re_attr_sensitive_close >()) {
|
|
1012
|
-
return SASS_MEMORY_NEW(
|
|
837
|
+
return SASS_MEMORY_NEW(AttributeSelector, p, name, matcher, value, 0);
|
|
1013
838
|
}
|
|
1014
839
|
else if (lex_css< re_attr_insensitive_close >()) {
|
|
1015
840
|
char modifier = lexed.begin[0];
|
|
1016
|
-
return SASS_MEMORY_NEW(
|
|
841
|
+
return SASS_MEMORY_NEW(AttributeSelector, p, name, matcher, value, modifier);
|
|
1017
842
|
}
|
|
1018
843
|
error("unterminated attribute selector for " + name);
|
|
1019
|
-
return
|
|
844
|
+
return {}; // to satisfy compilers (error must not return)
|
|
1020
845
|
}
|
|
1021
846
|
|
|
1022
847
|
/* parse block comment and add to block */
|
|
1023
|
-
void Parser::parse_block_comments()
|
|
848
|
+
void Parser::parse_block_comments(bool store)
|
|
1024
849
|
{
|
|
1025
850
|
Block_Obj block = block_stack.back();
|
|
1026
851
|
|
|
@@ -1028,7 +853,7 @@ namespace Sass {
|
|
|
1028
853
|
bool is_important = lexed.begin[2] == '!';
|
|
1029
854
|
// flag on second param is to skip loosely over comments
|
|
1030
855
|
String_Obj contents = parse_interpolated_chunk(lexed, true, false);
|
|
1031
|
-
block->append(SASS_MEMORY_NEW(Comment, pstate, contents, is_important));
|
|
856
|
+
if (store) block->append(SASS_MEMORY_NEW(Comment, pstate, contents, is_important));
|
|
1032
857
|
}
|
|
1033
858
|
}
|
|
1034
859
|
|
|
@@ -1036,12 +861,12 @@ namespace Sass {
|
|
|
1036
861
|
String_Obj prop;
|
|
1037
862
|
bool is_custom_property = false;
|
|
1038
863
|
if (lex< sequence< optional< exactly<'*'> >, identifier_schema > >()) {
|
|
1039
|
-
const
|
|
864
|
+
const sass::string property(lexed);
|
|
1040
865
|
is_custom_property = property.compare(0, 2, "--") == 0;
|
|
1041
866
|
prop = parse_identifier_schema();
|
|
1042
867
|
}
|
|
1043
868
|
else if (lex< sequence< optional< exactly<'*'> >, identifier, zero_plus< block_comment > > >()) {
|
|
1044
|
-
const
|
|
869
|
+
const sass::string property(lexed);
|
|
1045
870
|
is_custom_property = property.compare(0, 2, "--") == 0;
|
|
1046
871
|
prop = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
|
|
1047
872
|
}
|
|
@@ -1049,7 +874,7 @@ namespace Sass {
|
|
|
1049
874
|
css_error("Invalid CSS", " after ", ": expected \"}\", was ");
|
|
1050
875
|
}
|
|
1051
876
|
bool is_indented = true;
|
|
1052
|
-
const
|
|
877
|
+
const sass::string property(lexed);
|
|
1053
878
|
if (!lex_css< one_plus< exactly<':'> > >()) error("property \"" + escape_string(property) + "\" must be followed by a ':'");
|
|
1054
879
|
if (!is_custom_property && match< sequence< optional_css_comments, exactly<';'> > >()) error("style declaration must contain a value");
|
|
1055
880
|
if (match< sequence< optional_css_comments, exactly<'{'> > >()) is_indented = false; // don't indent if value is empty
|
|
@@ -1061,7 +886,7 @@ namespace Sass {
|
|
|
1061
886
|
return SASS_MEMORY_NEW(Declaration, prop->pstate(), prop, parse_static_value()/*, lex<kwd_important>()*/);
|
|
1062
887
|
}
|
|
1063
888
|
else {
|
|
1064
|
-
|
|
889
|
+
ExpressionObj value;
|
|
1065
890
|
Lookahead lookahead = lookahead_for_value(position);
|
|
1066
891
|
if (lookahead.found) {
|
|
1067
892
|
if (lookahead.has_interpolants) {
|
|
@@ -1072,7 +897,7 @@ namespace Sass {
|
|
|
1072
897
|
}
|
|
1073
898
|
else {
|
|
1074
899
|
value = parse_list(DELAYED);
|
|
1075
|
-
if (
|
|
900
|
+
if (List* list = Cast<List>(value)) {
|
|
1076
901
|
if (!list->is_bracketed() && list->length() == 0 && !peek< exactly <'{'> >()) {
|
|
1077
902
|
css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
|
|
1078
903
|
}
|
|
@@ -1086,27 +911,10 @@ namespace Sass {
|
|
|
1086
911
|
}
|
|
1087
912
|
}
|
|
1088
913
|
|
|
1089
|
-
|
|
1090
|
-
// this is never hit via spec tests
|
|
1091
|
-
bool Parser::parse_number_prefix()
|
|
1092
|
-
{
|
|
1093
|
-
bool positive = true;
|
|
1094
|
-
while(true) {
|
|
1095
|
-
if (lex < block_comment >()) continue;
|
|
1096
|
-
if (lex < number_prefix >()) continue;
|
|
1097
|
-
if (lex < exactly < '-' > >()) {
|
|
1098
|
-
positive = !positive;
|
|
1099
|
-
continue;
|
|
1100
|
-
}
|
|
1101
|
-
break;
|
|
1102
|
-
}
|
|
1103
|
-
return positive;
|
|
1104
|
-
}
|
|
1105
|
-
|
|
1106
|
-
Expression_Obj Parser::parse_map()
|
|
914
|
+
ExpressionObj Parser::parse_map()
|
|
1107
915
|
{
|
|
1108
916
|
NESTING_GUARD(nestings);
|
|
1109
|
-
|
|
917
|
+
ExpressionObj key = parse_list();
|
|
1110
918
|
List_Obj map = SASS_MEMORY_NEW(List, pstate, 0, SASS_HASH);
|
|
1111
919
|
|
|
1112
920
|
// it's not a map so return the lexed value as a list value
|
|
@@ -1118,7 +926,7 @@ namespace Sass {
|
|
|
1118
926
|
css_error("Invalid CSS", " after ", ": expected \")\", was ");
|
|
1119
927
|
}
|
|
1120
928
|
|
|
1121
|
-
|
|
929
|
+
ExpressionObj value = parse_space_list();
|
|
1122
930
|
|
|
1123
931
|
map->append(key);
|
|
1124
932
|
map->append(value);
|
|
@@ -1140,14 +948,14 @@ namespace Sass {
|
|
|
1140
948
|
map->append(value);
|
|
1141
949
|
}
|
|
1142
950
|
|
|
1143
|
-
|
|
1144
|
-
ps.offset = pstate - ps + pstate.offset;
|
|
951
|
+
SourceSpan ps = map->pstate();
|
|
952
|
+
ps.offset = pstate.position - ps.position + pstate.offset;
|
|
1145
953
|
map->pstate(ps);
|
|
1146
954
|
|
|
1147
955
|
return map;
|
|
1148
956
|
}
|
|
1149
957
|
|
|
1150
|
-
|
|
958
|
+
ExpressionObj Parser::parse_bracket_list()
|
|
1151
959
|
{
|
|
1152
960
|
NESTING_GUARD(nestings);
|
|
1153
961
|
// check if we have an empty list
|
|
@@ -1161,7 +969,7 @@ namespace Sass {
|
|
|
1161
969
|
bool has_paren = peek_css< exactly<'('> >() != NULL;
|
|
1162
970
|
|
|
1163
971
|
// now try to parse a space list
|
|
1164
|
-
|
|
972
|
+
ExpressionObj list = parse_space_list();
|
|
1165
973
|
// if it's a singleton, return it (don't wrap it)
|
|
1166
974
|
if (!peek_css< exactly<','> >(position)) {
|
|
1167
975
|
List_Obj l = Cast<List>(list);
|
|
@@ -1194,14 +1002,14 @@ namespace Sass {
|
|
|
1194
1002
|
// parse list returns either a space separated list,
|
|
1195
1003
|
// a comma separated list or any bare expression found.
|
|
1196
1004
|
// so to speak: we unwrap items from lists if possible here!
|
|
1197
|
-
|
|
1005
|
+
ExpressionObj Parser::parse_list(bool delayed)
|
|
1198
1006
|
{
|
|
1199
1007
|
NESTING_GUARD(nestings);
|
|
1200
1008
|
return parse_comma_list(delayed);
|
|
1201
1009
|
}
|
|
1202
1010
|
|
|
1203
1011
|
// will return singletons unwrapped
|
|
1204
|
-
|
|
1012
|
+
ExpressionObj Parser::parse_comma_list(bool delayed)
|
|
1205
1013
|
{
|
|
1206
1014
|
NESTING_GUARD(nestings);
|
|
1207
1015
|
// check if we have an empty list
|
|
@@ -1213,7 +1021,7 @@ namespace Sass {
|
|
|
1213
1021
|
}
|
|
1214
1022
|
|
|
1215
1023
|
// now try to parse a space list
|
|
1216
|
-
|
|
1024
|
+
ExpressionObj list = parse_space_list();
|
|
1217
1025
|
// if it's a singleton, return it (don't wrap it)
|
|
1218
1026
|
if (!peek_css< exactly<','> >(position)) {
|
|
1219
1027
|
// set_delay doesn't apply to list children
|
|
@@ -1241,10 +1049,10 @@ namespace Sass {
|
|
|
1241
1049
|
// EO parse_comma_list
|
|
1242
1050
|
|
|
1243
1051
|
// will return singletons unwrapped
|
|
1244
|
-
|
|
1052
|
+
ExpressionObj Parser::parse_space_list()
|
|
1245
1053
|
{
|
|
1246
1054
|
NESTING_GUARD(nestings);
|
|
1247
|
-
|
|
1055
|
+
ExpressionObj disj1 = parse_disjunction();
|
|
1248
1056
|
// if it's a singleton, return it (don't wrap it)
|
|
1249
1057
|
if (peek_css< space_list_terminator >(position)
|
|
1250
1058
|
) {
|
|
@@ -1266,60 +1074,60 @@ namespace Sass {
|
|
|
1266
1074
|
// EO parse_space_list
|
|
1267
1075
|
|
|
1268
1076
|
// parse logical OR operation
|
|
1269
|
-
|
|
1077
|
+
ExpressionObj Parser::parse_disjunction()
|
|
1270
1078
|
{
|
|
1271
1079
|
NESTING_GUARD(nestings);
|
|
1272
1080
|
advanceToNextToken();
|
|
1273
|
-
|
|
1081
|
+
SourceSpan state(pstate);
|
|
1274
1082
|
// parse the left hand side conjunction
|
|
1275
|
-
|
|
1083
|
+
ExpressionObj conj = parse_conjunction();
|
|
1276
1084
|
// parse multiple right hand sides
|
|
1277
|
-
|
|
1085
|
+
sass::vector<ExpressionObj> operands;
|
|
1278
1086
|
while (lex_css< kwd_or >())
|
|
1279
1087
|
operands.push_back(parse_conjunction());
|
|
1280
1088
|
// if it's a singleton, return it directly
|
|
1281
1089
|
if (operands.size() == 0) return conj;
|
|
1282
1090
|
// fold all operands into one binary expression
|
|
1283
|
-
|
|
1284
|
-
state.offset = pstate - state + pstate.offset;
|
|
1091
|
+
ExpressionObj ex = fold_operands(conj, operands, { Sass_OP::OR });
|
|
1092
|
+
state.offset = pstate.position - state.position + pstate.offset;
|
|
1285
1093
|
ex->pstate(state);
|
|
1286
1094
|
return ex;
|
|
1287
1095
|
}
|
|
1288
1096
|
// EO parse_disjunction
|
|
1289
1097
|
|
|
1290
1098
|
// parse logical AND operation
|
|
1291
|
-
|
|
1099
|
+
ExpressionObj Parser::parse_conjunction()
|
|
1292
1100
|
{
|
|
1293
1101
|
NESTING_GUARD(nestings);
|
|
1294
1102
|
advanceToNextToken();
|
|
1295
|
-
|
|
1103
|
+
SourceSpan state(pstate);
|
|
1296
1104
|
// parse the left hand side relation
|
|
1297
|
-
|
|
1105
|
+
ExpressionObj rel = parse_relation();
|
|
1298
1106
|
// parse multiple right hand sides
|
|
1299
|
-
|
|
1107
|
+
sass::vector<ExpressionObj> operands;
|
|
1300
1108
|
while (lex_css< kwd_and >()) {
|
|
1301
1109
|
operands.push_back(parse_relation());
|
|
1302
1110
|
}
|
|
1303
1111
|
// if it's a singleton, return it directly
|
|
1304
1112
|
if (operands.size() == 0) return rel;
|
|
1305
1113
|
// fold all operands into one binary expression
|
|
1306
|
-
|
|
1307
|
-
state.offset = pstate - state + pstate.offset;
|
|
1114
|
+
ExpressionObj ex = fold_operands(rel, operands, { Sass_OP::AND });
|
|
1115
|
+
state.offset = pstate.position - state.position + pstate.offset;
|
|
1308
1116
|
ex->pstate(state);
|
|
1309
1117
|
return ex;
|
|
1310
1118
|
}
|
|
1311
1119
|
// EO parse_conjunction
|
|
1312
1120
|
|
|
1313
1121
|
// parse comparison operations
|
|
1314
|
-
|
|
1122
|
+
ExpressionObj Parser::parse_relation()
|
|
1315
1123
|
{
|
|
1316
1124
|
NESTING_GUARD(nestings);
|
|
1317
1125
|
advanceToNextToken();
|
|
1318
|
-
|
|
1126
|
+
SourceSpan state(pstate);
|
|
1319
1127
|
// parse the left hand side expression
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1128
|
+
ExpressionObj lhs = parse_expression();
|
|
1129
|
+
sass::vector<ExpressionObj> operands;
|
|
1130
|
+
sass::vector<Operand> operators;
|
|
1323
1131
|
// if it's a singleton, return it (don't wrap it)
|
|
1324
1132
|
while (peek< alternatives <
|
|
1325
1133
|
kwd_eq,
|
|
@@ -1352,8 +1160,8 @@ namespace Sass {
|
|
|
1352
1160
|
// correctly set to zero. After folding we also unwrap
|
|
1353
1161
|
// single nested items. So we cannot set delay on the
|
|
1354
1162
|
// returned result here, as we have lost nestings ...
|
|
1355
|
-
|
|
1356
|
-
state.offset = pstate - state + pstate.offset;
|
|
1163
|
+
ExpressionObj ex = fold_operands(lhs, operands, operators);
|
|
1164
|
+
state.offset = pstate.position - state.position + pstate.offset;
|
|
1357
1165
|
ex->pstate(state);
|
|
1358
1166
|
return ex;
|
|
1359
1167
|
}
|
|
@@ -1364,25 +1172,25 @@ namespace Sass {
|
|
|
1364
1172
|
// called from parse_for_directive
|
|
1365
1173
|
// called from parse_media_expression
|
|
1366
1174
|
// parse addition and subtraction operations
|
|
1367
|
-
|
|
1175
|
+
ExpressionObj Parser::parse_expression()
|
|
1368
1176
|
{
|
|
1369
1177
|
NESTING_GUARD(nestings);
|
|
1370
1178
|
advanceToNextToken();
|
|
1371
|
-
|
|
1179
|
+
SourceSpan state(pstate);
|
|
1372
1180
|
// parses multiple add and subtract operations
|
|
1373
1181
|
// NOTE: make sure that identifiers starting with
|
|
1374
1182
|
// NOTE: dashes do NOT count as subtract operation
|
|
1375
|
-
|
|
1183
|
+
ExpressionObj lhs = parse_operators();
|
|
1376
1184
|
// if it's a singleton, return it (don't wrap it)
|
|
1377
1185
|
if (!(peek_css< exactly<'+'> >(position) ||
|
|
1378
|
-
// condition is a bit
|
|
1186
|
+
// condition is a bit mysterious, but some combinations should not be counted as operations
|
|
1379
1187
|
(peek< no_spaces >(position) && peek< sequence< negate< unsigned_number >, exactly<'-'>, negate< space > > >(position)) ||
|
|
1380
1188
|
(peek< sequence< negate< unsigned_number >, exactly<'-'>, negate< unsigned_number > > >(position))) ||
|
|
1381
1189
|
peek< sequence < zero_plus < exactly <'-' > >, identifier > >(position))
|
|
1382
1190
|
{ return lhs; }
|
|
1383
1191
|
|
|
1384
|
-
|
|
1385
|
-
|
|
1192
|
+
sass::vector<ExpressionObj> operands;
|
|
1193
|
+
sass::vector<Operand> operators;
|
|
1386
1194
|
bool left_ws = peek < css_comments >() != NULL;
|
|
1387
1195
|
while (
|
|
1388
1196
|
lex_css< exactly<'+'> >() ||
|
|
@@ -1401,22 +1209,22 @@ namespace Sass {
|
|
|
1401
1209
|
}
|
|
1402
1210
|
|
|
1403
1211
|
if (operands.size() == 0) return lhs;
|
|
1404
|
-
|
|
1405
|
-
state.offset = pstate - state + pstate.offset;
|
|
1212
|
+
ExpressionObj ex = fold_operands(lhs, operands, operators);
|
|
1213
|
+
state.offset = pstate.position - state.position + pstate.offset;
|
|
1406
1214
|
ex->pstate(state);
|
|
1407
1215
|
return ex;
|
|
1408
1216
|
}
|
|
1409
1217
|
|
|
1410
1218
|
// parse addition and subtraction operations
|
|
1411
|
-
|
|
1219
|
+
ExpressionObj Parser::parse_operators()
|
|
1412
1220
|
{
|
|
1413
1221
|
NESTING_GUARD(nestings);
|
|
1414
1222
|
advanceToNextToken();
|
|
1415
|
-
|
|
1416
|
-
|
|
1223
|
+
SourceSpan state(pstate);
|
|
1224
|
+
ExpressionObj factor = parse_factor();
|
|
1417
1225
|
// if it's a singleton, return it (don't wrap it)
|
|
1418
|
-
|
|
1419
|
-
|
|
1226
|
+
sass::vector<ExpressionObj> operands; // factors
|
|
1227
|
+
sass::vector<Operand> operators; // ops
|
|
1420
1228
|
// lex operations to apply to lhs
|
|
1421
1229
|
const char* left_ws = peek < css_comments >();
|
|
1422
1230
|
while (lex_css< class_char< static_ops > >()) {
|
|
@@ -1431,8 +1239,8 @@ namespace Sass {
|
|
|
1431
1239
|
left_ws = peek < css_comments >();
|
|
1432
1240
|
}
|
|
1433
1241
|
// operands and operators to binary expression
|
|
1434
|
-
|
|
1435
|
-
state.offset = pstate - state + pstate.offset;
|
|
1242
|
+
ExpressionObj ex = fold_operands(factor, operands, operators);
|
|
1243
|
+
state.offset = pstate.position - state.position + pstate.offset;
|
|
1436
1244
|
ex->pstate(state);
|
|
1437
1245
|
return ex;
|
|
1438
1246
|
}
|
|
@@ -1441,13 +1249,13 @@ namespace Sass {
|
|
|
1441
1249
|
|
|
1442
1250
|
// called from parse_operators
|
|
1443
1251
|
// called from parse_value_schema
|
|
1444
|
-
|
|
1252
|
+
ExpressionObj Parser::parse_factor()
|
|
1445
1253
|
{
|
|
1446
1254
|
NESTING_GUARD(nestings);
|
|
1447
1255
|
lex < css_comments >(false);
|
|
1448
1256
|
if (lex_css< exactly<'('> >()) {
|
|
1449
1257
|
// parse_map may return a list
|
|
1450
|
-
|
|
1258
|
+
ExpressionObj value = parse_map();
|
|
1451
1259
|
// lex the expected closing parenthesis
|
|
1452
1260
|
if (!lex_css< exactly<')'> >()) error("unclosed parenthesis");
|
|
1453
1261
|
// expression can be evaluated
|
|
@@ -1455,7 +1263,7 @@ namespace Sass {
|
|
|
1455
1263
|
}
|
|
1456
1264
|
else if (lex_css< exactly<'['> >()) {
|
|
1457
1265
|
// explicit bracketed
|
|
1458
|
-
|
|
1266
|
+
ExpressionObj value = parse_bracket_list();
|
|
1459
1267
|
// lex the expected closing square bracket
|
|
1460
1268
|
if (!lex_css< exactly<']'> >()) error("unclosed squared bracket");
|
|
1461
1269
|
return value;
|
|
@@ -1478,7 +1286,7 @@ namespace Sass {
|
|
|
1478
1286
|
}
|
|
1479
1287
|
else if (lex< identifier_schema >()) {
|
|
1480
1288
|
String_Obj string = parse_identifier_schema();
|
|
1481
|
-
if (
|
|
1289
|
+
if (String_Schema* schema = Cast<String_Schema>(string)) {
|
|
1482
1290
|
if (lex < exactly < '(' > >()) {
|
|
1483
1291
|
schema->append(parse_list());
|
|
1484
1292
|
lex < exactly < ')' > >();
|
|
@@ -1493,38 +1301,31 @@ namespace Sass {
|
|
|
1493
1301
|
return parse_function_call();
|
|
1494
1302
|
}
|
|
1495
1303
|
else if (lex< exactly<'+'> >()) {
|
|
1496
|
-
|
|
1304
|
+
Unary_Expression* ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::PLUS, parse_factor());
|
|
1497
1305
|
if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
|
|
1498
1306
|
return ex;
|
|
1499
1307
|
}
|
|
1500
1308
|
else if (lex< exactly<'-'> >()) {
|
|
1501
|
-
|
|
1309
|
+
Unary_Expression* ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::MINUS, parse_factor());
|
|
1502
1310
|
if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
|
|
1503
1311
|
return ex;
|
|
1504
1312
|
}
|
|
1505
1313
|
else if (lex< exactly<'/'> >()) {
|
|
1506
|
-
|
|
1314
|
+
Unary_Expression* ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::SLASH, parse_factor());
|
|
1507
1315
|
if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
|
|
1508
1316
|
return ex;
|
|
1509
1317
|
}
|
|
1510
1318
|
else if (lex< sequence< kwd_not > >()) {
|
|
1511
|
-
|
|
1319
|
+
Unary_Expression* ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::NOT, parse_factor());
|
|
1512
1320
|
if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
|
|
1513
1321
|
return ex;
|
|
1514
1322
|
}
|
|
1515
|
-
// this whole branch is never hit via spec tests
|
|
1516
|
-
else if (peek < sequence < one_plus < alternatives < css_whitespace, exactly<'-'>, exactly<'+'> > >, number > >()) {
|
|
1517
|
-
if (parse_number_prefix()) return parse_value(); // prefix is positive
|
|
1518
|
-
Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::MINUS, parse_value());
|
|
1519
|
-
if (ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
|
|
1520
|
-
return ex;
|
|
1521
|
-
}
|
|
1522
1323
|
else {
|
|
1523
1324
|
return parse_value();
|
|
1524
1325
|
}
|
|
1525
1326
|
}
|
|
1526
1327
|
|
|
1527
|
-
bool number_has_zero(const
|
|
1328
|
+
bool number_has_zero(const sass::string& parsed)
|
|
1528
1329
|
{
|
|
1529
1330
|
size_t L = parsed.length();
|
|
1530
1331
|
return !( (L > 0 && parsed.substr(0, 1) == ".") ||
|
|
@@ -1533,9 +1334,9 @@ namespace Sass {
|
|
|
1533
1334
|
(L > 2 && parsed.substr(0, 3) == "-0.") );
|
|
1534
1335
|
}
|
|
1535
1336
|
|
|
1536
|
-
|
|
1337
|
+
Number* Parser::lexed_number(const SourceSpan& pstate, const sass::string& parsed)
|
|
1537
1338
|
{
|
|
1538
|
-
|
|
1339
|
+
Number* nr = SASS_MEMORY_NEW(Number,
|
|
1539
1340
|
pstate,
|
|
1540
1341
|
sass_strtod(parsed.c_str()),
|
|
1541
1342
|
"",
|
|
@@ -1545,9 +1346,9 @@ namespace Sass {
|
|
|
1545
1346
|
return nr;
|
|
1546
1347
|
}
|
|
1547
1348
|
|
|
1548
|
-
|
|
1349
|
+
Number* Parser::lexed_percentage(const SourceSpan& pstate, const sass::string& parsed)
|
|
1549
1350
|
{
|
|
1550
|
-
|
|
1351
|
+
Number* nr = SASS_MEMORY_NEW(Number,
|
|
1551
1352
|
pstate,
|
|
1552
1353
|
sass_strtod(parsed.c_str()),
|
|
1553
1354
|
"%",
|
|
@@ -1557,18 +1358,18 @@ namespace Sass {
|
|
|
1557
1358
|
return nr;
|
|
1558
1359
|
}
|
|
1559
1360
|
|
|
1560
|
-
|
|
1361
|
+
Number* Parser::lexed_dimension(const SourceSpan& pstate, const sass::string& parsed)
|
|
1561
1362
|
{
|
|
1562
1363
|
size_t L = parsed.length();
|
|
1563
1364
|
size_t num_pos = parsed.find_first_not_of(" \n\r\t");
|
|
1564
|
-
if (num_pos ==
|
|
1365
|
+
if (num_pos == sass::string::npos) num_pos = L;
|
|
1565
1366
|
size_t unit_pos = parsed.find_first_not_of("-+0123456789.", num_pos);
|
|
1566
1367
|
if (parsed[unit_pos] == 'e' && is_number(parsed[unit_pos+1]) ) {
|
|
1567
1368
|
unit_pos = parsed.find_first_not_of("-+0123456789.", ++ unit_pos);
|
|
1568
1369
|
}
|
|
1569
|
-
if (unit_pos ==
|
|
1570
|
-
const
|
|
1571
|
-
|
|
1370
|
+
if (unit_pos == sass::string::npos) unit_pos = L;
|
|
1371
|
+
const sass::string& num = parsed.substr(num_pos, unit_pos - num_pos);
|
|
1372
|
+
Number* nr = SASS_MEMORY_NEW(Number,
|
|
1572
1373
|
pstate,
|
|
1573
1374
|
sass_strtod(num.c_str()),
|
|
1574
1375
|
Token(number(parsed.c_str())),
|
|
@@ -1578,19 +1379,19 @@ namespace Sass {
|
|
|
1578
1379
|
return nr;
|
|
1579
1380
|
}
|
|
1580
1381
|
|
|
1581
|
-
|
|
1382
|
+
Value* Parser::lexed_hex_color(const SourceSpan& pstate, const sass::string& parsed)
|
|
1582
1383
|
{
|
|
1583
|
-
|
|
1384
|
+
Color_RGBA* color = NULL;
|
|
1584
1385
|
if (parsed[0] != '#') {
|
|
1585
1386
|
return SASS_MEMORY_NEW(String_Quoted, pstate, parsed);
|
|
1586
1387
|
}
|
|
1587
1388
|
// chop off the '#'
|
|
1588
|
-
|
|
1389
|
+
sass::string hext(parsed.substr(1));
|
|
1589
1390
|
if (parsed.length() == 4) {
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
color = SASS_MEMORY_NEW(
|
|
1391
|
+
sass::string r(2, parsed[1]);
|
|
1392
|
+
sass::string g(2, parsed[2]);
|
|
1393
|
+
sass::string b(2, parsed[3]);
|
|
1394
|
+
color = SASS_MEMORY_NEW(Color_RGBA,
|
|
1594
1395
|
pstate,
|
|
1595
1396
|
static_cast<double>(strtol(r.c_str(), NULL, 16)),
|
|
1596
1397
|
static_cast<double>(strtol(g.c_str(), NULL, 16)),
|
|
@@ -1598,11 +1399,24 @@ namespace Sass {
|
|
|
1598
1399
|
1, // alpha channel
|
|
1599
1400
|
parsed);
|
|
1600
1401
|
}
|
|
1402
|
+
else if (parsed.length() == 5) {
|
|
1403
|
+
sass::string r(2, parsed[1]);
|
|
1404
|
+
sass::string g(2, parsed[2]);
|
|
1405
|
+
sass::string b(2, parsed[3]);
|
|
1406
|
+
sass::string a(2, parsed[4]);
|
|
1407
|
+
color = SASS_MEMORY_NEW(Color_RGBA,
|
|
1408
|
+
pstate,
|
|
1409
|
+
static_cast<double>(strtol(r.c_str(), NULL, 16)),
|
|
1410
|
+
static_cast<double>(strtol(g.c_str(), NULL, 16)),
|
|
1411
|
+
static_cast<double>(strtol(b.c_str(), NULL, 16)),
|
|
1412
|
+
static_cast<double>(strtol(a.c_str(), NULL, 16)) / 255,
|
|
1413
|
+
parsed);
|
|
1414
|
+
}
|
|
1601
1415
|
else if (parsed.length() == 7) {
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
color = SASS_MEMORY_NEW(
|
|
1416
|
+
sass::string r(parsed.substr(1,2));
|
|
1417
|
+
sass::string g(parsed.substr(3,2));
|
|
1418
|
+
sass::string b(parsed.substr(5,2));
|
|
1419
|
+
color = SASS_MEMORY_NEW(Color_RGBA,
|
|
1606
1420
|
pstate,
|
|
1607
1421
|
static_cast<double>(strtol(r.c_str(), NULL, 16)),
|
|
1608
1422
|
static_cast<double>(strtol(g.c_str(), NULL, 16)),
|
|
@@ -1611,11 +1425,11 @@ namespace Sass {
|
|
|
1611
1425
|
parsed);
|
|
1612
1426
|
}
|
|
1613
1427
|
else if (parsed.length() == 9) {
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
color = SASS_MEMORY_NEW(
|
|
1428
|
+
sass::string r(parsed.substr(1,2));
|
|
1429
|
+
sass::string g(parsed.substr(3,2));
|
|
1430
|
+
sass::string b(parsed.substr(5,2));
|
|
1431
|
+
sass::string a(parsed.substr(7,2));
|
|
1432
|
+
color = SASS_MEMORY_NEW(Color_RGBA,
|
|
1619
1433
|
pstate,
|
|
1620
1434
|
static_cast<double>(strtol(r.c_str(), NULL, 16)),
|
|
1621
1435
|
static_cast<double>(strtol(g.c_str(), NULL, 16)),
|
|
@@ -1628,8 +1442,21 @@ namespace Sass {
|
|
|
1628
1442
|
return color;
|
|
1629
1443
|
}
|
|
1630
1444
|
|
|
1445
|
+
Value* Parser::color_or_string(const sass::string& lexed) const
|
|
1446
|
+
{
|
|
1447
|
+
if (auto color = name_to_color(lexed)) {
|
|
1448
|
+
auto c = SASS_MEMORY_NEW(Color_RGBA, color);
|
|
1449
|
+
c->is_delayed(true);
|
|
1450
|
+
c->pstate(pstate);
|
|
1451
|
+
c->disp(lexed);
|
|
1452
|
+
return c;
|
|
1453
|
+
} else {
|
|
1454
|
+
return SASS_MEMORY_NEW(String_Constant, pstate, lexed);
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1631
1458
|
// parse one value for a list
|
|
1632
|
-
|
|
1459
|
+
ExpressionObj Parser::parse_value()
|
|
1633
1460
|
{
|
|
1634
1461
|
lex< css_comments >(false);
|
|
1635
1462
|
if (lex< ampersand >())
|
|
@@ -1637,7 +1464,7 @@ namespace Sass {
|
|
|
1637
1464
|
if (match< ampersand >()) {
|
|
1638
1465
|
warning("In Sass, \"&&\" means two copies of the parent selector. You probably want to use \"and\" instead.", pstate);
|
|
1639
1466
|
}
|
|
1640
|
-
return SASS_MEMORY_NEW(
|
|
1467
|
+
return SASS_MEMORY_NEW(Parent_Reference, pstate); }
|
|
1641
1468
|
|
|
1642
1469
|
if (lex< kwd_important >())
|
|
1643
1470
|
{ return SASS_MEMORY_NEW(String_Constant, pstate, "!important"); }
|
|
@@ -1670,7 +1497,7 @@ namespace Sass {
|
|
|
1670
1497
|
{ return SASS_MEMORY_NEW(Null, pstate); }
|
|
1671
1498
|
|
|
1672
1499
|
if (lex< identifier >()) {
|
|
1673
|
-
return
|
|
1500
|
+
return color_or_string(lexed);
|
|
1674
1501
|
}
|
|
1675
1502
|
|
|
1676
1503
|
if (lex< percentage >())
|
|
@@ -1681,17 +1508,7 @@ namespace Sass {
|
|
|
1681
1508
|
{ return lexed_hex_color(lexed); }
|
|
1682
1509
|
|
|
1683
1510
|
if (lex< hexa >())
|
|
1684
|
-
{
|
|
1685
|
-
std::string s = lexed.to_string();
|
|
1686
|
-
|
|
1687
|
-
deprecated(
|
|
1688
|
-
"The value \""+s+"\" is currently parsed as a string, but it will be parsed as a color in",
|
|
1689
|
-
"future versions of Sass. Use \"unquote('"+s+"')\" to continue parsing it as a string.",
|
|
1690
|
-
true, pstate
|
|
1691
|
-
);
|
|
1692
|
-
|
|
1693
|
-
return SASS_MEMORY_NEW(String_Quoted, pstate, lexed);
|
|
1694
|
-
}
|
|
1511
|
+
{ return lexed_hex_color(lexed); }
|
|
1695
1512
|
|
|
1696
1513
|
if (lex< sequence < exactly <'#'>, identifier > >())
|
|
1697
1514
|
{ return SASS_MEMORY_NEW(String_Quoted, pstate, lexed); }
|
|
@@ -1710,14 +1527,10 @@ namespace Sass {
|
|
|
1710
1527
|
if (lex< variable >())
|
|
1711
1528
|
{ return SASS_MEMORY_NEW(Variable, pstate, Util::normalize_underscores(lexed)); }
|
|
1712
1529
|
|
|
1713
|
-
// Special case handling for `%` proceeding an interpolant.
|
|
1714
|
-
if (lex< sequence< exactly<'%'>, optional< percentage > > >())
|
|
1715
|
-
{ return SASS_MEMORY_NEW(String_Constant, pstate, lexed); }
|
|
1716
|
-
|
|
1717
1530
|
css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
|
|
1718
1531
|
|
|
1719
1532
|
// unreachable statement
|
|
1720
|
-
return
|
|
1533
|
+
return {};
|
|
1721
1534
|
}
|
|
1722
1535
|
|
|
1723
1536
|
// this parses interpolation inside other strings
|
|
@@ -1730,7 +1543,7 @@ namespace Sass {
|
|
|
1730
1543
|
find_first_in_interval< exactly<hash_lbrace>, block_comment >(i, chunk.end);
|
|
1731
1544
|
|
|
1732
1545
|
if (!p) {
|
|
1733
|
-
|
|
1546
|
+
String_Quoted* str_quoted = SASS_MEMORY_NEW(String_Quoted, pstate, sass::string(i, chunk.end), 0, false, false, true, css);
|
|
1734
1547
|
if (!constant && str_quoted->quote_mark()) str_quoted->quote_mark('*');
|
|
1735
1548
|
return str_quoted;
|
|
1736
1549
|
}
|
|
@@ -1743,7 +1556,7 @@ namespace Sass {
|
|
|
1743
1556
|
if (p) {
|
|
1744
1557
|
if (i < p) {
|
|
1745
1558
|
// accumulate the preceding segment if it's nonempty
|
|
1746
|
-
schema->append(SASS_MEMORY_NEW(String_Constant, pstate,
|
|
1559
|
+
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, sass::string(i, p), css));
|
|
1747
1560
|
}
|
|
1748
1561
|
// we need to skip anything inside strings
|
|
1749
1562
|
// create a new target in parser/prelexer
|
|
@@ -1753,7 +1566,9 @@ namespace Sass {
|
|
|
1753
1566
|
const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p + 2, chunk.end); // find the closing brace
|
|
1754
1567
|
if (j) { --j;
|
|
1755
1568
|
// parse the interpolant and accumulate it
|
|
1756
|
-
|
|
1569
|
+
LocalOption<const char*> partEnd(end, j);
|
|
1570
|
+
LocalOption<const char*> partBeg(position, p + 2);
|
|
1571
|
+
ExpressionObj interp_node = parse_list();
|
|
1757
1572
|
interp_node->is_interpolant(true);
|
|
1758
1573
|
schema->append(interp_node);
|
|
1759
1574
|
i = j;
|
|
@@ -1765,7 +1580,7 @@ namespace Sass {
|
|
|
1765
1580
|
}
|
|
1766
1581
|
else { // no interpolants left; add the last segment if nonempty
|
|
1767
1582
|
// check if we need quotes here (was not sure after merge)
|
|
1768
|
-
if (i < chunk.end) schema->append(SASS_MEMORY_NEW(String_Constant, pstate,
|
|
1583
|
+
if (i < chunk.end) schema->append(SASS_MEMORY_NEW(String_Constant, pstate, sass::string(i, chunk.end), css));
|
|
1769
1584
|
break;
|
|
1770
1585
|
}
|
|
1771
1586
|
++ i;
|
|
@@ -1774,74 +1589,66 @@ namespace Sass {
|
|
|
1774
1589
|
return schema.detach();
|
|
1775
1590
|
}
|
|
1776
1591
|
|
|
1777
|
-
String_Schema_Obj Parser::parse_css_variable_value(
|
|
1592
|
+
String_Schema_Obj Parser::parse_css_variable_value()
|
|
1778
1593
|
{
|
|
1779
1594
|
String_Schema_Obj schema = SASS_MEMORY_NEW(String_Schema, pstate);
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
{
|
|
1795
|
-
String_Schema_Obj schema = SASS_MEMORY_NEW(String_Schema, pstate);
|
|
1796
|
-
if (
|
|
1797
|
-
(top_level && lex< css_variable_top_level_value >(false)) ||
|
|
1798
|
-
(!top_level && lex< css_variable_value >(false))
|
|
1799
|
-
) {
|
|
1800
|
-
Token str(lexed);
|
|
1801
|
-
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, str));
|
|
1802
|
-
}
|
|
1803
|
-
else if (Expression_Obj tok = lex_interpolation()) {
|
|
1804
|
-
if (String_Schema_Ptr s = Cast<String_Schema>(tok)) {
|
|
1805
|
-
schema->concat(s);
|
|
1806
|
-
} else {
|
|
1807
|
-
schema->append(tok);
|
|
1808
|
-
}
|
|
1809
|
-
}
|
|
1810
|
-
else if (lex< quoted_string >()) {
|
|
1811
|
-
Expression_Obj tok = parse_string();
|
|
1812
|
-
if (String_Schema_Ptr s = Cast<String_Schema>(tok)) {
|
|
1813
|
-
schema->concat(s);
|
|
1814
|
-
} else {
|
|
1815
|
-
schema->append(tok);
|
|
1816
|
-
}
|
|
1817
|
-
}
|
|
1818
|
-
else {
|
|
1819
|
-
if (peek< alternatives< exactly<'('>, exactly<'['>, exactly<'{'> > >()) {
|
|
1820
|
-
if (lex< exactly<'('> >()) {
|
|
1821
|
-
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string("(")));
|
|
1822
|
-
if (String_Schema_Obj tok = parse_css_variable_value(false)) schema->concat(tok);
|
|
1823
|
-
if (!lex< exactly<')'> >()) css_error("Invalid CSS", " after ", ": expected \")\", was ");
|
|
1824
|
-
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string(")")));
|
|
1595
|
+
sass::vector<char> brackets;
|
|
1596
|
+
while (true) {
|
|
1597
|
+
if (
|
|
1598
|
+
(brackets.empty() && lex< css_variable_top_level_value >(false)) ||
|
|
1599
|
+
(!brackets.empty() && lex< css_variable_value >(false))
|
|
1600
|
+
) {
|
|
1601
|
+
Token str(lexed);
|
|
1602
|
+
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, str));
|
|
1603
|
+
} else if (ExpressionObj tok = lex_interpolation()) {
|
|
1604
|
+
if (String_Schema* s = Cast<String_Schema>(tok)) {
|
|
1605
|
+
if (s->empty()) break;
|
|
1606
|
+
schema->concat(s);
|
|
1607
|
+
} else {
|
|
1608
|
+
schema->append(tok);
|
|
1825
1609
|
}
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1610
|
+
} else if (lex< quoted_string >()) {
|
|
1611
|
+
ExpressionObj tok = parse_string();
|
|
1612
|
+
if (tok.isNull()) break;
|
|
1613
|
+
if (String_Schema* s = Cast<String_Schema>(tok)) {
|
|
1614
|
+
if (s->empty()) break;
|
|
1615
|
+
schema->concat(s);
|
|
1616
|
+
} else {
|
|
1617
|
+
schema->append(tok);
|
|
1831
1618
|
}
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1619
|
+
} else if (lex< alternatives< exactly<'('>, exactly<'['>, exactly<'{'> > >()) {
|
|
1620
|
+
const char opening_bracket = *(position - 1);
|
|
1621
|
+
brackets.push_back(opening_bracket);
|
|
1622
|
+
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, sass::string(1, opening_bracket)));
|
|
1623
|
+
} else if (const char *match = peek< alternatives< exactly<')'>, exactly<']'>, exactly<'}'> > >()) {
|
|
1624
|
+
if (brackets.empty()) break;
|
|
1625
|
+
const char closing_bracket = *(match - 1);
|
|
1626
|
+
if (brackets.back() != Util::opening_bracket_for(closing_bracket)) {
|
|
1627
|
+
sass::string message = ": expected \"";
|
|
1628
|
+
message += Util::closing_bracket_for(brackets.back());
|
|
1629
|
+
message += "\", was ";
|
|
1630
|
+
css_error("Invalid CSS", " after ", message);
|
|
1837
1631
|
}
|
|
1632
|
+
lex< alternatives< exactly<')'>, exactly<']'>, exactly<'}'> > >();
|
|
1633
|
+
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, sass::string(1, closing_bracket)));
|
|
1634
|
+
brackets.pop_back();
|
|
1635
|
+
} else {
|
|
1636
|
+
break;
|
|
1838
1637
|
}
|
|
1839
1638
|
}
|
|
1840
1639
|
|
|
1841
|
-
|
|
1640
|
+
if (!brackets.empty()) {
|
|
1641
|
+
sass::string message = ": expected \"";
|
|
1642
|
+
message += Util::closing_bracket_for(brackets.back());
|
|
1643
|
+
message += "\", was ";
|
|
1644
|
+
css_error("Invalid CSS", " after ", message);
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
if (schema->empty()) error("Custom property values may not be empty.");
|
|
1648
|
+
return schema.detach();
|
|
1842
1649
|
}
|
|
1843
1650
|
|
|
1844
|
-
|
|
1651
|
+
ValueObj Parser::parse_static_value()
|
|
1845
1652
|
{
|
|
1846
1653
|
lex< static_value >();
|
|
1847
1654
|
Token str(lexed);
|
|
@@ -1852,8 +1659,7 @@ namespace Sass {
|
|
|
1852
1659
|
--str.end;
|
|
1853
1660
|
--position;
|
|
1854
1661
|
|
|
1855
|
-
|
|
1856
|
-
return str_node;
|
|
1662
|
+
return color_or_string(str.time_wspace());;
|
|
1857
1663
|
}
|
|
1858
1664
|
|
|
1859
1665
|
String_Obj Parser::parse_string()
|
|
@@ -1869,15 +1675,15 @@ namespace Sass {
|
|
|
1869
1675
|
// see if there any interpolants
|
|
1870
1676
|
const char* p = find_first_in_interval< exactly<hash_lbrace>, block_comment >(str.begin, str.end);
|
|
1871
1677
|
if (!p) {
|
|
1872
|
-
return SASS_MEMORY_NEW(String_Quoted, pstate,
|
|
1678
|
+
return SASS_MEMORY_NEW(String_Quoted, pstate, sass::string(str.begin, str.end));
|
|
1873
1679
|
}
|
|
1874
1680
|
|
|
1875
|
-
|
|
1681
|
+
String_Schema* schema = SASS_MEMORY_NEW(String_Schema, pstate);
|
|
1876
1682
|
while (i < str.end) {
|
|
1877
1683
|
p = find_first_in_interval< exactly<hash_lbrace>, block_comment >(i, str.end);
|
|
1878
1684
|
if (p) {
|
|
1879
1685
|
if (i < p) {
|
|
1880
|
-
schema->append(SASS_MEMORY_NEW(String_Constant, pstate,
|
|
1686
|
+
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, sass::string(i, p))); // accumulate the preceding segment if it's nonempty
|
|
1881
1687
|
}
|
|
1882
1688
|
if (peek < sequence < optional_spaces, exactly<rbrace> > >(p+2)) { position = p+2;
|
|
1883
1689
|
css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
|
|
@@ -1885,7 +1691,9 @@ namespace Sass {
|
|
|
1885
1691
|
const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p+2, str.end); // find the closing brace
|
|
1886
1692
|
if (j) {
|
|
1887
1693
|
// parse the interpolant and accumulate it
|
|
1888
|
-
|
|
1694
|
+
LocalOption<const char*> partEnd(end, j);
|
|
1695
|
+
LocalOption<const char*> partBeg(position, p + 2);
|
|
1696
|
+
ExpressionObj interp_node = parse_list();
|
|
1889
1697
|
interp_node->is_interpolant(true);
|
|
1890
1698
|
schema->append(interp_node);
|
|
1891
1699
|
i = j;
|
|
@@ -1897,7 +1705,7 @@ namespace Sass {
|
|
|
1897
1705
|
}
|
|
1898
1706
|
else { // no interpolants left; add the last segment if nonempty
|
|
1899
1707
|
if (i < str.end) {
|
|
1900
|
-
schema->append(SASS_MEMORY_NEW(String_Constant, pstate,
|
|
1708
|
+
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, sass::string(i, str.end)));
|
|
1901
1709
|
}
|
|
1902
1710
|
break;
|
|
1903
1711
|
}
|
|
@@ -1907,7 +1715,7 @@ namespace Sass {
|
|
|
1907
1715
|
|
|
1908
1716
|
String_Obj Parser::parse_ie_keyword_arg()
|
|
1909
1717
|
{
|
|
1910
|
-
|
|
1718
|
+
String_Schema_Obj kwd_arg = SASS_MEMORY_NEW(String_Schema, pstate, 3);
|
|
1911
1719
|
if (lex< variable >()) {
|
|
1912
1720
|
kwd_arg->append(SASS_MEMORY_NEW(Variable, pstate, Util::normalize_underscores(lexed)));
|
|
1913
1721
|
} else {
|
|
@@ -1918,7 +1726,7 @@ namespace Sass {
|
|
|
1918
1726
|
kwd_arg->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed));
|
|
1919
1727
|
if (peek< variable >()) kwd_arg->append(parse_list());
|
|
1920
1728
|
else if (lex< number >()) {
|
|
1921
|
-
|
|
1729
|
+
sass::string parsed(lexed);
|
|
1922
1730
|
Util::normalize_decimals(parsed);
|
|
1923
1731
|
kwd_arg->append(lexed_number(parsed));
|
|
1924
1732
|
}
|
|
@@ -1958,11 +1766,11 @@ namespace Sass {
|
|
|
1958
1766
|
if (peek< exactly< rbrace > >()) {
|
|
1959
1767
|
css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
|
|
1960
1768
|
}
|
|
1961
|
-
|
|
1769
|
+
ExpressionObj ex;
|
|
1962
1770
|
if (lex< re_static_expression >()) {
|
|
1963
1771
|
ex = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
|
|
1964
1772
|
} else {
|
|
1965
|
-
ex = parse_list();
|
|
1773
|
+
ex = parse_list(true);
|
|
1966
1774
|
}
|
|
1967
1775
|
ex->is_interpolant(true);
|
|
1968
1776
|
schema->append(ex);
|
|
@@ -1986,7 +1794,7 @@ namespace Sass {
|
|
|
1986
1794
|
}
|
|
1987
1795
|
if (peek < exactly < '-' > >()) break;
|
|
1988
1796
|
}
|
|
1989
|
-
else if (lex<
|
|
1797
|
+
else if (lex< identifier >()) {
|
|
1990
1798
|
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed));
|
|
1991
1799
|
if ((*position == '"' || *position == '\'') || peek < alternatives < alpha > >()) {
|
|
1992
1800
|
// need_space = true;
|
|
@@ -1994,7 +1802,7 @@ namespace Sass {
|
|
|
1994
1802
|
}
|
|
1995
1803
|
// lex (normalized) variable
|
|
1996
1804
|
else if (lex< variable >()) {
|
|
1997
|
-
|
|
1805
|
+
sass::string name(Util::normalize_underscores(lexed));
|
|
1998
1806
|
schema->append(SASS_MEMORY_NEW(Variable, pstate, name));
|
|
1999
1807
|
}
|
|
2000
1808
|
// lex percentage value
|
|
@@ -2026,7 +1834,7 @@ namespace Sass {
|
|
|
2026
1834
|
++num_items;
|
|
2027
1835
|
}
|
|
2028
1836
|
if (position != stop) {
|
|
2029
|
-
schema->append(SASS_MEMORY_NEW(String_Constant, pstate,
|
|
1837
|
+
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, sass::string(position, stop)));
|
|
2030
1838
|
position = stop;
|
|
2031
1839
|
}
|
|
2032
1840
|
end = ee;
|
|
@@ -2042,7 +1850,7 @@ namespace Sass {
|
|
|
2042
1850
|
// see if there any interpolants
|
|
2043
1851
|
const char* p = find_first_in_interval< exactly<hash_lbrace>, block_comment >(id.begin, id.end);
|
|
2044
1852
|
if (!p) {
|
|
2045
|
-
return SASS_MEMORY_NEW(String_Constant, pstate,
|
|
1853
|
+
return SASS_MEMORY_NEW(String_Constant, pstate, sass::string(id.begin, id.end));
|
|
2046
1854
|
}
|
|
2047
1855
|
|
|
2048
1856
|
String_Schema_Obj schema = SASS_MEMORY_NEW(String_Schema, pstate);
|
|
@@ -2063,7 +1871,9 @@ namespace Sass {
|
|
|
2063
1871
|
const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p+2, id.end); // find the closing brace
|
|
2064
1872
|
if (j) {
|
|
2065
1873
|
// parse the interpolant and accumulate it
|
|
2066
|
-
|
|
1874
|
+
LocalOption<const char*> partEnd(end, j);
|
|
1875
|
+
LocalOption<const char*> partBeg(position, p + 2);
|
|
1876
|
+
ExpressionObj interp_node = parse_list(DELAYED);
|
|
2067
1877
|
interp_node->is_interpolant(true);
|
|
2068
1878
|
schema->append(interp_node);
|
|
2069
1879
|
// schema->has_interpolants(true);
|
|
@@ -2090,10 +1900,10 @@ namespace Sass {
|
|
|
2090
1900
|
Function_Call_Obj Parser::parse_calc_function()
|
|
2091
1901
|
{
|
|
2092
1902
|
lex< identifier >();
|
|
2093
|
-
|
|
2094
|
-
|
|
1903
|
+
sass::string name(lexed);
|
|
1904
|
+
SourceSpan call_pos = pstate;
|
|
2095
1905
|
lex< exactly<'('> >();
|
|
2096
|
-
|
|
1906
|
+
SourceSpan arg_pos = pstate;
|
|
2097
1907
|
const char* arg_beg = position;
|
|
2098
1908
|
parse_list();
|
|
2099
1909
|
const char* arg_end = position;
|
|
@@ -2110,32 +1920,32 @@ namespace Sass {
|
|
|
2110
1920
|
|
|
2111
1921
|
String_Obj Parser::parse_url_function_string()
|
|
2112
1922
|
{
|
|
2113
|
-
|
|
1923
|
+
sass::string prefix("");
|
|
2114
1924
|
if (lex< uri_prefix >()) {
|
|
2115
|
-
prefix =
|
|
1925
|
+
prefix = sass::string(lexed);
|
|
2116
1926
|
}
|
|
2117
1927
|
|
|
2118
1928
|
lex < optional_spaces >();
|
|
2119
1929
|
String_Obj url_string = parse_url_function_argument();
|
|
2120
1930
|
|
|
2121
|
-
|
|
1931
|
+
sass::string suffix("");
|
|
2122
1932
|
if (lex< real_uri_suffix >()) {
|
|
2123
|
-
suffix =
|
|
1933
|
+
suffix = sass::string(lexed);
|
|
2124
1934
|
}
|
|
2125
1935
|
|
|
2126
|
-
|
|
1936
|
+
sass::string uri("");
|
|
2127
1937
|
if (url_string) {
|
|
2128
1938
|
uri = url_string->to_string({ NESTED, 5 });
|
|
2129
1939
|
}
|
|
2130
1940
|
|
|
2131
|
-
if (
|
|
1941
|
+
if (String_Schema* schema = Cast<String_Schema>(url_string)) {
|
|
2132
1942
|
String_Schema_Obj res = SASS_MEMORY_NEW(String_Schema, pstate);
|
|
2133
1943
|
res->append(SASS_MEMORY_NEW(String_Constant, pstate, prefix));
|
|
2134
1944
|
res->append(schema);
|
|
2135
1945
|
res->append(SASS_MEMORY_NEW(String_Constant, pstate, suffix));
|
|
2136
1946
|
return res;
|
|
2137
1947
|
} else {
|
|
2138
|
-
|
|
1948
|
+
sass::string res = prefix + uri + suffix;
|
|
2139
1949
|
return SASS_MEMORY_NEW(String_Constant, pstate, res);
|
|
2140
1950
|
}
|
|
2141
1951
|
}
|
|
@@ -2144,7 +1954,7 @@ namespace Sass {
|
|
|
2144
1954
|
{
|
|
2145
1955
|
const char* p = position;
|
|
2146
1956
|
|
|
2147
|
-
|
|
1957
|
+
sass::string uri("");
|
|
2148
1958
|
if (lex< real_uri_value >(false)) {
|
|
2149
1959
|
uri = lexed.to_string();
|
|
2150
1960
|
}
|
|
@@ -2155,52 +1965,56 @@ namespace Sass {
|
|
|
2155
1965
|
while (pp && peek< exactly< hash_lbrace > >(pp)) {
|
|
2156
1966
|
pp = sequence< interpolant, real_uri_value >(pp);
|
|
2157
1967
|
}
|
|
1968
|
+
if (!pp) return {};
|
|
2158
1969
|
position = pp;
|
|
2159
1970
|
return parse_interpolated_chunk(Token(p, position));
|
|
2160
1971
|
}
|
|
2161
1972
|
else if (uri != "") {
|
|
2162
|
-
|
|
1973
|
+
sass::string res = Util::rtrim(uri);
|
|
2163
1974
|
return SASS_MEMORY_NEW(String_Constant, pstate, res);
|
|
2164
1975
|
}
|
|
2165
1976
|
|
|
2166
|
-
return
|
|
1977
|
+
return {};
|
|
2167
1978
|
}
|
|
2168
1979
|
|
|
2169
1980
|
Function_Call_Obj Parser::parse_function_call()
|
|
2170
1981
|
{
|
|
2171
1982
|
lex< identifier >();
|
|
2172
|
-
|
|
1983
|
+
sass::string name(lexed);
|
|
2173
1984
|
|
|
2174
1985
|
if (Util::normalize_underscores(name) == "content-exists" && stack.back() != Scope::Mixin)
|
|
2175
1986
|
{ error("Cannot call content-exists() except within a mixin."); }
|
|
2176
1987
|
|
|
2177
|
-
|
|
1988
|
+
SourceSpan call_pos = pstate;
|
|
2178
1989
|
Arguments_Obj args = parse_arguments();
|
|
2179
1990
|
return SASS_MEMORY_NEW(Function_Call, call_pos, name, args);
|
|
2180
1991
|
}
|
|
2181
1992
|
|
|
2182
|
-
|
|
1993
|
+
Function_Call_Obj Parser::parse_function_call_schema()
|
|
2183
1994
|
{
|
|
2184
1995
|
String_Obj name = parse_identifier_schema();
|
|
2185
|
-
|
|
1996
|
+
SourceSpan source_position_of_call = pstate;
|
|
2186
1997
|
Arguments_Obj args = parse_arguments();
|
|
2187
1998
|
|
|
2188
|
-
return SASS_MEMORY_NEW(
|
|
1999
|
+
return SASS_MEMORY_NEW(Function_Call, source_position_of_call, name, args);
|
|
2189
2000
|
}
|
|
2190
2001
|
|
|
2191
2002
|
Content_Obj Parser::parse_content_directive()
|
|
2192
2003
|
{
|
|
2193
|
-
|
|
2004
|
+
SourceSpan call_pos = pstate;
|
|
2005
|
+
Arguments_Obj args = parse_arguments();
|
|
2006
|
+
|
|
2007
|
+
return SASS_MEMORY_NEW(Content, call_pos, args);
|
|
2194
2008
|
}
|
|
2195
2009
|
|
|
2196
2010
|
If_Obj Parser::parse_if_directive(bool else_if)
|
|
2197
2011
|
{
|
|
2198
2012
|
stack.push_back(Scope::Control);
|
|
2199
|
-
|
|
2013
|
+
SourceSpan if_source_position = pstate;
|
|
2200
2014
|
bool root = block_stack.back()->is_root();
|
|
2201
|
-
|
|
2015
|
+
ExpressionObj predicate = parse_list();
|
|
2202
2016
|
Block_Obj block = parse_block(root);
|
|
2203
|
-
Block_Obj alternative
|
|
2017
|
+
Block_Obj alternative;
|
|
2204
2018
|
|
|
2205
2019
|
// only throw away comment if we parse a case
|
|
2206
2020
|
// we want all other comments to be parsed
|
|
@@ -2215,23 +2029,23 @@ namespace Sass {
|
|
|
2215
2029
|
return SASS_MEMORY_NEW(If, if_source_position, predicate, block, alternative);
|
|
2216
2030
|
}
|
|
2217
2031
|
|
|
2218
|
-
|
|
2032
|
+
ForRuleObj Parser::parse_for_directive()
|
|
2219
2033
|
{
|
|
2220
2034
|
stack.push_back(Scope::Control);
|
|
2221
|
-
|
|
2035
|
+
SourceSpan for_source_position = pstate;
|
|
2222
2036
|
bool root = block_stack.back()->is_root();
|
|
2223
2037
|
lex_variable();
|
|
2224
|
-
|
|
2038
|
+
sass::string var(Util::normalize_underscores(lexed));
|
|
2225
2039
|
if (!lex< kwd_from >()) error("expected 'from' keyword in @for directive");
|
|
2226
|
-
|
|
2040
|
+
ExpressionObj lower_bound = parse_expression();
|
|
2227
2041
|
bool inclusive = false;
|
|
2228
2042
|
if (lex< kwd_through >()) inclusive = true;
|
|
2229
2043
|
else if (lex< kwd_to >()) inclusive = false;
|
|
2230
2044
|
else error("expected 'through' or 'to' keyword in @for directive");
|
|
2231
|
-
|
|
2045
|
+
ExpressionObj upper_bound = parse_expression();
|
|
2232
2046
|
Block_Obj body = parse_block(root);
|
|
2233
2047
|
stack.pop_back();
|
|
2234
|
-
return SASS_MEMORY_NEW(
|
|
2048
|
+
return SASS_MEMORY_NEW(ForRule, for_source_position, var, lower_bound, upper_bound, body, inclusive);
|
|
2235
2049
|
}
|
|
2236
2050
|
|
|
2237
2051
|
// helper to parse a var token
|
|
@@ -2247,7 +2061,7 @@ namespace Sass {
|
|
|
2247
2061
|
css_error("Invalid CSS", " after ", ": expected identifier, was ");
|
|
2248
2062
|
}
|
|
2249
2063
|
// return object
|
|
2250
|
-
return
|
|
2064
|
+
return lexed;
|
|
2251
2065
|
}
|
|
2252
2066
|
// helper to parse identifier
|
|
2253
2067
|
Token Parser::lex_identifier()
|
|
@@ -2257,15 +2071,15 @@ namespace Sass {
|
|
|
2257
2071
|
css_error("Invalid CSS", " after ", ": expected identifier, was ");
|
|
2258
2072
|
}
|
|
2259
2073
|
// return object
|
|
2260
|
-
return
|
|
2074
|
+
return lexed;
|
|
2261
2075
|
}
|
|
2262
2076
|
|
|
2263
|
-
|
|
2077
|
+
EachRuleObj Parser::parse_each_directive()
|
|
2264
2078
|
{
|
|
2265
2079
|
stack.push_back(Scope::Control);
|
|
2266
|
-
|
|
2080
|
+
SourceSpan each_source_position = pstate;
|
|
2267
2081
|
bool root = block_stack.back()->is_root();
|
|
2268
|
-
|
|
2082
|
+
sass::vector<sass::string> vars;
|
|
2269
2083
|
lex_variable();
|
|
2270
2084
|
vars.push_back(Util::normalize_underscores(lexed));
|
|
2271
2085
|
while (lex< exactly<','> >()) {
|
|
@@ -2273,21 +2087,21 @@ namespace Sass {
|
|
|
2273
2087
|
vars.push_back(Util::normalize_underscores(lexed));
|
|
2274
2088
|
}
|
|
2275
2089
|
if (!lex< kwd_in >()) error("expected 'in' keyword in @each directive");
|
|
2276
|
-
|
|
2090
|
+
ExpressionObj list = parse_list();
|
|
2277
2091
|
Block_Obj body = parse_block(root);
|
|
2278
2092
|
stack.pop_back();
|
|
2279
|
-
return SASS_MEMORY_NEW(
|
|
2093
|
+
return SASS_MEMORY_NEW(EachRule, each_source_position, vars, list, body);
|
|
2280
2094
|
}
|
|
2281
2095
|
|
|
2282
2096
|
// called after parsing `kwd_while_directive`
|
|
2283
|
-
|
|
2097
|
+
WhileRuleObj Parser::parse_while_directive()
|
|
2284
2098
|
{
|
|
2285
2099
|
stack.push_back(Scope::Control);
|
|
2286
2100
|
bool root = block_stack.back()->is_root();
|
|
2287
2101
|
// create the initial while call object
|
|
2288
|
-
|
|
2102
|
+
WhileRuleObj call = SASS_MEMORY_NEW(WhileRule, pstate, ExpressionObj{}, Block_Obj{});
|
|
2289
2103
|
// parse mandatory predicate
|
|
2290
|
-
|
|
2104
|
+
ExpressionObj predicate = parse_list();
|
|
2291
2105
|
List_Obj l = Cast<List>(predicate);
|
|
2292
2106
|
if (!predicate || (l && !l->length())) {
|
|
2293
2107
|
css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ", false);
|
|
@@ -2301,20 +2115,107 @@ namespace Sass {
|
|
|
2301
2115
|
return call.detach();
|
|
2302
2116
|
}
|
|
2303
2117
|
|
|
2304
|
-
|
|
2305
|
-
|
|
2118
|
+
|
|
2119
|
+
sass::vector<CssMediaQuery_Obj> Parser::parseCssMediaQueries()
|
|
2306
2120
|
{
|
|
2307
|
-
|
|
2308
|
-
|
|
2121
|
+
sass::vector<CssMediaQuery_Obj> result;
|
|
2122
|
+
do {
|
|
2123
|
+
if (auto query = parseCssMediaQuery()) {
|
|
2124
|
+
result.push_back(query);
|
|
2125
|
+
}
|
|
2126
|
+
} while (lex<exactly<','>>());
|
|
2127
|
+
return result;
|
|
2128
|
+
}
|
|
2129
|
+
|
|
2130
|
+
sass::string Parser::parseIdentifier()
|
|
2131
|
+
{
|
|
2132
|
+
if (lex < identifier >(false)) {
|
|
2133
|
+
return sass::string(lexed);
|
|
2134
|
+
}
|
|
2135
|
+
return sass::string();
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2138
|
+
CssMediaQuery_Obj Parser::parseCssMediaQuery()
|
|
2139
|
+
{
|
|
2140
|
+
CssMediaQuery_Obj result = SASS_MEMORY_NEW(CssMediaQuery, pstate);
|
|
2141
|
+
lex<css_comments>(false);
|
|
2142
|
+
|
|
2143
|
+
// Check if any tokens are to parse
|
|
2144
|
+
if (!peek_css<exactly<'('>>()) {
|
|
2145
|
+
|
|
2146
|
+
sass::string token1(parseIdentifier());
|
|
2147
|
+
lex<css_comments>(false);
|
|
2148
|
+
|
|
2149
|
+
if (token1.empty()) {
|
|
2150
|
+
return {};
|
|
2151
|
+
}
|
|
2152
|
+
|
|
2153
|
+
sass::string token2(parseIdentifier());
|
|
2154
|
+
lex<css_comments>(false);
|
|
2155
|
+
|
|
2156
|
+
if (Util::equalsLiteral("and", token2)) {
|
|
2157
|
+
result->type(token1);
|
|
2158
|
+
}
|
|
2159
|
+
else {
|
|
2160
|
+
if (token2.empty()) {
|
|
2161
|
+
result->type(token1);
|
|
2162
|
+
}
|
|
2163
|
+
else {
|
|
2164
|
+
result->modifier(token1);
|
|
2165
|
+
result->type(token2);
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
if (lex < kwd_and >()) {
|
|
2169
|
+
lex<css_comments>(false);
|
|
2170
|
+
}
|
|
2171
|
+
else {
|
|
2172
|
+
return result;
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2175
|
+
}
|
|
2176
|
+
|
|
2177
|
+
}
|
|
2178
|
+
|
|
2179
|
+
sass::vector<sass::string> queries;
|
|
2180
|
+
|
|
2181
|
+
do {
|
|
2182
|
+
lex<css_comments>(false);
|
|
2183
|
+
|
|
2184
|
+
if (lex<exactly<'('>>()) {
|
|
2185
|
+
// In dart sass parser returns a pure string
|
|
2186
|
+
if (lex < skip_over_scopes < exactly < '(' >, exactly < ')' > > >()) {
|
|
2187
|
+
sass::string decl("(" + sass::string(lexed));
|
|
2188
|
+
queries.push_back(decl);
|
|
2189
|
+
}
|
|
2190
|
+
// Should be: parseDeclarationValue;
|
|
2191
|
+
if (!lex<exactly<')'>>()) {
|
|
2192
|
+
// Should we throw an error here?
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
} while (lex < kwd_and >());
|
|
2196
|
+
|
|
2197
|
+
result->features(queries);
|
|
2198
|
+
|
|
2199
|
+
if (result->features().empty()) {
|
|
2200
|
+
if (result->type().empty()) {
|
|
2201
|
+
return {};
|
|
2202
|
+
}
|
|
2203
|
+
}
|
|
2204
|
+
|
|
2205
|
+
return result;
|
|
2206
|
+
}
|
|
2309
2207
|
|
|
2310
|
-
media_block->media_queries(parse_media_queries());
|
|
2311
2208
|
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2209
|
+
// EO parse_while_directive
|
|
2210
|
+
MediaRule_Obj Parser::parseMediaRule()
|
|
2211
|
+
{
|
|
2212
|
+
MediaRule_Obj rule = SASS_MEMORY_NEW(MediaRule, pstate);
|
|
2213
|
+
stack.push_back(Scope::Media);
|
|
2214
|
+
rule->schema(parse_media_queries());
|
|
2215
|
+
parse_block_comments(false);
|
|
2216
|
+
rule->block(parse_css_block());
|
|
2316
2217
|
stack.pop_back();
|
|
2317
|
-
return
|
|
2218
|
+
return rule;
|
|
2318
2219
|
}
|
|
2319
2220
|
|
|
2320
2221
|
List_Obj Parser::parse_media_queries()
|
|
@@ -2327,7 +2228,7 @@ namespace Sass {
|
|
|
2327
2228
|
return queries.detach();
|
|
2328
2229
|
}
|
|
2329
2230
|
|
|
2330
|
-
//
|
|
2231
|
+
// Expression* Parser::parse_media_query()
|
|
2331
2232
|
Media_Query_Obj Parser::parse_media_query()
|
|
2332
2233
|
{
|
|
2333
2234
|
advanceToNextToken();
|
|
@@ -2335,15 +2236,17 @@ namespace Sass {
|
|
|
2335
2236
|
if (lex < kwd_not >()) { media_query->is_negated(true); lex < css_comments >(false); }
|
|
2336
2237
|
else if (lex < kwd_only >()) { media_query->is_restricted(true); lex < css_comments >(false); }
|
|
2337
2238
|
|
|
2338
|
-
if (lex < identifier_schema >())
|
|
2339
|
-
else if (lex < identifier >())
|
|
2239
|
+
if (lex < identifier_schema >()) media_query->media_type(parse_identifier_schema());
|
|
2240
|
+
else if (lex < identifier >()) media_query->media_type(parse_interpolated_chunk(lexed));
|
|
2340
2241
|
else media_query->append(parse_media_expression());
|
|
2341
2242
|
|
|
2342
2243
|
while (lex_css < kwd_and >()) media_query->append(parse_media_expression());
|
|
2343
2244
|
if (lex < identifier_schema >()) {
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2245
|
+
String_Schema_Obj schema = SASS_MEMORY_NEW(String_Schema, pstate);
|
|
2246
|
+
if (media_query->media_type()) {
|
|
2247
|
+
schema->append(media_query->media_type());
|
|
2248
|
+
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, " "));
|
|
2249
|
+
}
|
|
2347
2250
|
schema->append(parse_identifier_schema());
|
|
2348
2251
|
media_query->media_type(schema);
|
|
2349
2252
|
}
|
|
@@ -2354,21 +2257,21 @@ namespace Sass {
|
|
|
2354
2257
|
return media_query;
|
|
2355
2258
|
}
|
|
2356
2259
|
|
|
2357
|
-
|
|
2260
|
+
Media_Query_ExpressionObj Parser::parse_media_expression()
|
|
2358
2261
|
{
|
|
2359
2262
|
if (lex < identifier_schema >()) {
|
|
2360
2263
|
String_Obj ss = parse_identifier_schema();
|
|
2361
|
-
return SASS_MEMORY_NEW(Media_Query_Expression, pstate, ss,
|
|
2264
|
+
return SASS_MEMORY_NEW(Media_Query_Expression, pstate, ss, ExpressionObj{}, true);
|
|
2362
2265
|
}
|
|
2363
2266
|
if (!lex_css< exactly<'('> >()) {
|
|
2364
2267
|
error("media query expression must begin with '('");
|
|
2365
2268
|
}
|
|
2366
|
-
|
|
2269
|
+
ExpressionObj feature;
|
|
2367
2270
|
if (peek_css< exactly<')'> >()) {
|
|
2368
2271
|
error("media feature required in media query expression");
|
|
2369
2272
|
}
|
|
2370
2273
|
feature = parse_expression();
|
|
2371
|
-
|
|
2274
|
+
ExpressionObj expression;
|
|
2372
2275
|
if (lex_css< exactly<':'> >()) {
|
|
2373
2276
|
expression = parse_list(DELAYED);
|
|
2374
2277
|
}
|
|
@@ -2380,14 +2283,11 @@ namespace Sass {
|
|
|
2380
2283
|
|
|
2381
2284
|
// lexed after `kwd_supports_directive`
|
|
2382
2285
|
// these are very similar to media blocks
|
|
2383
|
-
|
|
2286
|
+
SupportsRuleObj Parser::parse_supports_directive()
|
|
2384
2287
|
{
|
|
2385
|
-
|
|
2386
|
-
if (!cond) {
|
|
2387
|
-
css_error("Invalid CSS", " after ", ": expected @supports condition (e.g. (display: flexbox)), was ", false);
|
|
2388
|
-
}
|
|
2288
|
+
SupportsConditionObj cond = parse_supports_condition(/*top_level=*/true);
|
|
2389
2289
|
// create the ast node object for the support queries
|
|
2390
|
-
|
|
2290
|
+
SupportsRuleObj query = SASS_MEMORY_NEW(SupportsRule, pstate, cond);
|
|
2391
2291
|
// additional block is mandatory
|
|
2392
2292
|
// parse inner block
|
|
2393
2293
|
query->block(parse_block());
|
|
@@ -2397,65 +2297,65 @@ namespace Sass {
|
|
|
2397
2297
|
|
|
2398
2298
|
// parse one query operation
|
|
2399
2299
|
// may encounter nested queries
|
|
2400
|
-
|
|
2300
|
+
SupportsConditionObj Parser::parse_supports_condition(bool top_level)
|
|
2401
2301
|
{
|
|
2402
2302
|
lex < css_whitespace >();
|
|
2403
|
-
|
|
2303
|
+
SupportsConditionObj cond;
|
|
2404
2304
|
if ((cond = parse_supports_negation())) return cond;
|
|
2405
|
-
if ((cond = parse_supports_operator())) return cond;
|
|
2305
|
+
if ((cond = parse_supports_operator(top_level))) return cond;
|
|
2406
2306
|
if ((cond = parse_supports_interpolation())) return cond;
|
|
2407
2307
|
return cond;
|
|
2408
2308
|
}
|
|
2409
2309
|
|
|
2410
|
-
|
|
2310
|
+
SupportsConditionObj Parser::parse_supports_negation()
|
|
2411
2311
|
{
|
|
2412
|
-
if (!lex < kwd_not >()) return
|
|
2413
|
-
|
|
2414
|
-
return SASS_MEMORY_NEW(
|
|
2312
|
+
if (!lex < kwd_not >()) return {};
|
|
2313
|
+
SupportsConditionObj cond = parse_supports_condition_in_parens(/*parens_required=*/true);
|
|
2314
|
+
return SASS_MEMORY_NEW(SupportsNegation, pstate, cond);
|
|
2415
2315
|
}
|
|
2416
2316
|
|
|
2417
|
-
|
|
2317
|
+
SupportsConditionObj Parser::parse_supports_operator(bool top_level)
|
|
2418
2318
|
{
|
|
2419
|
-
|
|
2420
|
-
if (cond.isNull()) return
|
|
2319
|
+
SupportsConditionObj cond = parse_supports_condition_in_parens(/*parens_required=*/top_level);
|
|
2320
|
+
if (cond.isNull()) return {};
|
|
2421
2321
|
|
|
2422
2322
|
while (true) {
|
|
2423
|
-
|
|
2424
|
-
if (lex < kwd_and >()) { op =
|
|
2323
|
+
SupportsOperation::Operand op = SupportsOperation::OR;
|
|
2324
|
+
if (lex < kwd_and >()) { op = SupportsOperation::AND; }
|
|
2425
2325
|
else if(!lex < kwd_or >()) { break; }
|
|
2426
2326
|
|
|
2427
2327
|
lex < css_whitespace >();
|
|
2428
|
-
|
|
2328
|
+
SupportsConditionObj right = parse_supports_condition_in_parens(/*parens_required=*/true);
|
|
2429
2329
|
|
|
2430
|
-
//
|
|
2431
|
-
cond = SASS_MEMORY_NEW(
|
|
2330
|
+
// SupportsCondition* cc = SASS_MEMORY_NEW(SupportsCondition, *static_cast<SupportsCondition*>(cond));
|
|
2331
|
+
cond = SASS_MEMORY_NEW(SupportsOperation, pstate, cond, right, op);
|
|
2432
2332
|
}
|
|
2433
2333
|
return cond;
|
|
2434
2334
|
}
|
|
2435
2335
|
|
|
2436
|
-
|
|
2336
|
+
SupportsConditionObj Parser::parse_supports_interpolation()
|
|
2437
2337
|
{
|
|
2438
|
-
if (!lex < interpolant >()) return
|
|
2338
|
+
if (!lex < interpolant >()) return {};
|
|
2439
2339
|
|
|
2440
2340
|
String_Obj interp = parse_interpolated_chunk(lexed);
|
|
2441
|
-
if (!interp) return
|
|
2341
|
+
if (!interp) return {};
|
|
2442
2342
|
|
|
2443
2343
|
return SASS_MEMORY_NEW(Supports_Interpolation, pstate, interp);
|
|
2444
2344
|
}
|
|
2445
2345
|
|
|
2446
2346
|
// TODO: This needs some major work. Although feature conditions
|
|
2447
2347
|
// look like declarations their semantics differ significantly
|
|
2448
|
-
|
|
2348
|
+
SupportsConditionObj Parser::parse_supports_declaration()
|
|
2449
2349
|
{
|
|
2450
|
-
|
|
2350
|
+
SupportsCondition* cond;
|
|
2451
2351
|
// parse something declaration like
|
|
2452
|
-
|
|
2453
|
-
|
|
2352
|
+
ExpressionObj feature = parse_expression();
|
|
2353
|
+
ExpressionObj expression;
|
|
2454
2354
|
if (lex_css< exactly<':'> >()) {
|
|
2455
2355
|
expression = parse_list(DELAYED);
|
|
2456
2356
|
}
|
|
2457
2357
|
if (!feature || !expression) error("@supports condition expected declaration");
|
|
2458
|
-
cond = SASS_MEMORY_NEW(
|
|
2358
|
+
cond = SASS_MEMORY_NEW(SupportsDeclaration,
|
|
2459
2359
|
feature->pstate(),
|
|
2460
2360
|
feature,
|
|
2461
2361
|
expression);
|
|
@@ -2463,30 +2363,33 @@ namespace Sass {
|
|
|
2463
2363
|
return cond;
|
|
2464
2364
|
}
|
|
2465
2365
|
|
|
2466
|
-
|
|
2366
|
+
SupportsConditionObj Parser::parse_supports_condition_in_parens(bool parens_required)
|
|
2467
2367
|
{
|
|
2468
|
-
|
|
2469
|
-
if (interp !=
|
|
2368
|
+
SupportsConditionObj interp = parse_supports_interpolation();
|
|
2369
|
+
if (interp != nullptr) return interp;
|
|
2470
2370
|
|
|
2471
|
-
if (!lex < exactly <'('> >())
|
|
2371
|
+
if (!lex < exactly <'('> >()) {
|
|
2372
|
+
if (parens_required) {
|
|
2373
|
+
css_error("Invalid CSS", " after ", ": expected @supports condition (e.g. (display: flexbox)), was ", /*trim=*/false);
|
|
2374
|
+
} else {
|
|
2375
|
+
return {};
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2472
2378
|
lex < css_whitespace >();
|
|
2473
2379
|
|
|
2474
|
-
|
|
2475
|
-
if (cond
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
cond = parse_supports_declaration();
|
|
2479
|
-
if (!lex < exactly <')'> >()) error("unclosed parenthesis in @supports declaration");
|
|
2480
|
-
}
|
|
2380
|
+
SupportsConditionObj cond = parse_supports_condition(/*top_level=*/false);
|
|
2381
|
+
if (cond.isNull()) cond = parse_supports_declaration();
|
|
2382
|
+
if (!lex < exactly <')'> >()) error("unclosed parenthesis in @supports declaration");
|
|
2383
|
+
|
|
2481
2384
|
lex < css_whitespace >();
|
|
2482
2385
|
return cond;
|
|
2483
2386
|
}
|
|
2484
2387
|
|
|
2485
|
-
|
|
2388
|
+
AtRootRuleObj Parser::parse_at_root_block()
|
|
2486
2389
|
{
|
|
2487
2390
|
stack.push_back(Scope::AtRoot);
|
|
2488
|
-
|
|
2489
|
-
Block_Obj body
|
|
2391
|
+
SourceSpan at_source_position = pstate;
|
|
2392
|
+
Block_Obj body;
|
|
2490
2393
|
At_Root_Query_Obj expr;
|
|
2491
2394
|
Lookahead lookahead_result;
|
|
2492
2395
|
if (lex_css< exactly<'('> >()) {
|
|
@@ -2497,11 +2400,11 @@ namespace Sass {
|
|
|
2497
2400
|
body = parse_block(true);
|
|
2498
2401
|
}
|
|
2499
2402
|
else if ((lookahead_result = lookahead_for_selector(position)).found) {
|
|
2500
|
-
|
|
2403
|
+
StyleRuleObj r = parse_ruleset(lookahead_result);
|
|
2501
2404
|
body = SASS_MEMORY_NEW(Block, r->pstate(), 1, true);
|
|
2502
2405
|
body->append(r);
|
|
2503
2406
|
}
|
|
2504
|
-
|
|
2407
|
+
AtRootRuleObj at_root = SASS_MEMORY_NEW(AtRootRule, at_source_position, body);
|
|
2505
2408
|
if (!expr.isNull()) at_root->expression(expr);
|
|
2506
2409
|
stack.pop_back();
|
|
2507
2410
|
return at_root;
|
|
@@ -2515,9 +2418,9 @@ namespace Sass {
|
|
|
2515
2418
|
css_error("Invalid CSS", " after ", ": expected \"with\" or \"without\", was ");
|
|
2516
2419
|
}
|
|
2517
2420
|
|
|
2518
|
-
|
|
2421
|
+
ExpressionObj feature = parse_list();
|
|
2519
2422
|
if (!lex_css< exactly<':'> >()) error("style declaration must contain a value");
|
|
2520
|
-
|
|
2423
|
+
ExpressionObj expression = parse_list();
|
|
2521
2424
|
List_Obj value = SASS_MEMORY_NEW(List, feature->pstate(), 1);
|
|
2522
2425
|
|
|
2523
2426
|
if (expression->concrete_type() == Expression::LIST) {
|
|
@@ -2533,71 +2436,9 @@ namespace Sass {
|
|
|
2533
2436
|
return cond;
|
|
2534
2437
|
}
|
|
2535
2438
|
|
|
2536
|
-
|
|
2537
|
-
{
|
|
2538
|
-
std::string kwd(lexed);
|
|
2539
|
-
|
|
2540
|
-
if (lexed == "@else") error("Invalid CSS: @else must come after @if");
|
|
2541
|
-
|
|
2542
|
-
// this whole branch is never hit via spec tests
|
|
2543
|
-
|
|
2544
|
-
Directive_Ptr at_rule = SASS_MEMORY_NEW(Directive, pstate, kwd);
|
|
2545
|
-
Lookahead lookahead = lookahead_for_include(position);
|
|
2546
|
-
if (lookahead.found && !lookahead.has_interpolants) {
|
|
2547
|
-
at_rule->selector(parse_selector_list(false));
|
|
2548
|
-
}
|
|
2549
|
-
|
|
2550
|
-
lex < css_comments >(false);
|
|
2551
|
-
|
|
2552
|
-
if (lex < static_property >()) {
|
|
2553
|
-
at_rule->value(parse_interpolated_chunk(Token(lexed)));
|
|
2554
|
-
} else if (!(peek < alternatives < exactly<'{'>, exactly<'}'>, exactly<';'> > >())) {
|
|
2555
|
-
at_rule->value(parse_list());
|
|
2556
|
-
}
|
|
2557
|
-
|
|
2558
|
-
lex < css_comments >(false);
|
|
2559
|
-
|
|
2560
|
-
if (peek< exactly<'{'> >()) {
|
|
2561
|
-
at_rule->block(parse_block());
|
|
2562
|
-
}
|
|
2563
|
-
|
|
2564
|
-
return at_rule;
|
|
2565
|
-
}
|
|
2566
|
-
|
|
2567
|
-
// this whole branch is never hit via spec tests
|
|
2568
|
-
Directive_Obj Parser::parse_prefixed_directive()
|
|
2439
|
+
AtRuleObj Parser::parse_directive()
|
|
2569
2440
|
{
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
if (lexed == "@else") error("Invalid CSS: @else must come after @if");
|
|
2573
|
-
|
|
2574
|
-
Directive_Obj at_rule = SASS_MEMORY_NEW(Directive, pstate, kwd);
|
|
2575
|
-
Lookahead lookahead = lookahead_for_include(position);
|
|
2576
|
-
if (lookahead.found && !lookahead.has_interpolants) {
|
|
2577
|
-
at_rule->selector(parse_selector_list(false));
|
|
2578
|
-
}
|
|
2579
|
-
|
|
2580
|
-
lex < css_comments >(false);
|
|
2581
|
-
|
|
2582
|
-
if (lex < static_property >()) {
|
|
2583
|
-
at_rule->value(parse_interpolated_chunk(Token(lexed)));
|
|
2584
|
-
} else if (!(peek < alternatives < exactly<'{'>, exactly<'}'>, exactly<';'> > >())) {
|
|
2585
|
-
at_rule->value(parse_list());
|
|
2586
|
-
}
|
|
2587
|
-
|
|
2588
|
-
lex < css_comments >(false);
|
|
2589
|
-
|
|
2590
|
-
if (peek< exactly<'{'> >()) {
|
|
2591
|
-
at_rule->block(parse_block());
|
|
2592
|
-
}
|
|
2593
|
-
|
|
2594
|
-
return at_rule;
|
|
2595
|
-
}
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
Directive_Obj Parser::parse_directive()
|
|
2599
|
-
{
|
|
2600
|
-
Directive_Obj directive = SASS_MEMORY_NEW(Directive, pstate, lexed);
|
|
2441
|
+
AtRuleObj directive = SASS_MEMORY_NEW(AtRule, pstate, lexed);
|
|
2601
2442
|
String_Schema_Obj val = parse_almost_any_value();
|
|
2602
2443
|
// strip left and right if they are of type string
|
|
2603
2444
|
directive->value(val);
|
|
@@ -2607,34 +2448,35 @@ namespace Sass {
|
|
|
2607
2448
|
return directive;
|
|
2608
2449
|
}
|
|
2609
2450
|
|
|
2610
|
-
|
|
2451
|
+
ExpressionObj Parser::lex_interpolation()
|
|
2611
2452
|
{
|
|
2612
2453
|
if (lex < interpolant >(true) != NULL) {
|
|
2613
2454
|
return parse_interpolated_chunk(lexed, true);
|
|
2614
2455
|
}
|
|
2615
|
-
return
|
|
2456
|
+
return {};
|
|
2616
2457
|
}
|
|
2617
2458
|
|
|
2618
|
-
|
|
2459
|
+
ExpressionObj Parser::lex_interp_uri()
|
|
2619
2460
|
{
|
|
2620
2461
|
// create a string schema by lexing optional interpolations
|
|
2621
2462
|
return lex_interp< re_string_uri_open, re_string_uri_close >();
|
|
2622
2463
|
}
|
|
2623
2464
|
|
|
2624
|
-
|
|
2465
|
+
ExpressionObj Parser::lex_interp_string()
|
|
2625
2466
|
{
|
|
2626
|
-
|
|
2467
|
+
ExpressionObj rv;
|
|
2627
2468
|
if ((rv = lex_interp< re_string_double_open, re_string_double_close >())) return rv;
|
|
2628
2469
|
if ((rv = lex_interp< re_string_single_open, re_string_single_close >())) return rv;
|
|
2629
2470
|
return rv;
|
|
2630
2471
|
}
|
|
2631
2472
|
|
|
2632
|
-
|
|
2473
|
+
ExpressionObj Parser::lex_almost_any_value_chars()
|
|
2633
2474
|
{
|
|
2634
2475
|
const char* match =
|
|
2635
2476
|
lex <
|
|
2636
2477
|
one_plus <
|
|
2637
2478
|
alternatives <
|
|
2479
|
+
exactly <'>'>,
|
|
2638
2480
|
sequence <
|
|
2639
2481
|
exactly <'\\'>,
|
|
2640
2482
|
any_char
|
|
@@ -2678,30 +2520,32 @@ namespace Sass {
|
|
|
2678
2520
|
if (match) {
|
|
2679
2521
|
return SASS_MEMORY_NEW(String_Constant, pstate, lexed);
|
|
2680
2522
|
}
|
|
2681
|
-
return
|
|
2523
|
+
return {};
|
|
2682
2524
|
}
|
|
2683
2525
|
|
|
2684
|
-
|
|
2526
|
+
ExpressionObj Parser::lex_almost_any_value_token()
|
|
2685
2527
|
{
|
|
2686
|
-
|
|
2687
|
-
if (*position == 0) return
|
|
2528
|
+
ExpressionObj rv;
|
|
2529
|
+
if (*position == 0) return {};
|
|
2688
2530
|
if ((rv = lex_almost_any_value_chars())) return rv;
|
|
2689
2531
|
// if ((rv = lex_block_comment())) return rv;
|
|
2690
2532
|
// if ((rv = lex_single_line_comment())) return rv;
|
|
2691
2533
|
if ((rv = lex_interp_string())) return rv;
|
|
2692
2534
|
if ((rv = lex_interp_uri())) return rv;
|
|
2693
2535
|
if ((rv = lex_interpolation())) return rv;
|
|
2694
|
-
|
|
2536
|
+
if (lex< alternatives< hex, hex0 > >())
|
|
2537
|
+
{ return lexed_hex_color(lexed); }
|
|
2538
|
+
return rv;
|
|
2695
2539
|
}
|
|
2696
2540
|
|
|
2697
2541
|
String_Schema_Obj Parser::parse_almost_any_value()
|
|
2698
2542
|
{
|
|
2699
2543
|
|
|
2700
2544
|
String_Schema_Obj schema = SASS_MEMORY_NEW(String_Schema, pstate);
|
|
2701
|
-
if (*position == 0) return
|
|
2545
|
+
if (*position == 0) return {};
|
|
2702
2546
|
lex < spaces >(false);
|
|
2703
|
-
|
|
2704
|
-
if (!token) return
|
|
2547
|
+
ExpressionObj token = lex_almost_any_value_token();
|
|
2548
|
+
if (!token) return {};
|
|
2705
2549
|
schema->append(token);
|
|
2706
2550
|
if (*position == 0) {
|
|
2707
2551
|
schema->rtrim();
|
|
@@ -2719,7 +2563,7 @@ namespace Sass {
|
|
|
2719
2563
|
return schema.detach();
|
|
2720
2564
|
}
|
|
2721
2565
|
|
|
2722
|
-
|
|
2566
|
+
WarningRuleObj Parser::parse_warning()
|
|
2723
2567
|
{
|
|
2724
2568
|
if (stack.back() != Scope::Root &&
|
|
2725
2569
|
stack.back() != Scope::Function &&
|
|
@@ -2728,10 +2572,10 @@ namespace Sass {
|
|
|
2728
2572
|
stack.back() != Scope::Rules) {
|
|
2729
2573
|
error("Illegal nesting: Only properties may be nested beneath properties.");
|
|
2730
2574
|
}
|
|
2731
|
-
return SASS_MEMORY_NEW(
|
|
2575
|
+
return SASS_MEMORY_NEW(WarningRule, pstate, parse_list(DELAYED));
|
|
2732
2576
|
}
|
|
2733
2577
|
|
|
2734
|
-
|
|
2578
|
+
ErrorRuleObj Parser::parse_error()
|
|
2735
2579
|
{
|
|
2736
2580
|
if (stack.back() != Scope::Root &&
|
|
2737
2581
|
stack.back() != Scope::Function &&
|
|
@@ -2740,10 +2584,10 @@ namespace Sass {
|
|
|
2740
2584
|
stack.back() != Scope::Rules) {
|
|
2741
2585
|
error("Illegal nesting: Only properties may be nested beneath properties.");
|
|
2742
2586
|
}
|
|
2743
|
-
return SASS_MEMORY_NEW(
|
|
2587
|
+
return SASS_MEMORY_NEW(ErrorRule, pstate, parse_list(DELAYED));
|
|
2744
2588
|
}
|
|
2745
2589
|
|
|
2746
|
-
|
|
2590
|
+
DebugRuleObj Parser::parse_debug()
|
|
2747
2591
|
{
|
|
2748
2592
|
if (stack.back() != Scope::Root &&
|
|
2749
2593
|
stack.back() != Scope::Function &&
|
|
@@ -2752,7 +2596,7 @@ namespace Sass {
|
|
|
2752
2596
|
stack.back() != Scope::Rules) {
|
|
2753
2597
|
error("Illegal nesting: Only properties may be nested beneath properties.");
|
|
2754
2598
|
}
|
|
2755
|
-
return SASS_MEMORY_NEW(
|
|
2599
|
+
return SASS_MEMORY_NEW(DebugRule, pstate, parse_list(DELAYED));
|
|
2756
2600
|
}
|
|
2757
2601
|
|
|
2758
2602
|
Return_Obj Parser::parse_return_directive()
|
|
@@ -2777,6 +2621,7 @@ namespace Sass {
|
|
|
2777
2621
|
>(p)
|
|
2778
2622
|
) {
|
|
2779
2623
|
bool could_be_property = peek< sequence< exactly<'-'>, exactly<'-'> > >(p) != 0;
|
|
2624
|
+
bool could_be_escaped = false;
|
|
2780
2625
|
while (p < q) {
|
|
2781
2626
|
// did we have interpolations?
|
|
2782
2627
|
if (*p == '#' && *(p+1) == '{') {
|
|
@@ -2785,9 +2630,10 @@ namespace Sass {
|
|
|
2785
2630
|
}
|
|
2786
2631
|
// A property that's ambiguous with a nested selector is interpreted as a
|
|
2787
2632
|
// custom property.
|
|
2788
|
-
if (*p == ':') {
|
|
2633
|
+
if (*p == ':' && !could_be_escaped) {
|
|
2789
2634
|
rv.is_custom_property = could_be_property || p+1 == q || peek< space >(p+1);
|
|
2790
2635
|
}
|
|
2636
|
+
could_be_escaped = *p == '\\';
|
|
2791
2637
|
++ p;
|
|
2792
2638
|
}
|
|
2793
2639
|
// store anyway }
|
|
@@ -2797,7 +2643,7 @@ namespace Sass {
|
|
|
2797
2643
|
rv.error = q;
|
|
2798
2644
|
rv.position = q;
|
|
2799
2645
|
// check expected opening bracket
|
|
2800
|
-
// only after
|
|
2646
|
+
// only after successful matching
|
|
2801
2647
|
if (peek < exactly<'{'> >(q)) rv.found = q;
|
|
2802
2648
|
// else if (peek < end_of_file >(q)) rv.found = q;
|
|
2803
2649
|
else if (peek < exactly<'('> >(q)) rv.found = q;
|
|
@@ -2905,53 +2751,53 @@ namespace Sass {
|
|
|
2905
2751
|
void Parser::read_bom()
|
|
2906
2752
|
{
|
|
2907
2753
|
size_t skip = 0;
|
|
2908
|
-
|
|
2754
|
+
sass::string encoding;
|
|
2909
2755
|
bool utf_8 = false;
|
|
2910
|
-
switch ((unsigned char)
|
|
2756
|
+
switch ((unsigned char)position[0]) {
|
|
2911
2757
|
case 0xEF:
|
|
2912
|
-
skip = check_bom_chars(
|
|
2758
|
+
skip = check_bom_chars(position, end, utf_8_bom, 3);
|
|
2913
2759
|
encoding = "UTF-8";
|
|
2914
2760
|
utf_8 = true;
|
|
2915
2761
|
break;
|
|
2916
2762
|
case 0xFE:
|
|
2917
|
-
skip = check_bom_chars(
|
|
2763
|
+
skip = check_bom_chars(position, end, utf_16_bom_be, 2);
|
|
2918
2764
|
encoding = "UTF-16 (big endian)";
|
|
2919
2765
|
break;
|
|
2920
2766
|
case 0xFF:
|
|
2921
|
-
skip = check_bom_chars(
|
|
2922
|
-
skip += (skip ? check_bom_chars(
|
|
2767
|
+
skip = check_bom_chars(position, end, utf_16_bom_le, 2);
|
|
2768
|
+
skip += (skip ? check_bom_chars(position, end, utf_32_bom_le, 4) : 0);
|
|
2923
2769
|
encoding = (skip == 2 ? "UTF-16 (little endian)" : "UTF-32 (little endian)");
|
|
2924
2770
|
break;
|
|
2925
2771
|
case 0x00:
|
|
2926
|
-
skip = check_bom_chars(
|
|
2772
|
+
skip = check_bom_chars(position, end, utf_32_bom_be, 4);
|
|
2927
2773
|
encoding = "UTF-32 (big endian)";
|
|
2928
2774
|
break;
|
|
2929
2775
|
case 0x2B:
|
|
2930
|
-
skip = check_bom_chars(
|
|
2931
|
-
| check_bom_chars(
|
|
2932
|
-
| check_bom_chars(
|
|
2933
|
-
| check_bom_chars(
|
|
2934
|
-
| check_bom_chars(
|
|
2776
|
+
skip = check_bom_chars(position, end, utf_7_bom_1, 4)
|
|
2777
|
+
| check_bom_chars(position, end, utf_7_bom_2, 4)
|
|
2778
|
+
| check_bom_chars(position, end, utf_7_bom_3, 4)
|
|
2779
|
+
| check_bom_chars(position, end, utf_7_bom_4, 4)
|
|
2780
|
+
| check_bom_chars(position, end, utf_7_bom_5, 5);
|
|
2935
2781
|
encoding = "UTF-7";
|
|
2936
2782
|
break;
|
|
2937
2783
|
case 0xF7:
|
|
2938
|
-
skip = check_bom_chars(
|
|
2784
|
+
skip = check_bom_chars(position, end, utf_1_bom, 3);
|
|
2939
2785
|
encoding = "UTF-1";
|
|
2940
2786
|
break;
|
|
2941
2787
|
case 0xDD:
|
|
2942
|
-
skip = check_bom_chars(
|
|
2788
|
+
skip = check_bom_chars(position, end, utf_ebcdic_bom, 4);
|
|
2943
2789
|
encoding = "UTF-EBCDIC";
|
|
2944
2790
|
break;
|
|
2945
2791
|
case 0x0E:
|
|
2946
|
-
skip = check_bom_chars(
|
|
2792
|
+
skip = check_bom_chars(position, end, scsu_bom, 3);
|
|
2947
2793
|
encoding = "SCSU";
|
|
2948
2794
|
break;
|
|
2949
2795
|
case 0xFB:
|
|
2950
|
-
skip = check_bom_chars(
|
|
2796
|
+
skip = check_bom_chars(position, end, bocu_1_bom, 3);
|
|
2951
2797
|
encoding = "BOCU-1";
|
|
2952
2798
|
break;
|
|
2953
2799
|
case 0x84:
|
|
2954
|
-
skip = check_bom_chars(
|
|
2800
|
+
skip = check_bom_chars(position, end, gb_18030_bom, 4);
|
|
2955
2801
|
encoding = "GB-18030";
|
|
2956
2802
|
break;
|
|
2957
2803
|
default: break;
|
|
@@ -2971,7 +2817,7 @@ namespace Sass {
|
|
|
2971
2817
|
}
|
|
2972
2818
|
|
|
2973
2819
|
|
|
2974
|
-
|
|
2820
|
+
ExpressionObj Parser::fold_operands(ExpressionObj base, sass::vector<ExpressionObj>& operands, Operand op)
|
|
2975
2821
|
{
|
|
2976
2822
|
for (size_t i = 0, S = operands.size(); i < S; ++i) {
|
|
2977
2823
|
base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), op, base, operands[i]);
|
|
@@ -2979,9 +2825,9 @@ namespace Sass {
|
|
|
2979
2825
|
return base;
|
|
2980
2826
|
}
|
|
2981
2827
|
|
|
2982
|
-
|
|
2828
|
+
ExpressionObj Parser::fold_operands(ExpressionObj base, sass::vector<ExpressionObj>& operands, sass::vector<Operand>& ops, size_t i)
|
|
2983
2829
|
{
|
|
2984
|
-
if (
|
|
2830
|
+
if (String_Schema* schema = Cast<String_Schema>(base)) {
|
|
2985
2831
|
// return schema;
|
|
2986
2832
|
if (schema->has_interpolants()) {
|
|
2987
2833
|
if (i + 1 < operands.size() && (
|
|
@@ -2995,7 +2841,7 @@ namespace Sass {
|
|
|
2995
2841
|
|| (ops[0].operand == Sass_OP::LTE)
|
|
2996
2842
|
|| (ops[0].operand == Sass_OP::GTE)
|
|
2997
2843
|
)) {
|
|
2998
|
-
|
|
2844
|
+
ExpressionObj rhs = fold_operands(operands[i], operands, ops, i + 1);
|
|
2999
2845
|
rhs = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[0], schema, rhs);
|
|
3000
2846
|
return rhs;
|
|
3001
2847
|
}
|
|
@@ -3003,12 +2849,19 @@ namespace Sass {
|
|
|
3003
2849
|
}
|
|
3004
2850
|
}
|
|
3005
2851
|
|
|
2852
|
+
if (operands.size() > Constants::MaxCallStack) {
|
|
2853
|
+
// XXX: this is never hit via spec tests
|
|
2854
|
+
sass::ostream stm;
|
|
2855
|
+
stm << "Stack depth exceeded max of " << Constants::MaxCallStack;
|
|
2856
|
+
error(stm.str());
|
|
2857
|
+
}
|
|
2858
|
+
|
|
3006
2859
|
for (size_t S = operands.size(); i < S; ++i) {
|
|
3007
|
-
if (
|
|
2860
|
+
if (String_Schema* schema = Cast<String_Schema>(operands[i])) {
|
|
3008
2861
|
if (schema->has_interpolants()) {
|
|
3009
2862
|
if (i + 1 < S) {
|
|
3010
2863
|
// this whole branch is never hit via spec tests
|
|
3011
|
-
|
|
2864
|
+
ExpressionObj rhs = fold_operands(operands[i+1], operands, ops, i + 2);
|
|
3012
2865
|
rhs = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], schema, rhs);
|
|
3013
2866
|
base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], base, rhs);
|
|
3014
2867
|
return base;
|
|
@@ -3021,34 +2874,27 @@ namespace Sass {
|
|
|
3021
2874
|
} else {
|
|
3022
2875
|
base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], base, operands[i]);
|
|
3023
2876
|
}
|
|
3024
|
-
|
|
2877
|
+
Binary_Expression* b = Cast<Binary_Expression>(base.ptr());
|
|
3025
2878
|
if (b && ops[i].operand == Sass_OP::DIV && b->left()->is_delayed() && b->right()->is_delayed()) {
|
|
3026
2879
|
base->is_delayed(true);
|
|
3027
2880
|
}
|
|
3028
2881
|
}
|
|
3029
2882
|
// nested binary expression are never to be delayed
|
|
3030
|
-
if (
|
|
2883
|
+
if (Binary_Expression* b = Cast<Binary_Expression>(base)) {
|
|
3031
2884
|
if (Cast<Binary_Expression>(b->left())) base->set_delayed(false);
|
|
3032
2885
|
if (Cast<Binary_Expression>(b->right())) base->set_delayed(false);
|
|
3033
2886
|
}
|
|
3034
2887
|
return base;
|
|
3035
2888
|
}
|
|
3036
2889
|
|
|
3037
|
-
void Parser::error(
|
|
2890
|
+
void Parser::error(sass::string msg)
|
|
3038
2891
|
{
|
|
3039
|
-
Position p(pos.line ? pos : before_token);
|
|
3040
|
-
ParserState pstate(path, source, p, Offset(0, 0));
|
|
3041
2892
|
traces.push_back(Backtrace(pstate));
|
|
3042
2893
|
throw Exception::InvalidSass(pstate, traces, msg);
|
|
3043
2894
|
}
|
|
3044
2895
|
|
|
3045
|
-
void Parser::error(std::string msg)
|
|
3046
|
-
{
|
|
3047
|
-
error(msg, pstate);
|
|
3048
|
-
}
|
|
3049
|
-
|
|
3050
2896
|
// print a css parsing error with actual context information from parsed source
|
|
3051
|
-
void Parser::css_error(const
|
|
2897
|
+
void Parser::css_error(const sass::string& msg, const sass::string& prefix, const sass::string& middle, const bool trim)
|
|
3052
2898
|
{
|
|
3053
2899
|
int max_len = 18;
|
|
3054
2900
|
const char* end = this->end;
|
|
@@ -3057,13 +2903,13 @@ namespace Sass {
|
|
|
3057
2903
|
if (!pos) pos = position;
|
|
3058
2904
|
|
|
3059
2905
|
const char* last_pos(pos);
|
|
3060
|
-
if (last_pos >
|
|
3061
|
-
utf8::prior(last_pos,
|
|
2906
|
+
if (last_pos > begin) {
|
|
2907
|
+
utf8::prior(last_pos, begin);
|
|
3062
2908
|
}
|
|
3063
2909
|
// backup position to last significant char
|
|
3064
|
-
while (trim && last_pos >
|
|
3065
|
-
if (!
|
|
3066
|
-
utf8::prior(last_pos,
|
|
2910
|
+
while (trim && last_pos > begin&& last_pos < end) {
|
|
2911
|
+
if (!Util::ascii_isspace(static_cast<unsigned char>(*last_pos))) break;
|
|
2912
|
+
utf8::prior(last_pos, begin);
|
|
3067
2913
|
}
|
|
3068
2914
|
|
|
3069
2915
|
bool ellipsis_left = false;
|
|
@@ -3072,9 +2918,9 @@ namespace Sass {
|
|
|
3072
2918
|
|
|
3073
2919
|
if (*pos_left) utf8::next(pos_left, end);
|
|
3074
2920
|
if (*end_left) utf8::next(end_left, end);
|
|
3075
|
-
while (pos_left >
|
|
2921
|
+
while (pos_left > begin) {
|
|
3076
2922
|
if (utf8::distance(pos_left, end_left) >= max_len) {
|
|
3077
|
-
utf8::prior(pos_left,
|
|
2923
|
+
utf8::prior(pos_left, begin);
|
|
3078
2924
|
ellipsis_left = *(pos_left) != '\n' &&
|
|
3079
2925
|
*(pos_left) != '\r';
|
|
3080
2926
|
utf8::next(pos_left, end);
|
|
@@ -3082,13 +2928,13 @@ namespace Sass {
|
|
|
3082
2928
|
}
|
|
3083
2929
|
|
|
3084
2930
|
const char* prev = pos_left;
|
|
3085
|
-
utf8::prior(prev,
|
|
2931
|
+
utf8::prior(prev, begin);
|
|
3086
2932
|
if (*prev == '\r') break;
|
|
3087
2933
|
if (*prev == '\n') break;
|
|
3088
2934
|
pos_left = prev;
|
|
3089
2935
|
}
|
|
3090
|
-
if (pos_left <
|
|
3091
|
-
pos_left =
|
|
2936
|
+
if (pos_left < begin) {
|
|
2937
|
+
pos_left = begin;
|
|
3092
2938
|
}
|
|
3093
2939
|
|
|
3094
2940
|
bool ellipsis_right = false;
|
|
@@ -3106,14 +2952,12 @@ namespace Sass {
|
|
|
3106
2952
|
}
|
|
3107
2953
|
// if (*end_right == 0) end_right ++;
|
|
3108
2954
|
|
|
3109
|
-
|
|
3110
|
-
|
|
2955
|
+
sass::string left(pos_left, end_left);
|
|
2956
|
+
sass::string right(pos_right, end_right);
|
|
3111
2957
|
size_t left_subpos = left.size() > 15 ? left.size() - 15 : 0;
|
|
3112
2958
|
size_t right_subpos = right.size() > 15 ? right.size() - 15 : 0;
|
|
3113
2959
|
if (left_subpos && ellipsis_left) left = ellipsis + left.substr(left_subpos);
|
|
3114
2960
|
if (right_subpos && ellipsis_right) right = right.substr(right_subpos) + ellipsis;
|
|
3115
|
-
// Hotfix when source is null, probably due to interpolation parsing!?
|
|
3116
|
-
if (source == NULL || *source == 0) source = pstate.src;
|
|
3117
2961
|
// now pass new message to the more generic error function
|
|
3118
2962
|
error(msg + prefix + quote(left) + middle + quote(right));
|
|
3119
2963
|
}
|