sassc 1.11.4 → 1.12.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 +5 -5
- data/.travis.yml +2 -2
- data/CODE_OF_CONDUCT.md +10 -0
- data/README.md +4 -1
- data/ext/libsass/.editorconfig +1 -1
- data/ext/libsass/.github/CONTRIBUTING.md +7 -7
- data/ext/libsass/.github/ISSUE_TEMPLATE.md +31 -6
- data/ext/libsass/.gitignore +3 -0
- data/ext/libsass/.travis.yml +37 -18
- data/ext/libsass/GNUmakefile.am +23 -37
- data/ext/libsass/Makefile +10 -6
- data/ext/libsass/Makefile.conf +3 -0
- data/ext/libsass/Readme.md +68 -63
- data/ext/libsass/appveyor.yml +7 -3
- data/ext/libsass/configure.ac +10 -14
- data/ext/libsass/docs/api-context-internal.md +29 -21
- data/ext/libsass/docs/api-context.md +26 -6
- data/ext/libsass/docs/api-doc.md +49 -16
- data/ext/libsass/docs/api-function-example.md +1 -1
- data/ext/libsass/docs/api-function.md +31 -7
- data/ext/libsass/docs/api-importer.md +19 -19
- data/ext/libsass/docs/api-value.md +4 -2
- data/ext/libsass/docs/build-on-windows.md +4 -4
- data/ext/libsass/docs/build-with-mingw.md +3 -3
- data/ext/libsass/docs/build.md +9 -9
- data/ext/libsass/docs/custom-functions-internal.md +10 -8
- data/ext/libsass/docs/implementations.md +20 -8
- data/ext/libsass/docs/unicode.md +16 -10
- data/ext/libsass/include/sass/base.h +0 -3
- data/ext/libsass/include/sass/context.h +20 -2
- data/ext/libsass/include/sass/functions.h +31 -0
- data/ext/libsass/include/sass/values.h +3 -1
- data/ext/libsass/include/sass/version.h +1 -1
- data/ext/libsass/include/sass/version.h.in +1 -1
- data/ext/libsass/include/sass2scss.h +1 -1
- data/ext/libsass/res/resource.rc +6 -6
- data/ext/libsass/script/ci-build-libsass +10 -5
- data/ext/libsass/script/ci-build-plugin +62 -0
- data/ext/libsass/script/ci-install-compiler +1 -1
- data/ext/libsass/script/ci-install-deps +4 -7
- data/ext/libsass/script/ci-report-coverage +13 -3
- data/ext/libsass/script/tap-driver +1 -1
- data/ext/libsass/script/tap-runner +1 -1
- data/ext/libsass/src/GNUmakefile.am +1 -1
- data/ext/libsass/src/ast.cpp +537 -762
- data/ext/libsass/src/ast.hpp +377 -419
- data/ext/libsass/src/ast_def_macros.hpp +26 -1
- data/ext/libsass/src/ast_fwd_decl.cpp +29 -0
- data/ext/libsass/src/ast_fwd_decl.hpp +94 -21
- data/ext/libsass/src/b64/encode.h +3 -1
- data/ext/libsass/src/backtrace.cpp +46 -0
- data/ext/libsass/src/backtrace.hpp +7 -54
- data/ext/libsass/src/bind.cpp +72 -50
- data/ext/libsass/src/bind.hpp +0 -1
- data/ext/libsass/src/cencode.c +6 -0
- data/ext/libsass/src/check_nesting.cpp +157 -135
- data/ext/libsass/src/check_nesting.hpp +11 -10
- data/ext/libsass/src/color_maps.cpp +10 -6
- data/ext/libsass/src/color_maps.hpp +6 -8
- data/ext/libsass/src/constants.cpp +4 -3
- data/ext/libsass/src/constants.hpp +4 -3
- data/ext/libsass/src/context.cpp +110 -47
- data/ext/libsass/src/context.hpp +11 -1
- data/ext/libsass/src/cssize.cpp +105 -94
- data/ext/libsass/src/cssize.hpp +4 -5
- data/ext/libsass/src/debugger.hpp +247 -244
- data/ext/libsass/src/emitter.cpp +30 -6
- data/ext/libsass/src/emitter.hpp +7 -0
- data/ext/libsass/src/environment.cpp +67 -16
- data/ext/libsass/src/environment.hpp +28 -7
- data/ext/libsass/src/error_handling.cpp +92 -64
- data/ext/libsass/src/error_handling.hpp +64 -43
- data/ext/libsass/src/eval.cpp +494 -544
- data/ext/libsass/src/eval.hpp +17 -23
- data/ext/libsass/src/expand.cpp +182 -154
- data/ext/libsass/src/expand.hpp +4 -5
- data/ext/libsass/src/extend.cpp +299 -291
- data/ext/libsass/src/extend.hpp +46 -11
- data/ext/libsass/src/file.cpp +103 -36
- data/ext/libsass/src/file.hpp +21 -4
- data/ext/libsass/src/functions.cpp +561 -312
- data/ext/libsass/src/functions.hpp +8 -5
- data/ext/libsass/src/inspect.cpp +108 -53
- data/ext/libsass/src/inspect.hpp +5 -2
- data/ext/libsass/src/lexer.cpp +15 -7
- data/ext/libsass/src/lexer.hpp +13 -4
- data/ext/libsass/src/listize.cpp +3 -2
- data/ext/libsass/src/listize.hpp +0 -1
- data/ext/libsass/src/memory/SharedPtr.cpp +16 -18
- data/ext/libsass/src/memory/SharedPtr.hpp +47 -43
- data/ext/libsass/src/node.cpp +34 -38
- data/ext/libsass/src/node.hpp +6 -8
- data/ext/libsass/src/operation.hpp +2 -2
- data/ext/libsass/src/operators.cpp +240 -0
- data/ext/libsass/src/operators.hpp +30 -0
- data/ext/libsass/src/output.cpp +22 -20
- data/ext/libsass/src/parser.cpp +719 -358
- data/ext/libsass/src/parser.hpp +57 -22
- data/ext/libsass/src/plugins.cpp +28 -10
- data/ext/libsass/src/position.cpp +21 -3
- data/ext/libsass/src/position.hpp +2 -1
- data/ext/libsass/src/prelexer.cpp +104 -19
- data/ext/libsass/src/prelexer.hpp +10 -3
- data/ext/libsass/src/remove_placeholders.cpp +9 -10
- data/ext/libsass/src/remove_placeholders.hpp +1 -5
- data/ext/libsass/src/sass.cpp +62 -4
- data/ext/libsass/src/sass.hpp +5 -2
- data/ext/libsass/src/sass_context.cpp +96 -58
- data/ext/libsass/src/sass_context.hpp +7 -5
- data/ext/libsass/src/sass_functions.cpp +63 -1
- data/ext/libsass/src/sass_functions.hpp +19 -1
- data/ext/libsass/src/sass_util.cpp +3 -3
- data/ext/libsass/src/sass_util.hpp +4 -4
- data/ext/libsass/src/sass_values.cpp +42 -39
- data/ext/libsass/src/sass_values.hpp +2 -1
- data/ext/libsass/src/source_map.cpp +16 -18
- data/ext/libsass/src/subset_map.cpp +6 -8
- data/ext/libsass/src/subset_map.hpp +6 -6
- data/ext/libsass/src/to_c.cpp +2 -2
- data/ext/libsass/src/to_value.cpp +8 -3
- data/ext/libsass/src/to_value.hpp +1 -0
- data/ext/libsass/src/units.cpp +349 -45
- data/ext/libsass/src/units.hpp +39 -22
- data/ext/libsass/src/utf8/checked.h +7 -0
- data/ext/libsass/src/utf8/unchecked.h +7 -0
- data/ext/libsass/src/utf8_string.cpp +1 -1
- data/ext/libsass/src/util.cpp +139 -45
- data/ext/libsass/src/util.hpp +4 -7
- data/ext/libsass/src/values.cpp +15 -23
- data/ext/libsass/win/libsass.sln +13 -2
- data/ext/libsass/win/libsass.sln.DotSettings +9 -0
- data/ext/libsass/win/libsass.targets +3 -0
- data/ext/libsass/win/libsass.vcxproj.filters +9 -0
- data/lib/sassc/version.rb +1 -1
- data/sassc.gemspec +1 -1
- data/test/native_test.rb +1 -1
- metadata +11 -4
data/ext/libsass/src/parser.cpp
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
#include "sass.hpp"
|
|
2
|
-
#include <cstdlib>
|
|
3
|
-
#include <iostream>
|
|
4
|
-
#include <vector>
|
|
5
2
|
#include "parser.hpp"
|
|
6
3
|
#include "file.hpp"
|
|
7
4
|
#include "inspect.hpp"
|
|
@@ -24,18 +21,20 @@
|
|
|
24
21
|
// Another case with delayed values are colors. In compressed mode
|
|
25
22
|
// only processed values get compressed (other are left as written).
|
|
26
23
|
|
|
24
|
+
#include <cstdlib>
|
|
25
|
+
#include <iostream>
|
|
26
|
+
#include <vector>
|
|
27
27
|
#include <typeinfo>
|
|
28
|
-
#include <tuple>
|
|
29
28
|
|
|
30
29
|
namespace Sass {
|
|
31
30
|
using namespace Constants;
|
|
32
31
|
using namespace Prelexer;
|
|
33
32
|
|
|
34
|
-
Parser Parser::from_c_str(const char* beg, Context& ctx, ParserState pstate, const char* source)
|
|
33
|
+
Parser Parser::from_c_str(const char* beg, Context& ctx, Backtraces traces, ParserState pstate, const char* source)
|
|
35
34
|
{
|
|
36
35
|
pstate.offset.column = 0;
|
|
37
36
|
pstate.offset.line = 0;
|
|
38
|
-
Parser p(ctx, pstate);
|
|
37
|
+
Parser p(ctx, pstate, traces);
|
|
39
38
|
p.source = source ? source : beg;
|
|
40
39
|
p.position = beg ? beg : p.source;
|
|
41
40
|
p.end = p.position + strlen(p.position);
|
|
@@ -45,11 +44,11 @@ namespace Sass {
|
|
|
45
44
|
return p;
|
|
46
45
|
}
|
|
47
46
|
|
|
48
|
-
Parser Parser::from_c_str(const char* beg, const char* end, Context& ctx, ParserState pstate, const char* source)
|
|
47
|
+
Parser Parser::from_c_str(const char* beg, const char* end, Context& ctx, Backtraces traces, ParserState pstate, const char* source)
|
|
49
48
|
{
|
|
50
49
|
pstate.offset.column = 0;
|
|
51
50
|
pstate.offset.line = 0;
|
|
52
|
-
Parser p(ctx, pstate);
|
|
51
|
+
Parser p(ctx, pstate, traces);
|
|
53
52
|
p.source = source ? source : beg;
|
|
54
53
|
p.position = beg ? beg : p.source;
|
|
55
54
|
p.end = end ? end : p.position + strlen(p.position);
|
|
@@ -67,9 +66,9 @@ namespace Sass {
|
|
|
67
66
|
pstate.offset.line = 0;
|
|
68
67
|
}
|
|
69
68
|
|
|
70
|
-
Selector_List_Obj Parser::parse_selector(const char* beg, Context& ctx, ParserState pstate, const char* source)
|
|
69
|
+
Selector_List_Obj Parser::parse_selector(const char* beg, Context& ctx, Backtraces traces, ParserState pstate, const char* source)
|
|
71
70
|
{
|
|
72
|
-
Parser p = Parser::from_c_str(beg, ctx, pstate, source);
|
|
71
|
+
Parser p = Parser::from_c_str(beg, ctx, traces, pstate, source);
|
|
73
72
|
// ToDo: ruby sass errors on parent references
|
|
74
73
|
// ToDo: remap the source-map entries somehow
|
|
75
74
|
return p.parse_selector_list(false);
|
|
@@ -81,9 +80,9 @@ namespace Sass {
|
|
|
81
80
|
&& ! peek_css<exactly<'{'>>(start);
|
|
82
81
|
}
|
|
83
82
|
|
|
84
|
-
Parser Parser::from_token(Token t, Context& ctx, ParserState pstate, const char* source)
|
|
83
|
+
Parser Parser::from_token(Token t, Context& ctx, Backtraces traces, ParserState pstate, const char* source)
|
|
85
84
|
{
|
|
86
|
-
Parser p(ctx, pstate);
|
|
85
|
+
Parser p(ctx, pstate, traces);
|
|
87
86
|
p.source = source ? source : t.begin;
|
|
88
87
|
p.position = t.begin ? t.begin : p.source;
|
|
89
88
|
p.end = t.end ? t.end : p.position + strlen(p.position);
|
|
@@ -96,21 +95,35 @@ namespace Sass {
|
|
|
96
95
|
/* main entry point to parse root block */
|
|
97
96
|
Block_Obj Parser::parse()
|
|
98
97
|
{
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
|
|
99
|
+
// consume unicode BOM
|
|
101
100
|
read_bom();
|
|
102
101
|
|
|
103
|
-
//
|
|
102
|
+
// scan the input to find invalid utf8 sequences
|
|
103
|
+
const char* it = utf8::find_invalid(position, end);
|
|
104
|
+
|
|
105
|
+
// report invalid utf8
|
|
106
|
+
if (it != end) {
|
|
107
|
+
pstate += Offset::init(position, it);
|
|
108
|
+
traces.push_back(Backtrace(pstate));
|
|
109
|
+
throw Exception::InvalidSass(pstate, traces, "Invalid UTF-8 sequence");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// create a block AST node to hold children
|
|
113
|
+
Block_Obj root = SASS_MEMORY_NEW(Block, pstate, 0, true);
|
|
114
|
+
|
|
115
|
+
// check seems a bit esoteric but works
|
|
104
116
|
if (ctx.resources.size() == 1) {
|
|
105
|
-
|
|
106
|
-
ctx.apply_custom_headers(
|
|
117
|
+
// apply headers only on very first include
|
|
118
|
+
ctx.apply_custom_headers(root, path, pstate);
|
|
107
119
|
}
|
|
108
120
|
|
|
121
|
+
// parse children nodes
|
|
109
122
|
block_stack.push_back(root);
|
|
110
|
-
|
|
123
|
+
parse_block_nodes(true);
|
|
111
124
|
block_stack.pop_back();
|
|
112
125
|
|
|
113
|
-
// update
|
|
126
|
+
// update final position
|
|
114
127
|
root->update_pstate(pstate);
|
|
115
128
|
|
|
116
129
|
if (position != end) {
|
|
@@ -138,7 +151,7 @@ namespace Sass {
|
|
|
138
151
|
Block_Obj block = SASS_MEMORY_NEW(Block, pstate, 0, is_root);
|
|
139
152
|
block_stack.push_back(block);
|
|
140
153
|
|
|
141
|
-
if (!parse_block_nodes()) css_error("Invalid CSS", " after ", ": expected \"}\", was ");
|
|
154
|
+
if (!parse_block_nodes(is_root)) css_error("Invalid CSS", " after ", ": expected \"}\", was ");
|
|
142
155
|
|
|
143
156
|
if (!lex_css < exactly<'}'> >()) {
|
|
144
157
|
css_error("Invalid CSS", " after ", ": expected \"}\", was ");
|
|
@@ -154,7 +167,7 @@ namespace Sass {
|
|
|
154
167
|
|
|
155
168
|
block_stack.pop_back();
|
|
156
169
|
|
|
157
|
-
return
|
|
170
|
+
return block;
|
|
158
171
|
}
|
|
159
172
|
|
|
160
173
|
// convenience function for block parsing
|
|
@@ -162,7 +175,6 @@ namespace Sass {
|
|
|
162
175
|
// also updates the `in_at_root` flag
|
|
163
176
|
Block_Obj Parser::parse_block(bool is_root)
|
|
164
177
|
{
|
|
165
|
-
LOCAL_FLAG(in_at_root, is_root);
|
|
166
178
|
return parse_css_block(is_root);
|
|
167
179
|
}
|
|
168
180
|
|
|
@@ -214,27 +226,29 @@ namespace Sass {
|
|
|
214
226
|
// also parse block comments
|
|
215
227
|
|
|
216
228
|
// first parse everything that is allowed in functions
|
|
217
|
-
if (lex < variable >(true)) { block->append(
|
|
218
|
-
else if (lex < kwd_err >(true)) { block->append(
|
|
219
|
-
else if (lex < kwd_dbg >(true)) { block->append(
|
|
220
|
-
else if (lex < kwd_warn >(true)) { block->append(
|
|
221
|
-
else if (lex < kwd_if_directive >(true)) { block->append(
|
|
222
|
-
else if (lex < kwd_for_directive >(true)) { block->append(
|
|
223
|
-
else if (lex < kwd_each_directive >(true)) { block->append(
|
|
224
|
-
else if (lex < kwd_while_directive >(true)) { block->append(
|
|
225
|
-
else if (lex < kwd_return_directive >(true)) { block->append(
|
|
229
|
+
if (lex < variable >(true)) { block->append(parse_assignment()); }
|
|
230
|
+
else if (lex < kwd_err >(true)) { block->append(parse_error()); }
|
|
231
|
+
else if (lex < kwd_dbg >(true)) { block->append(parse_debug()); }
|
|
232
|
+
else if (lex < kwd_warn >(true)) { block->append(parse_warning()); }
|
|
233
|
+
else if (lex < kwd_if_directive >(true)) { block->append(parse_if_directive()); }
|
|
234
|
+
else if (lex < kwd_for_directive >(true)) { block->append(parse_for_directive()); }
|
|
235
|
+
else if (lex < kwd_each_directive >(true)) { block->append(parse_each_directive()); }
|
|
236
|
+
else if (lex < kwd_while_directive >(true)) { block->append(parse_while_directive()); }
|
|
237
|
+
else if (lex < kwd_return_directive >(true)) { block->append(parse_return_directive()); }
|
|
226
238
|
|
|
227
239
|
// parse imports to process later
|
|
228
240
|
else if (lex < kwd_import >(true)) {
|
|
229
241
|
Scope parent = stack.empty() ? Scope::Rules : stack.back();
|
|
230
242
|
if (parent != Scope::Function && parent != Scope::Root && parent != Scope::Rules && parent != Scope::Media) {
|
|
231
243
|
if (! peek_css< uri_prefix >(position)) { // this seems to go in ruby sass 3.4.20
|
|
232
|
-
error("Import directives may not be used within control directives or mixins."
|
|
244
|
+
error("Import directives may not be used within control directives or mixins.");
|
|
233
245
|
}
|
|
234
246
|
}
|
|
247
|
+
// this puts the parsed doc into sheets
|
|
248
|
+
// import stub will fetch this in expand
|
|
235
249
|
Import_Obj imp = parse_import();
|
|
236
250
|
// if it is a url, we only add the statement
|
|
237
|
-
if (!imp->urls().empty()) block->append(
|
|
251
|
+
if (!imp->urls().empty()) block->append(imp);
|
|
238
252
|
// process all resources now (add Import_Stub nodes)
|
|
239
253
|
for (size_t i = 0, S = imp->incs().size(); i < S; ++i) {
|
|
240
254
|
block->append(SASS_MEMORY_NEW(Import_Stub, pstate, imp->incs()[i]));
|
|
@@ -244,34 +258,45 @@ namespace Sass {
|
|
|
244
258
|
else if (lex < kwd_extend >(true)) {
|
|
245
259
|
Lookahead lookahead = lookahead_for_include(position);
|
|
246
260
|
if (!lookahead.found) css_error("Invalid CSS", " after ", ": expected selector, was ");
|
|
247
|
-
|
|
248
|
-
if (lookahead.has_interpolants)
|
|
249
|
-
|
|
250
|
-
|
|
261
|
+
Selector_List_Obj target;
|
|
262
|
+
if (!lookahead.has_interpolants) {
|
|
263
|
+
target = parse_selector_list(true);
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
target = SASS_MEMORY_NEW(Selector_List, pstate);
|
|
267
|
+
target->schema(parse_selector_schema(lookahead.found, true));
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
block->append(SASS_MEMORY_NEW(Extension, pstate, target));
|
|
251
271
|
}
|
|
252
272
|
|
|
253
273
|
// selector may contain interpolations which need delayed evaluation
|
|
254
|
-
else if (
|
|
255
|
-
|
|
274
|
+
else if (
|
|
275
|
+
!(lookahead_result = lookahead_for_selector(position)).error &&
|
|
276
|
+
!lookahead_result.is_custom_property
|
|
277
|
+
)
|
|
278
|
+
{
|
|
279
|
+
block->append(parse_ruleset(lookahead_result));
|
|
280
|
+
}
|
|
256
281
|
|
|
257
282
|
// parse multiple specific keyword directives
|
|
258
|
-
else if (lex < kwd_media >(true)) { block->append(
|
|
259
|
-
else if (lex < kwd_at_root >(true)) { block->append(
|
|
260
|
-
else if (lex < kwd_include_directive >(true)) { block->append(
|
|
261
|
-
else if (lex < kwd_content_directive >(true)) { block->append(
|
|
262
|
-
else if (lex < kwd_supports_directive >(true)) { block->append(
|
|
263
|
-
else if (lex < kwd_mixin >(true)) { block->append(
|
|
264
|
-
else if (lex < kwd_function >(true)) { block->append(
|
|
283
|
+
else if (lex < kwd_media >(true)) { block->append(parse_media_block()); }
|
|
284
|
+
else if (lex < kwd_at_root >(true)) { block->append(parse_at_root_block()); }
|
|
285
|
+
else if (lex < kwd_include_directive >(true)) { block->append(parse_include_directive()); }
|
|
286
|
+
else if (lex < kwd_content_directive >(true)) { block->append(parse_content_directive()); }
|
|
287
|
+
else if (lex < kwd_supports_directive >(true)) { block->append(parse_supports_directive()); }
|
|
288
|
+
else if (lex < kwd_mixin >(true)) { block->append(parse_definition(Definition::MIXIN)); }
|
|
289
|
+
else if (lex < kwd_function >(true)) { block->append(parse_definition(Definition::FUNCTION)); }
|
|
265
290
|
|
|
266
291
|
// ignore the @charset directive for now
|
|
267
292
|
else if (lex< kwd_charset_directive >(true)) { parse_charset_directive(); }
|
|
268
293
|
|
|
269
294
|
// generic at keyword (keep last)
|
|
270
|
-
else if (lex< re_special_directive >(true)) { block->append(
|
|
271
|
-
else if (lex< re_prefixed_directive >(true)) { block->append(
|
|
272
|
-
else if (lex< at_keyword >(true)) { block->append(
|
|
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
|
+
else if (lex< at_keyword >(true)) { block->append(parse_directive()); }
|
|
273
298
|
|
|
274
|
-
else if (is_root /* && block->is_root() */) {
|
|
299
|
+
else if (is_root && stack.back() != Scope::AtRoot /* && block->is_root() */) {
|
|
275
300
|
lex< css_whitespace >();
|
|
276
301
|
if (position >= end) return true;
|
|
277
302
|
css_error("Invalid CSS", " after ", ": expected 1 selector or at-rule, was ");
|
|
@@ -283,7 +308,7 @@ namespace Sass {
|
|
|
283
308
|
// maybe we are expected to parse something?
|
|
284
309
|
Declaration_Obj decl = parse_declaration();
|
|
285
310
|
decl->tabs(indentation);
|
|
286
|
-
block->append(
|
|
311
|
+
block->append(decl);
|
|
287
312
|
// maybe we have a "sub-block"
|
|
288
313
|
if (peek< exactly<'{'> >()) {
|
|
289
314
|
if (decl->is_indented()) ++ indentation;
|
|
@@ -312,28 +337,28 @@ namespace Sass {
|
|
|
312
337
|
}
|
|
313
338
|
else if (lex< uri_prefix >()) {
|
|
314
339
|
Arguments_Obj args = SASS_MEMORY_NEW(Arguments, pstate);
|
|
315
|
-
Function_Call_Obj result = SASS_MEMORY_NEW(Function_Call, pstate, "url",
|
|
340
|
+
Function_Call_Obj result = SASS_MEMORY_NEW(Function_Call, pstate, "url", args);
|
|
316
341
|
|
|
317
342
|
if (lex< quoted_string >()) {
|
|
318
|
-
Expression_Obj
|
|
319
|
-
args->append(SASS_MEMORY_NEW(Argument,
|
|
343
|
+
Expression_Obj quoted_url = parse_string();
|
|
344
|
+
args->append(SASS_MEMORY_NEW(Argument, quoted_url->pstate(), quoted_url));
|
|
320
345
|
}
|
|
321
|
-
else if (String_Obj
|
|
322
|
-
args->append(SASS_MEMORY_NEW(Argument,
|
|
346
|
+
else if (String_Obj string_url = parse_url_function_argument()) {
|
|
347
|
+
args->append(SASS_MEMORY_NEW(Argument, string_url->pstate(), string_url));
|
|
323
348
|
}
|
|
324
349
|
else if (peek < skip_over_scopes < exactly < '(' >, exactly < ')' > > >(position)) {
|
|
325
|
-
Expression_Obj
|
|
326
|
-
args->append(SASS_MEMORY_NEW(Argument,
|
|
350
|
+
Expression_Obj braced_url = parse_list(); // parse_interpolated_chunk(lexed);
|
|
351
|
+
args->append(SASS_MEMORY_NEW(Argument, braced_url->pstate(), braced_url));
|
|
327
352
|
}
|
|
328
353
|
else {
|
|
329
|
-
error("malformed URL"
|
|
354
|
+
error("malformed URL");
|
|
330
355
|
}
|
|
331
|
-
if (!lex< exactly<')'> >()) error("URI is missing ')'"
|
|
332
|
-
to_import.push_back(std::pair<std::string, Function_Call_Obj>("",
|
|
356
|
+
if (!lex< exactly<')'> >()) error("URI is missing ')'");
|
|
357
|
+
to_import.push_back(std::pair<std::string, Function_Call_Obj>("", result));
|
|
333
358
|
}
|
|
334
359
|
else {
|
|
335
|
-
if (first) error("@import directive requires a url or quoted path"
|
|
336
|
-
else error("expecting another url or quoted path in @import list"
|
|
360
|
+
if (first) error("@import directive requires a url or quoted path");
|
|
361
|
+
else error("expecting another url or quoted path in @import list");
|
|
337
362
|
}
|
|
338
363
|
first = false;
|
|
339
364
|
} while (lex_css< exactly<','> >());
|
|
@@ -345,9 +370,12 @@ namespace Sass {
|
|
|
345
370
|
|
|
346
371
|
for(auto location : to_import) {
|
|
347
372
|
if (location.second) {
|
|
348
|
-
imp->urls().push_back(
|
|
349
|
-
}
|
|
350
|
-
|
|
373
|
+
imp->urls().push_back(location.second);
|
|
374
|
+
}
|
|
375
|
+
// check if custom importers want to take over the handling
|
|
376
|
+
else if (!ctx.call_importers(unquote(location.first), path, pstate, imp)) {
|
|
377
|
+
// nobody wants it, so we do our import
|
|
378
|
+
ctx.import_url(imp, location.first, path);
|
|
351
379
|
}
|
|
352
380
|
}
|
|
353
381
|
|
|
@@ -357,37 +385,42 @@ namespace Sass {
|
|
|
357
385
|
Definition_Obj Parser::parse_definition(Definition::Type which_type)
|
|
358
386
|
{
|
|
359
387
|
std::string which_str(lexed);
|
|
360
|
-
if (!lex< identifier >()) error("invalid name in " + which_str + " definition"
|
|
388
|
+
if (!lex< identifier >()) error("invalid name in " + which_str + " definition");
|
|
361
389
|
std::string name(Util::normalize_underscores(lexed));
|
|
362
390
|
if (which_type == Definition::FUNCTION && (name == "and" || name == "or" || name == "not"))
|
|
363
|
-
{ error("Invalid function name \"" + name + "\"."
|
|
391
|
+
{ error("Invalid function name \"" + name + "\"."); }
|
|
364
392
|
ParserState source_position_of_def = pstate;
|
|
365
393
|
Parameters_Obj params = parse_parameters();
|
|
366
394
|
if (which_type == Definition::MIXIN) stack.push_back(Scope::Mixin);
|
|
367
395
|
else stack.push_back(Scope::Function);
|
|
368
396
|
Block_Obj body = parse_block();
|
|
369
397
|
stack.pop_back();
|
|
370
|
-
return SASS_MEMORY_NEW(Definition, source_position_of_def, name,
|
|
398
|
+
return SASS_MEMORY_NEW(Definition, source_position_of_def, name, params, body, which_type);
|
|
371
399
|
}
|
|
372
400
|
|
|
373
401
|
Parameters_Obj Parser::parse_parameters()
|
|
374
402
|
{
|
|
375
|
-
std::string name(lexed);
|
|
376
|
-
Position position = after_token;
|
|
377
403
|
Parameters_Obj params = SASS_MEMORY_NEW(Parameters, pstate);
|
|
378
404
|
if (lex_css< exactly<'('> >()) {
|
|
379
405
|
// if there's anything there at all
|
|
380
406
|
if (!peek_css< exactly<')'> >()) {
|
|
381
|
-
do
|
|
382
|
-
|
|
407
|
+
do {
|
|
408
|
+
if (peek< exactly<')'> >()) break;
|
|
409
|
+
params->append(parse_parameter());
|
|
410
|
+
} while (lex_css< exactly<','> >());
|
|
411
|
+
}
|
|
412
|
+
if (!lex_css< exactly<')'> >()) {
|
|
413
|
+
css_error("Invalid CSS", " after ", ": expected \")\", was ");
|
|
383
414
|
}
|
|
384
|
-
if (!lex_css< exactly<')'> >()) error("expected a variable name (e.g. $x) or ')' for the parameter list for " + name, position);
|
|
385
415
|
}
|
|
386
416
|
return params;
|
|
387
417
|
}
|
|
388
418
|
|
|
389
419
|
Parameter_Obj Parser::parse_parameter()
|
|
390
420
|
{
|
|
421
|
+
if (peek< alternatives< exactly<','>, exactly< '{' >, exactly<';'> > >()) {
|
|
422
|
+
css_error("Invalid CSS", " after ", ": expected variable (e.g. $foo), was ");
|
|
423
|
+
}
|
|
391
424
|
while (lex< alternatives < spaces, block_comment > >());
|
|
392
425
|
lex < variable >();
|
|
393
426
|
std::string name(Util::normalize_underscores(lexed));
|
|
@@ -402,27 +435,32 @@ namespace Sass {
|
|
|
402
435
|
else if (lex< exactly< ellipsis > >()) {
|
|
403
436
|
is_rest = true;
|
|
404
437
|
}
|
|
405
|
-
return SASS_MEMORY_NEW(Parameter, pos, name,
|
|
438
|
+
return SASS_MEMORY_NEW(Parameter, pos, name, val, is_rest);
|
|
406
439
|
}
|
|
407
440
|
|
|
408
441
|
Arguments_Obj Parser::parse_arguments()
|
|
409
442
|
{
|
|
410
|
-
std::string name(lexed);
|
|
411
|
-
Position position = after_token;
|
|
412
443
|
Arguments_Obj args = SASS_MEMORY_NEW(Arguments, pstate);
|
|
413
444
|
if (lex_css< exactly<'('> >()) {
|
|
414
445
|
// if there's anything there at all
|
|
415
446
|
if (!peek_css< exactly<')'> >()) {
|
|
416
|
-
do
|
|
417
|
-
|
|
447
|
+
do {
|
|
448
|
+
if (peek< exactly<')'> >()) break;
|
|
449
|
+
args->append(parse_argument());
|
|
450
|
+
} while (lex_css< exactly<','> >());
|
|
451
|
+
}
|
|
452
|
+
if (!lex_css< exactly<')'> >()) {
|
|
453
|
+
css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
|
|
418
454
|
}
|
|
419
|
-
if (!lex_css< exactly<')'> >()) error("expected a variable name (e.g. $x) or ')' for the parameter list for " + name, position);
|
|
420
455
|
}
|
|
421
456
|
return args;
|
|
422
457
|
}
|
|
423
458
|
|
|
424
459
|
Argument_Obj Parser::parse_argument()
|
|
425
460
|
{
|
|
461
|
+
if (peek< alternatives< exactly<','>, exactly< '{' >, exactly<';'> > >()) {
|
|
462
|
+
css_error("Invalid CSS", " after ", ": expected \")\", was ");
|
|
463
|
+
}
|
|
426
464
|
if (peek_css< sequence < exactly< hash_lbrace >, exactly< rbrace > > >()) {
|
|
427
465
|
position += 2;
|
|
428
466
|
css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
|
|
@@ -441,7 +479,7 @@ namespace Sass {
|
|
|
441
479
|
bool is_arglist = false;
|
|
442
480
|
bool is_keyword = false;
|
|
443
481
|
Expression_Obj val = parse_space_list();
|
|
444
|
-
List_Ptr l =
|
|
482
|
+
List_Ptr l = Cast<List>(val);
|
|
445
483
|
if (lex_css< exactly< ellipsis > >()) {
|
|
446
484
|
if (val->concrete_type() == Expression::MAP || (
|
|
447
485
|
(l != NULL && l->separator() == SASS_HASH)
|
|
@@ -457,14 +495,14 @@ namespace Sass {
|
|
|
457
495
|
{
|
|
458
496
|
std::string name(Util::normalize_underscores(lexed));
|
|
459
497
|
ParserState var_source_position = pstate;
|
|
460
|
-
if (!lex< exactly<':'> >()) error("expected ':' after " + name + " in assignment statement"
|
|
498
|
+
if (!lex< exactly<':'> >()) error("expected ':' after " + name + " in assignment statement");
|
|
461
499
|
if (peek_css< alternatives < exactly<';'>, end_of_file > >()) {
|
|
462
500
|
css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
|
|
463
501
|
}
|
|
464
502
|
Expression_Obj val;
|
|
465
503
|
Lookahead lookahead = lookahead_for_value(position);
|
|
466
504
|
if (lookahead.has_interpolants && lookahead.found) {
|
|
467
|
-
val =
|
|
505
|
+
val = parse_value_schema(lookahead.found);
|
|
468
506
|
} else {
|
|
469
507
|
val = parse_list();
|
|
470
508
|
}
|
|
@@ -478,15 +516,23 @@ namespace Sass {
|
|
|
478
516
|
}
|
|
479
517
|
|
|
480
518
|
// a ruleset connects a selector and a block
|
|
481
|
-
Ruleset_Obj Parser::parse_ruleset(Lookahead lookahead
|
|
519
|
+
Ruleset_Obj Parser::parse_ruleset(Lookahead lookahead)
|
|
482
520
|
{
|
|
521
|
+
NESTING_GUARD(nestings);
|
|
522
|
+
// inherit is_root from parent block
|
|
523
|
+
Block_Obj parent = block_stack.back();
|
|
524
|
+
bool is_root = parent && parent->is_root();
|
|
483
525
|
// make sure to move up the the last position
|
|
484
526
|
lex < optional_css_whitespace >(false, true);
|
|
485
527
|
// create the connector object (add parts later)
|
|
486
528
|
Ruleset_Obj ruleset = SASS_MEMORY_NEW(Ruleset, pstate);
|
|
487
529
|
// parse selector static or as schema to be evaluated later
|
|
488
|
-
if (lookahead.parsable) ruleset->selector(
|
|
489
|
-
else
|
|
530
|
+
if (lookahead.parsable) ruleset->selector(parse_selector_list(false));
|
|
531
|
+
else {
|
|
532
|
+
Selector_List_Obj list = SASS_MEMORY_NEW(Selector_List, pstate);
|
|
533
|
+
list->schema(parse_selector_schema(lookahead.position, false));
|
|
534
|
+
ruleset->selector(list);
|
|
535
|
+
}
|
|
490
536
|
// then parse the inner block
|
|
491
537
|
stack.push_back(Scope::Rules);
|
|
492
538
|
ruleset->block(parse_block());
|
|
@@ -494,7 +540,6 @@ namespace Sass {
|
|
|
494
540
|
// update for end position
|
|
495
541
|
ruleset->update_pstate(pstate);
|
|
496
542
|
ruleset->block()->update_pstate(pstate);
|
|
497
|
-
// inherit is_root from parent block
|
|
498
543
|
// need this info for sanity checks
|
|
499
544
|
ruleset->is_root(is_root);
|
|
500
545
|
// return AST Node
|
|
@@ -504,15 +549,17 @@ namespace Sass {
|
|
|
504
549
|
// parse a selector schema that will be evaluated in the eval stage
|
|
505
550
|
// uses a string schema internally to do the actual schema handling
|
|
506
551
|
// in the eval stage we will be re-parse it into an actual selector
|
|
507
|
-
Selector_Schema_Obj Parser::parse_selector_schema(const char* end_of_selector)
|
|
552
|
+
Selector_Schema_Obj Parser::parse_selector_schema(const char* end_of_selector, bool chroot)
|
|
508
553
|
{
|
|
554
|
+
NESTING_GUARD(nestings);
|
|
509
555
|
// move up to the start
|
|
510
556
|
lex< optional_spaces >();
|
|
511
557
|
const char* i = position;
|
|
512
558
|
// selector schema re-uses string schema implementation
|
|
513
559
|
String_Schema_Ptr schema = SASS_MEMORY_NEW(String_Schema, pstate);
|
|
514
560
|
// the selector schema is pretty much just a wrapper for the string schema
|
|
515
|
-
|
|
561
|
+
Selector_Schema_Obj selector_schema = SASS_MEMORY_NEW(Selector_Schema, pstate, schema);
|
|
562
|
+
selector_schema->connect_parent(chroot == false);
|
|
516
563
|
selector_schema->media_block(last_media_block);
|
|
517
564
|
|
|
518
565
|
// process until end
|
|
@@ -525,23 +572,24 @@ namespace Sass {
|
|
|
525
572
|
String_Constant_Obj str = SASS_MEMORY_NEW(String_Constant, pstate, parsed);
|
|
526
573
|
pstate += Offset(parsed);
|
|
527
574
|
str->update_pstate(pstate);
|
|
528
|
-
schema->append(
|
|
575
|
+
schema->append(str);
|
|
529
576
|
}
|
|
530
577
|
|
|
531
|
-
// check if the interpolation only contains white-space (error out)
|
|
532
|
-
if (peek < sequence < optional_spaces, exactly<rbrace> > >(p+2)) { position = p+2;
|
|
533
|
-
css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
|
|
534
|
-
}
|
|
535
578
|
// skip over all nested inner interpolations up to our own delimiter
|
|
536
579
|
const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p + 2, end_of_selector);
|
|
580
|
+
// check if the interpolation never ends of only contains white-space (error out)
|
|
581
|
+
if (!j || peek < sequence < optional_spaces, exactly<rbrace> > >(p+2)) {
|
|
582
|
+
position = p+2;
|
|
583
|
+
css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
|
|
584
|
+
}
|
|
537
585
|
// pass inner expression to the parser to resolve nested interpolations
|
|
538
586
|
pstate.add(p, p+2);
|
|
539
|
-
Expression_Obj interpolant = Parser::from_c_str(p+2, j, ctx, pstate).parse_list();
|
|
587
|
+
Expression_Obj interpolant = Parser::from_c_str(p+2, j, ctx, traces, pstate).parse_list();
|
|
540
588
|
// set status on the list expression
|
|
541
589
|
interpolant->is_interpolant(true);
|
|
542
590
|
// schema->has_interpolants(true);
|
|
543
591
|
// add to the string schema
|
|
544
|
-
schema->append(
|
|
592
|
+
schema->append(interpolant);
|
|
545
593
|
// advance parser state
|
|
546
594
|
pstate.add(p+2, j);
|
|
547
595
|
// advance position
|
|
@@ -557,7 +605,7 @@ namespace Sass {
|
|
|
557
605
|
pstate += Offset(parsed);
|
|
558
606
|
str->update_pstate(pstate);
|
|
559
607
|
i = end_of_selector;
|
|
560
|
-
schema->append(
|
|
608
|
+
schema->append(str);
|
|
561
609
|
}
|
|
562
610
|
// exit loop
|
|
563
611
|
}
|
|
@@ -574,7 +622,7 @@ namespace Sass {
|
|
|
574
622
|
after_token = before_token = pstate;
|
|
575
623
|
|
|
576
624
|
// return parsed result
|
|
577
|
-
return selector_schema;
|
|
625
|
+
return selector_schema.detach();
|
|
578
626
|
}
|
|
579
627
|
// EO parse_selector_schema
|
|
580
628
|
|
|
@@ -611,24 +659,29 @@ namespace Sass {
|
|
|
611
659
|
|
|
612
660
|
// parse a list of complex selectors
|
|
613
661
|
// this is the main entry point for most
|
|
614
|
-
Selector_List_Obj Parser::parse_selector_list(bool
|
|
662
|
+
Selector_List_Obj Parser::parse_selector_list(bool chroot)
|
|
615
663
|
{
|
|
616
|
-
bool reloop
|
|
664
|
+
bool reloop;
|
|
617
665
|
bool had_linefeed = false;
|
|
666
|
+
NESTING_GUARD(nestings);
|
|
618
667
|
Complex_Selector_Obj sel;
|
|
619
668
|
Selector_List_Obj group = SASS_MEMORY_NEW(Selector_List, pstate);
|
|
620
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
|
+
|
|
621
675
|
do {
|
|
622
676
|
reloop = false;
|
|
623
677
|
|
|
624
678
|
had_linefeed = had_linefeed || peek_newline();
|
|
625
679
|
|
|
626
|
-
if (peek_css< class_char < selector_list_delims > >())
|
|
680
|
+
if (peek_css< alternatives < class_char < selector_list_delims > > >())
|
|
627
681
|
break; // in case there are superfluous commas at the end
|
|
628
682
|
|
|
629
|
-
|
|
630
683
|
// now parse the complex selector
|
|
631
|
-
sel = parse_complex_selector(
|
|
684
|
+
sel = parse_complex_selector(chroot);
|
|
632
685
|
|
|
633
686
|
if (!sel) return group.detach();
|
|
634
687
|
|
|
@@ -662,14 +715,17 @@ namespace Sass {
|
|
|
662
715
|
// complex selector, with one of four combinator operations.
|
|
663
716
|
// the compound selector (head) is optional, since the combinator
|
|
664
717
|
// can come first in the whole selector sequence (like `> DIV').
|
|
665
|
-
Complex_Selector_Obj Parser::parse_complex_selector(bool
|
|
718
|
+
Complex_Selector_Obj Parser::parse_complex_selector(bool chroot)
|
|
666
719
|
{
|
|
667
720
|
|
|
668
|
-
|
|
721
|
+
NESTING_GUARD(nestings);
|
|
722
|
+
String_Obj reference = 0;
|
|
669
723
|
lex < block_comment >();
|
|
670
724
|
advanceToNextToken();
|
|
671
725
|
Complex_Selector_Obj sel = SASS_MEMORY_NEW(Complex_Selector, pstate);
|
|
672
726
|
|
|
727
|
+
if (peek < end_of_file >()) return 0;
|
|
728
|
+
|
|
673
729
|
// parse the left hand side
|
|
674
730
|
Compound_Selector_Obj lhs;
|
|
675
731
|
// special case if it starts with combinator ([+~>])
|
|
@@ -678,11 +734,9 @@ namespace Sass {
|
|
|
678
734
|
lhs = parse_compound_selector();
|
|
679
735
|
}
|
|
680
736
|
|
|
681
|
-
// check for end of file condition
|
|
682
|
-
if (peek < end_of_file >()) return 0;
|
|
683
737
|
|
|
684
738
|
// parse combinator between lhs and rhs
|
|
685
|
-
Complex_Selector::Combinator combinator;
|
|
739
|
+
Complex_Selector::Combinator combinator = Complex_Selector::ANCESTOR_OF;
|
|
686
740
|
if (lex< exactly<'+'> >()) combinator = Complex_Selector::ADJACENT_TO;
|
|
687
741
|
else if (lex< exactly<'~'> >()) combinator = Complex_Selector::PRECEDES;
|
|
688
742
|
else if (lex< exactly<'>'> >()) combinator = Complex_Selector::PARENT_OF;
|
|
@@ -693,7 +747,6 @@ namespace Sass {
|
|
|
693
747
|
reference = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
|
|
694
748
|
if (!lex < exactly < '/' > >()) return 0; // ToDo: error msg?
|
|
695
749
|
}
|
|
696
|
-
else /* if (lex< zero >()) */ combinator = Complex_Selector::ANCESTOR_OF;
|
|
697
750
|
|
|
698
751
|
if (!lhs && combinator == Complex_Selector::ANCESTOR_OF) return 0;
|
|
699
752
|
|
|
@@ -715,7 +768,7 @@ namespace Sass {
|
|
|
715
768
|
|
|
716
769
|
// add a parent selector if we are not in a root
|
|
717
770
|
// also skip adding parent ref if we only have refs
|
|
718
|
-
if (!sel->has_parent_ref() && !
|
|
771
|
+
if (!sel->has_parent_ref() && !chroot) {
|
|
719
772
|
// create the objects to wrap parent selector reference
|
|
720
773
|
Compound_Selector_Obj head = SASS_MEMORY_NEW(Compound_Selector, pstate);
|
|
721
774
|
Parent_Selector_Ptr parent = SASS_MEMORY_NEW(Parent_Selector, pstate, false);
|
|
@@ -760,7 +813,7 @@ namespace Sass {
|
|
|
760
813
|
// parse functional
|
|
761
814
|
if (match < re_pseudo_selector >())
|
|
762
815
|
{
|
|
763
|
-
seq->append(
|
|
816
|
+
seq->append(parse_simple_selector());
|
|
764
817
|
}
|
|
765
818
|
// parse parent selector
|
|
766
819
|
else if (lex< exactly<'&'> >(false))
|
|
@@ -795,11 +848,11 @@ namespace Sass {
|
|
|
795
848
|
else {
|
|
796
849
|
Simple_Selector_Obj sel = parse_simple_selector();
|
|
797
850
|
if (!sel) return 0;
|
|
798
|
-
seq->append(
|
|
851
|
+
seq->append(sel);
|
|
799
852
|
}
|
|
800
853
|
}
|
|
801
854
|
|
|
802
|
-
if (seq && !peek_css<exactly<'{'
|
|
855
|
+
if (seq && !peek_css<alternatives<end_of_file,exactly<'{'>>>()) {
|
|
803
856
|
seq->has_line_break(peek_newline());
|
|
804
857
|
}
|
|
805
858
|
|
|
@@ -818,29 +871,29 @@ namespace Sass {
|
|
|
818
871
|
else if (lex< id_name >()) {
|
|
819
872
|
return SASS_MEMORY_NEW(Id_Selector, pstate, lexed);
|
|
820
873
|
}
|
|
821
|
-
else if (lex< quoted_string >()) {
|
|
822
|
-
return SASS_MEMORY_NEW(Element_Selector, pstate, unquote(lexed));
|
|
823
|
-
}
|
|
824
874
|
else if (lex< alternatives < variable, number, static_reference_combinator > >()) {
|
|
825
875
|
return SASS_MEMORY_NEW(Element_Selector, pstate, lexed);
|
|
826
876
|
}
|
|
827
877
|
else if (peek< pseudo_not >()) {
|
|
828
|
-
return
|
|
878
|
+
return parse_negated_selector();
|
|
829
879
|
}
|
|
830
880
|
else if (peek< re_pseudo_selector >()) {
|
|
831
|
-
return
|
|
881
|
+
return parse_pseudo_selector();
|
|
832
882
|
}
|
|
833
883
|
else if (peek< exactly<':'> >()) {
|
|
834
|
-
return
|
|
884
|
+
return parse_pseudo_selector();
|
|
835
885
|
}
|
|
836
886
|
else if (lex < exactly<'['> >()) {
|
|
837
|
-
return
|
|
887
|
+
return parse_attribute_selector();
|
|
838
888
|
}
|
|
839
889
|
else if (lex< placeholder >()) {
|
|
840
890
|
Placeholder_Selector_Ptr sel = SASS_MEMORY_NEW(Placeholder_Selector, pstate, lexed);
|
|
841
891
|
sel->media_block(last_media_block);
|
|
842
892
|
return sel;
|
|
843
893
|
}
|
|
894
|
+
else {
|
|
895
|
+
css_error("Invalid CSS", " after ", ": expected selector, was ");
|
|
896
|
+
}
|
|
844
897
|
// failed
|
|
845
898
|
return 0;
|
|
846
899
|
}
|
|
@@ -852,10 +905,10 @@ namespace Sass {
|
|
|
852
905
|
ParserState nsource_position = pstate;
|
|
853
906
|
Selector_List_Obj negated = parse_selector_list(true);
|
|
854
907
|
if (!lex< exactly<')'> >()) {
|
|
855
|
-
error("negated selector is missing ')'"
|
|
908
|
+
error("negated selector is missing ')'");
|
|
856
909
|
}
|
|
857
910
|
name.erase(name.size() - 1);
|
|
858
|
-
return SASS_MEMORY_NEW(Wrapped_Selector, nsource_position, name,
|
|
911
|
+
return SASS_MEMORY_NEW(Wrapped_Selector, nsource_position, name, negated);
|
|
859
912
|
}
|
|
860
913
|
|
|
861
914
|
// a pseudo selector often starts with one or two colons
|
|
@@ -888,15 +941,15 @@ namespace Sass {
|
|
|
888
941
|
>()
|
|
889
942
|
) {
|
|
890
943
|
lex_css< alternatives < static_value, binomial > >();
|
|
891
|
-
|
|
892
|
-
if (
|
|
944
|
+
String_Constant_Obj expr = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
|
|
945
|
+
if (lex_css< exactly<')'> >()) {
|
|
893
946
|
expr->can_compress_whitespace(true);
|
|
894
947
|
return SASS_MEMORY_NEW(Pseudo_Selector, p, name, expr);
|
|
895
948
|
}
|
|
896
949
|
}
|
|
897
950
|
else if (Selector_List_Obj wrapped = parse_selector_list(true)) {
|
|
898
951
|
if (wrapped && lex_css< exactly<')'> >()) {
|
|
899
|
-
return SASS_MEMORY_NEW(Wrapped_Selector, p, name,
|
|
952
|
+
return SASS_MEMORY_NEW(Wrapped_Selector, p, name, wrapped);
|
|
900
953
|
}
|
|
901
954
|
}
|
|
902
955
|
|
|
@@ -916,15 +969,31 @@ namespace Sass {
|
|
|
916
969
|
return 0;
|
|
917
970
|
}
|
|
918
971
|
|
|
972
|
+
const char* Parser::re_attr_sensitive_close(const char* src)
|
|
973
|
+
{
|
|
974
|
+
return alternatives < exactly<']'>, exactly<'/'> >(src);
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
const char* Parser::re_attr_insensitive_close(const char* src)
|
|
978
|
+
{
|
|
979
|
+
return sequence < insensitive<'i'>, re_attr_sensitive_close >(src);
|
|
980
|
+
}
|
|
981
|
+
|
|
919
982
|
Attribute_Selector_Obj Parser::parse_attribute_selector()
|
|
920
983
|
{
|
|
921
984
|
ParserState p = pstate;
|
|
922
|
-
if (!lex_css< attribute_name >()) error("invalid attribute name in attribute selector"
|
|
985
|
+
if (!lex_css< attribute_name >()) error("invalid attribute name in attribute selector");
|
|
923
986
|
std::string name(lexed);
|
|
924
|
-
if (lex_css<
|
|
987
|
+
if (lex_css< re_attr_sensitive_close >()) {
|
|
988
|
+
return SASS_MEMORY_NEW(Attribute_Selector, p, name, "", 0, 0);
|
|
989
|
+
}
|
|
990
|
+
else if (lex_css< re_attr_insensitive_close >()) {
|
|
991
|
+
char modifier = lexed.begin[0];
|
|
992
|
+
return SASS_MEMORY_NEW(Attribute_Selector, p, name, "", 0, modifier);
|
|
993
|
+
}
|
|
925
994
|
if (!lex_css< alternatives< exact_match, class_match, dash_match,
|
|
926
995
|
prefix_match, suffix_match, substring_match > >()) {
|
|
927
|
-
error("invalid operator in attribute selector for " + name
|
|
996
|
+
error("invalid operator in attribute selector for " + name);
|
|
928
997
|
}
|
|
929
998
|
std::string matcher(lexed);
|
|
930
999
|
|
|
@@ -933,14 +1002,21 @@ namespace Sass {
|
|
|
933
1002
|
value = SASS_MEMORY_NEW(String_Constant, p, lexed);
|
|
934
1003
|
}
|
|
935
1004
|
else if (lex_css< quoted_string >()) {
|
|
936
|
-
value =
|
|
1005
|
+
value = parse_interpolated_chunk(lexed, true); // needed!
|
|
937
1006
|
}
|
|
938
1007
|
else {
|
|
939
|
-
error("expected a string constant or identifier in attribute selector for " + name
|
|
1008
|
+
error("expected a string constant or identifier in attribute selector for " + name);
|
|
940
1009
|
}
|
|
941
1010
|
|
|
942
|
-
if (
|
|
943
|
-
|
|
1011
|
+
if (lex_css< re_attr_sensitive_close >()) {
|
|
1012
|
+
return SASS_MEMORY_NEW(Attribute_Selector, p, name, matcher, value, 0);
|
|
1013
|
+
}
|
|
1014
|
+
else if (lex_css< re_attr_insensitive_close >()) {
|
|
1015
|
+
char modifier = lexed.begin[0];
|
|
1016
|
+
return SASS_MEMORY_NEW(Attribute_Selector, p, name, matcher, value, modifier);
|
|
1017
|
+
}
|
|
1018
|
+
error("unterminated attribute selector for " + name);
|
|
1019
|
+
return NULL; // to satisfy compilers (error must not return)
|
|
944
1020
|
}
|
|
945
1021
|
|
|
946
1022
|
/* parse block comment and add to block */
|
|
@@ -951,17 +1027,22 @@ namespace Sass {
|
|
|
951
1027
|
while (lex< block_comment >()) {
|
|
952
1028
|
bool is_important = lexed.begin[2] == '!';
|
|
953
1029
|
// flag on second param is to skip loosely over comments
|
|
954
|
-
String_Obj contents = parse_interpolated_chunk(lexed, true);
|
|
1030
|
+
String_Obj contents = parse_interpolated_chunk(lexed, true, false);
|
|
955
1031
|
block->append(SASS_MEMORY_NEW(Comment, pstate, contents, is_important));
|
|
956
1032
|
}
|
|
957
1033
|
}
|
|
958
1034
|
|
|
959
1035
|
Declaration_Obj Parser::parse_declaration() {
|
|
960
1036
|
String_Obj prop;
|
|
1037
|
+
bool is_custom_property = false;
|
|
961
1038
|
if (lex< sequence< optional< exactly<'*'> >, identifier_schema > >()) {
|
|
1039
|
+
const std::string property(lexed);
|
|
1040
|
+
is_custom_property = property.compare(0, 2, "--") == 0;
|
|
962
1041
|
prop = parse_identifier_schema();
|
|
963
1042
|
}
|
|
964
1043
|
else if (lex< sequence< optional< exactly<'*'> >, identifier, zero_plus< block_comment > > >()) {
|
|
1044
|
+
const std::string property(lexed);
|
|
1045
|
+
is_custom_property = property.compare(0, 2, "--") == 0;
|
|
965
1046
|
prop = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
|
|
966
1047
|
}
|
|
967
1048
|
else {
|
|
@@ -969,27 +1050,30 @@ namespace Sass {
|
|
|
969
1050
|
}
|
|
970
1051
|
bool is_indented = true;
|
|
971
1052
|
const std::string property(lexed);
|
|
972
|
-
if (!lex_css< one_plus< exactly<':'> > >()) error("property \"" + property
|
|
1053
|
+
if (!lex_css< one_plus< exactly<':'> > >()) error("property \"" + escape_string(property) + "\" must be followed by a ':'");
|
|
1054
|
+
if (!is_custom_property && match< sequence< optional_css_comments, exactly<';'> > >()) error("style declaration must contain a value");
|
|
1055
|
+
if (match< sequence< optional_css_comments, exactly<'{'> > >()) is_indented = false; // don't indent if value is empty
|
|
1056
|
+
if (is_custom_property) {
|
|
1057
|
+
return SASS_MEMORY_NEW(Declaration, prop->pstate(), prop, parse_css_variable_value(), false, true);
|
|
1058
|
+
}
|
|
973
1059
|
lex < css_comments >(false);
|
|
974
|
-
if (peek_css< exactly<';'> >()) error("style declaration must contain a value", pstate);
|
|
975
|
-
if (peek_css< exactly<'{'> >()) is_indented = false; // don't indent if value is empty
|
|
976
1060
|
if (peek_css< static_value >()) {
|
|
977
|
-
return SASS_MEMORY_NEW(Declaration, prop->pstate(), prop,
|
|
1061
|
+
return SASS_MEMORY_NEW(Declaration, prop->pstate(), prop, parse_static_value()/*, lex<kwd_important>()*/);
|
|
978
1062
|
}
|
|
979
1063
|
else {
|
|
980
1064
|
Expression_Obj value;
|
|
981
1065
|
Lookahead lookahead = lookahead_for_value(position);
|
|
982
1066
|
if (lookahead.found) {
|
|
983
1067
|
if (lookahead.has_interpolants) {
|
|
984
|
-
value =
|
|
1068
|
+
value = parse_value_schema(lookahead.found);
|
|
985
1069
|
} else {
|
|
986
|
-
value =
|
|
1070
|
+
value = parse_list(DELAYED);
|
|
987
1071
|
}
|
|
988
1072
|
}
|
|
989
1073
|
else {
|
|
990
|
-
value =
|
|
991
|
-
if (List_Ptr list =
|
|
992
|
-
if (list->length() == 0 && !peek< exactly <'{'> >()) {
|
|
1074
|
+
value = parse_list(DELAYED);
|
|
1075
|
+
if (List_Ptr list = Cast<List>(value)) {
|
|
1076
|
+
if (!list->is_bracketed() && list->length() == 0 && !peek< exactly <'{'> >()) {
|
|
993
1077
|
css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
|
|
994
1078
|
}
|
|
995
1079
|
}
|
|
@@ -1003,6 +1087,7 @@ namespace Sass {
|
|
|
1003
1087
|
}
|
|
1004
1088
|
|
|
1005
1089
|
// parse +/- and return false if negative
|
|
1090
|
+
// this is never hit via spec tests
|
|
1006
1091
|
bool Parser::parse_number_prefix()
|
|
1007
1092
|
{
|
|
1008
1093
|
bool positive = true;
|
|
@@ -1020,6 +1105,7 @@ namespace Sass {
|
|
|
1020
1105
|
|
|
1021
1106
|
Expression_Obj Parser::parse_map()
|
|
1022
1107
|
{
|
|
1108
|
+
NESTING_GUARD(nestings);
|
|
1023
1109
|
Expression_Obj key = parse_list();
|
|
1024
1110
|
List_Obj map = SASS_MEMORY_NEW(List, pstate, 0, SASS_HASH);
|
|
1025
1111
|
|
|
@@ -1027,6 +1113,11 @@ namespace Sass {
|
|
|
1027
1113
|
if (!lex_css< exactly<':'> >())
|
|
1028
1114
|
{ return key; }
|
|
1029
1115
|
|
|
1116
|
+
List_Obj l = Cast<List>(key);
|
|
1117
|
+
if (l && l->separator() == SASS_COMMA) {
|
|
1118
|
+
css_error("Invalid CSS", " after ", ": expected \")\", was ");
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1030
1121
|
Expression_Obj value = parse_space_list();
|
|
1031
1122
|
|
|
1032
1123
|
map->append(key);
|
|
@@ -1038,12 +1129,12 @@ namespace Sass {
|
|
|
1038
1129
|
if (peek_css< exactly<')'> >(position))
|
|
1039
1130
|
{ break; }
|
|
1040
1131
|
|
|
1041
|
-
|
|
1132
|
+
key = parse_space_list();
|
|
1042
1133
|
|
|
1043
1134
|
if (!(lex< exactly<':'> >()))
|
|
1044
1135
|
{ css_error("Invalid CSS", " after ", ": expected \":\", was "); }
|
|
1045
1136
|
|
|
1046
|
-
|
|
1137
|
+
value = parse_space_list();
|
|
1047
1138
|
|
|
1048
1139
|
map->append(key);
|
|
1049
1140
|
map->append(value);
|
|
@@ -1053,7 +1144,51 @@ namespace Sass {
|
|
|
1053
1144
|
ps.offset = pstate - ps + pstate.offset;
|
|
1054
1145
|
map->pstate(ps);
|
|
1055
1146
|
|
|
1056
|
-
return
|
|
1147
|
+
return map;
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
Expression_Obj Parser::parse_bracket_list()
|
|
1151
|
+
{
|
|
1152
|
+
NESTING_GUARD(nestings);
|
|
1153
|
+
// check if we have an empty list
|
|
1154
|
+
// return the empty list as such
|
|
1155
|
+
if (peek_css< list_terminator >(position))
|
|
1156
|
+
{
|
|
1157
|
+
// return an empty list (nothing to delay)
|
|
1158
|
+
return SASS_MEMORY_NEW(List, pstate, 0, SASS_SPACE, false, true);
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
bool has_paren = peek_css< exactly<'('> >() != NULL;
|
|
1162
|
+
|
|
1163
|
+
// now try to parse a space list
|
|
1164
|
+
Expression_Obj list = parse_space_list();
|
|
1165
|
+
// if it's a singleton, return it (don't wrap it)
|
|
1166
|
+
if (!peek_css< exactly<','> >(position)) {
|
|
1167
|
+
List_Obj l = Cast<List>(list);
|
|
1168
|
+
if (!l || l->is_bracketed() || has_paren) {
|
|
1169
|
+
List_Obj bracketed_list = SASS_MEMORY_NEW(List, pstate, 1, SASS_SPACE, false, true);
|
|
1170
|
+
bracketed_list->append(list);
|
|
1171
|
+
return bracketed_list;
|
|
1172
|
+
}
|
|
1173
|
+
l->is_bracketed(true);
|
|
1174
|
+
return l;
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
// if we got so far, we actually do have a comma list
|
|
1178
|
+
List_Obj bracketed_list = SASS_MEMORY_NEW(List, pstate, 2, SASS_COMMA, false, true);
|
|
1179
|
+
// wrap the first expression
|
|
1180
|
+
bracketed_list->append(list);
|
|
1181
|
+
|
|
1182
|
+
while (lex_css< exactly<','> >())
|
|
1183
|
+
{
|
|
1184
|
+
// check for abort condition
|
|
1185
|
+
if (peek_css< list_terminator >(position)
|
|
1186
|
+
) { break; }
|
|
1187
|
+
// otherwise add another expression
|
|
1188
|
+
bracketed_list->append(parse_space_list());
|
|
1189
|
+
}
|
|
1190
|
+
// return the list
|
|
1191
|
+
return bracketed_list;
|
|
1057
1192
|
}
|
|
1058
1193
|
|
|
1059
1194
|
// parse list returns either a space separated list,
|
|
@@ -1061,26 +1196,17 @@ namespace Sass {
|
|
|
1061
1196
|
// so to speak: we unwrap items from lists if possible here!
|
|
1062
1197
|
Expression_Obj Parser::parse_list(bool delayed)
|
|
1063
1198
|
{
|
|
1199
|
+
NESTING_GUARD(nestings);
|
|
1064
1200
|
return parse_comma_list(delayed);
|
|
1065
1201
|
}
|
|
1066
1202
|
|
|
1067
1203
|
// will return singletons unwrapped
|
|
1068
1204
|
Expression_Obj Parser::parse_comma_list(bool delayed)
|
|
1069
1205
|
{
|
|
1206
|
+
NESTING_GUARD(nestings);
|
|
1070
1207
|
// check if we have an empty list
|
|
1071
1208
|
// return the empty list as such
|
|
1072
|
-
if (peek_css<
|
|
1073
|
-
// exactly<'!'>,
|
|
1074
|
-
exactly<';'>,
|
|
1075
|
-
exactly<'}'>,
|
|
1076
|
-
exactly<'{'>,
|
|
1077
|
-
exactly<')'>,
|
|
1078
|
-
exactly<':'>,
|
|
1079
|
-
end_of_file,
|
|
1080
|
-
exactly<ellipsis>,
|
|
1081
|
-
default_flag,
|
|
1082
|
-
global_flag
|
|
1083
|
-
> >(position))
|
|
1209
|
+
if (peek_css< list_terminator >(position))
|
|
1084
1210
|
{
|
|
1085
1211
|
// return an empty list (nothing to delay)
|
|
1086
1212
|
return SASS_MEMORY_NEW(List, pstate, 0);
|
|
@@ -1104,74 +1230,45 @@ namespace Sass {
|
|
|
1104
1230
|
while (lex_css< exactly<','> >())
|
|
1105
1231
|
{
|
|
1106
1232
|
// check for abort condition
|
|
1107
|
-
if (peek_css<
|
|
1108
|
-
exactly<';'>,
|
|
1109
|
-
exactly<'}'>,
|
|
1110
|
-
exactly<'{'>,
|
|
1111
|
-
exactly<')'>,
|
|
1112
|
-
exactly<':'>,
|
|
1113
|
-
end_of_file,
|
|
1114
|
-
exactly<ellipsis>,
|
|
1115
|
-
default_flag,
|
|
1116
|
-
global_flag
|
|
1117
|
-
> >(position)
|
|
1233
|
+
if (peek_css< list_terminator >(position)
|
|
1118
1234
|
) { break; }
|
|
1119
1235
|
// otherwise add another expression
|
|
1120
1236
|
comma_list->append(parse_space_list());
|
|
1121
1237
|
}
|
|
1122
1238
|
// return the list
|
|
1123
|
-
return
|
|
1239
|
+
return comma_list;
|
|
1124
1240
|
}
|
|
1125
1241
|
// EO parse_comma_list
|
|
1126
1242
|
|
|
1127
1243
|
// will return singletons unwrapped
|
|
1128
1244
|
Expression_Obj Parser::parse_space_list()
|
|
1129
1245
|
{
|
|
1246
|
+
NESTING_GUARD(nestings);
|
|
1130
1247
|
Expression_Obj disj1 = parse_disjunction();
|
|
1131
1248
|
// if it's a singleton, return it (don't wrap it)
|
|
1132
|
-
if (peek_css<
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
exactly<'}'>,
|
|
1136
|
-
exactly<'{'>,
|
|
1137
|
-
exactly<')'>,
|
|
1138
|
-
exactly<','>,
|
|
1139
|
-
exactly<':'>,
|
|
1140
|
-
end_of_file,
|
|
1141
|
-
exactly<ellipsis>,
|
|
1142
|
-
default_flag,
|
|
1143
|
-
global_flag
|
|
1144
|
-
> >(position)
|
|
1145
|
-
) { return disj1; }
|
|
1249
|
+
if (peek_css< space_list_terminator >(position)
|
|
1250
|
+
) {
|
|
1251
|
+
return disj1; }
|
|
1146
1252
|
|
|
1147
1253
|
List_Obj space_list = SASS_MEMORY_NEW(List, pstate, 2, SASS_SPACE);
|
|
1148
1254
|
space_list->append(disj1);
|
|
1149
1255
|
|
|
1150
|
-
while (
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
exactly<'}'>,
|
|
1154
|
-
exactly<'{'>,
|
|
1155
|
-
exactly<')'>,
|
|
1156
|
-
exactly<','>,
|
|
1157
|
-
exactly<':'>,
|
|
1158
|
-
end_of_file,
|
|
1159
|
-
exactly<ellipsis>,
|
|
1160
|
-
default_flag,
|
|
1161
|
-
global_flag
|
|
1162
|
-
> >(position)) && peek_css< optional_css_whitespace >() != end
|
|
1256
|
+
while (
|
|
1257
|
+
!(peek_css< space_list_terminator >(position)) &&
|
|
1258
|
+
peek_css< optional_css_whitespace >() != end
|
|
1163
1259
|
) {
|
|
1164
1260
|
// the space is parsed implicitly?
|
|
1165
1261
|
space_list->append(parse_disjunction());
|
|
1166
1262
|
}
|
|
1167
1263
|
// return the list
|
|
1168
|
-
return
|
|
1264
|
+
return space_list;
|
|
1169
1265
|
}
|
|
1170
1266
|
// EO parse_space_list
|
|
1171
1267
|
|
|
1172
1268
|
// parse logical OR operation
|
|
1173
1269
|
Expression_Obj Parser::parse_disjunction()
|
|
1174
1270
|
{
|
|
1271
|
+
NESTING_GUARD(nestings);
|
|
1175
1272
|
advanceToNextToken();
|
|
1176
1273
|
ParserState state(pstate);
|
|
1177
1274
|
// parse the left hand side conjunction
|
|
@@ -1193,6 +1290,7 @@ namespace Sass {
|
|
|
1193
1290
|
// parse logical AND operation
|
|
1194
1291
|
Expression_Obj Parser::parse_conjunction()
|
|
1195
1292
|
{
|
|
1293
|
+
NESTING_GUARD(nestings);
|
|
1196
1294
|
advanceToNextToken();
|
|
1197
1295
|
ParserState state(pstate);
|
|
1198
1296
|
// parse the left hand side relation
|
|
@@ -1200,7 +1298,7 @@ namespace Sass {
|
|
|
1200
1298
|
// parse multiple right hand sides
|
|
1201
1299
|
std::vector<Expression_Obj> operands;
|
|
1202
1300
|
while (lex_css< kwd_and >()) {
|
|
1203
|
-
operands.push_back(
|
|
1301
|
+
operands.push_back(parse_relation());
|
|
1204
1302
|
}
|
|
1205
1303
|
// if it's a singleton, return it directly
|
|
1206
1304
|
if (operands.size() == 0) return rel;
|
|
@@ -1215,6 +1313,7 @@ namespace Sass {
|
|
|
1215
1313
|
// parse comparison operations
|
|
1216
1314
|
Expression_Obj Parser::parse_relation()
|
|
1217
1315
|
{
|
|
1316
|
+
NESTING_GUARD(nestings);
|
|
1218
1317
|
advanceToNextToken();
|
|
1219
1318
|
ParserState state(pstate);
|
|
1220
1319
|
// parse the left hand side expression
|
|
@@ -1246,8 +1345,7 @@ namespace Sass {
|
|
|
1246
1345
|
// is directly adjacent to expression?
|
|
1247
1346
|
bool right_ws = peek < css_comments >() != NULL;
|
|
1248
1347
|
operators.push_back({ op, left_ws, right_ws });
|
|
1249
|
-
operands.push_back(
|
|
1250
|
-
left_ws = peek < css_comments >() != NULL;
|
|
1348
|
+
operands.push_back(parse_expression());
|
|
1251
1349
|
}
|
|
1252
1350
|
// we are called recursively for list, so we first
|
|
1253
1351
|
// fold inner binary expression which has delayed
|
|
@@ -1268,6 +1366,7 @@ namespace Sass {
|
|
|
1268
1366
|
// parse addition and subtraction operations
|
|
1269
1367
|
Expression_Obj Parser::parse_expression()
|
|
1270
1368
|
{
|
|
1369
|
+
NESTING_GUARD(nestings);
|
|
1271
1370
|
advanceToNextToken();
|
|
1272
1371
|
ParserState state(pstate);
|
|
1273
1372
|
// parses multiple add and subtract operations
|
|
@@ -1297,7 +1396,7 @@ namespace Sass {
|
|
|
1297
1396
|
|
|
1298
1397
|
bool right_ws = peek < css_comments >() != NULL;
|
|
1299
1398
|
operators.push_back({ lexed.to_string() == "+" ? Sass_OP::ADD : Sass_OP::SUB, left_ws, right_ws });
|
|
1300
|
-
operands.push_back(
|
|
1399
|
+
operands.push_back(parse_operators());
|
|
1301
1400
|
left_ws = peek < css_comments >() != NULL;
|
|
1302
1401
|
}
|
|
1303
1402
|
|
|
@@ -1311,6 +1410,7 @@ namespace Sass {
|
|
|
1311
1410
|
// parse addition and subtraction operations
|
|
1312
1411
|
Expression_Obj Parser::parse_operators()
|
|
1313
1412
|
{
|
|
1413
|
+
NESTING_GUARD(nestings);
|
|
1314
1414
|
advanceToNextToken();
|
|
1315
1415
|
ParserState state(pstate);
|
|
1316
1416
|
Expression_Obj factor = parse_factor();
|
|
@@ -1325,7 +1425,7 @@ namespace Sass {
|
|
|
1325
1425
|
case '*': operators.push_back({ Sass_OP::MUL, left_ws != 0, right_ws != 0 }); break;
|
|
1326
1426
|
case '/': operators.push_back({ Sass_OP::DIV, left_ws != 0, right_ws != 0 }); break;
|
|
1327
1427
|
case '%': operators.push_back({ Sass_OP::MOD, left_ws != 0, right_ws != 0 }); break;
|
|
1328
|
-
default: throw std::runtime_error("unknown static op parsed");
|
|
1428
|
+
default: throw std::runtime_error("unknown static op parsed");
|
|
1329
1429
|
}
|
|
1330
1430
|
operands.push_back(parse_factor());
|
|
1331
1431
|
left_ws = peek < css_comments >();
|
|
@@ -1343,65 +1443,79 @@ namespace Sass {
|
|
|
1343
1443
|
// called from parse_value_schema
|
|
1344
1444
|
Expression_Obj Parser::parse_factor()
|
|
1345
1445
|
{
|
|
1446
|
+
NESTING_GUARD(nestings);
|
|
1346
1447
|
lex < css_comments >(false);
|
|
1347
1448
|
if (lex_css< exactly<'('> >()) {
|
|
1348
1449
|
// parse_map may return a list
|
|
1349
1450
|
Expression_Obj value = parse_map();
|
|
1350
1451
|
// lex the expected closing parenthesis
|
|
1351
|
-
if (!lex_css< exactly<')'> >()) error("unclosed parenthesis"
|
|
1452
|
+
if (!lex_css< exactly<')'> >()) error("unclosed parenthesis");
|
|
1352
1453
|
// expression can be evaluated
|
|
1353
|
-
return
|
|
1454
|
+
return value;
|
|
1455
|
+
}
|
|
1456
|
+
else if (lex_css< exactly<'['> >()) {
|
|
1457
|
+
// explicit bracketed
|
|
1458
|
+
Expression_Obj value = parse_bracket_list();
|
|
1459
|
+
// lex the expected closing square bracket
|
|
1460
|
+
if (!lex_css< exactly<']'> >()) error("unclosed squared bracket");
|
|
1461
|
+
return value;
|
|
1354
1462
|
}
|
|
1355
1463
|
// string may be interpolated
|
|
1356
1464
|
// if (lex< quoted_string >()) {
|
|
1357
1465
|
// return &parse_string();
|
|
1358
1466
|
// }
|
|
1359
1467
|
else if (peek< ie_property >()) {
|
|
1360
|
-
return
|
|
1468
|
+
return parse_ie_property();
|
|
1361
1469
|
}
|
|
1362
1470
|
else if (peek< ie_keyword_arg >()) {
|
|
1363
|
-
return
|
|
1471
|
+
return parse_ie_keyword_arg();
|
|
1364
1472
|
}
|
|
1365
1473
|
else if (peek< sequence < calc_fn_call, exactly <'('> > >()) {
|
|
1366
|
-
return
|
|
1474
|
+
return parse_calc_function();
|
|
1367
1475
|
}
|
|
1368
1476
|
else if (lex < functional_schema >()) {
|
|
1369
|
-
return
|
|
1477
|
+
return parse_function_call_schema();
|
|
1370
1478
|
}
|
|
1371
1479
|
else if (lex< identifier_schema >()) {
|
|
1372
1480
|
String_Obj string = parse_identifier_schema();
|
|
1373
|
-
if (String_Schema_Ptr schema =
|
|
1481
|
+
if (String_Schema_Ptr schema = Cast<String_Schema>(string)) {
|
|
1374
1482
|
if (lex < exactly < '(' > >()) {
|
|
1375
|
-
schema->append(
|
|
1483
|
+
schema->append(parse_list());
|
|
1376
1484
|
lex < exactly < ')' > >();
|
|
1377
1485
|
}
|
|
1378
1486
|
}
|
|
1379
|
-
return
|
|
1487
|
+
return string;
|
|
1380
1488
|
}
|
|
1381
1489
|
else if (peek< sequence< uri_prefix, W, real_uri_value > >()) {
|
|
1382
|
-
return
|
|
1490
|
+
return parse_url_function_string();
|
|
1383
1491
|
}
|
|
1384
1492
|
else if (peek< re_functional >()) {
|
|
1385
|
-
return
|
|
1493
|
+
return parse_function_call();
|
|
1386
1494
|
}
|
|
1387
1495
|
else if (lex< exactly<'+'> >()) {
|
|
1388
|
-
Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::PLUS,
|
|
1496
|
+
Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::PLUS, parse_factor());
|
|
1389
1497
|
if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
|
|
1390
1498
|
return ex;
|
|
1391
1499
|
}
|
|
1392
1500
|
else if (lex< exactly<'-'> >()) {
|
|
1393
|
-
Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::MINUS,
|
|
1501
|
+
Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::MINUS, parse_factor());
|
|
1502
|
+
if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
|
|
1503
|
+
return ex;
|
|
1504
|
+
}
|
|
1505
|
+
else if (lex< exactly<'/'> >()) {
|
|
1506
|
+
Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::SLASH, parse_factor());
|
|
1394
1507
|
if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
|
|
1395
1508
|
return ex;
|
|
1396
1509
|
}
|
|
1397
1510
|
else if (lex< sequence< kwd_not > >()) {
|
|
1398
|
-
Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::NOT,
|
|
1511
|
+
Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::NOT, parse_factor());
|
|
1399
1512
|
if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
|
|
1400
1513
|
return ex;
|
|
1401
1514
|
}
|
|
1515
|
+
// this whole branch is never hit via spec tests
|
|
1402
1516
|
else if (peek < sequence < one_plus < alternatives < css_whitespace, exactly<'-'>, exactly<'+'> > >, number > >()) {
|
|
1403
|
-
if (parse_number_prefix()) return
|
|
1404
|
-
Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::MINUS,
|
|
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());
|
|
1405
1519
|
if (ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
|
|
1406
1520
|
return ex;
|
|
1407
1521
|
}
|
|
@@ -1410,12 +1524,132 @@ namespace Sass {
|
|
|
1410
1524
|
}
|
|
1411
1525
|
}
|
|
1412
1526
|
|
|
1527
|
+
bool number_has_zero(const std::string& parsed)
|
|
1528
|
+
{
|
|
1529
|
+
size_t L = parsed.length();
|
|
1530
|
+
return !( (L > 0 && parsed.substr(0, 1) == ".") ||
|
|
1531
|
+
(L > 1 && parsed.substr(0, 2) == "0.") ||
|
|
1532
|
+
(L > 1 && parsed.substr(0, 2) == "-.") ||
|
|
1533
|
+
(L > 2 && parsed.substr(0, 3) == "-0.") );
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
Number_Ptr Parser::lexed_number(const ParserState& pstate, const std::string& parsed)
|
|
1537
|
+
{
|
|
1538
|
+
Number_Ptr nr = SASS_MEMORY_NEW(Number,
|
|
1539
|
+
pstate,
|
|
1540
|
+
sass_strtod(parsed.c_str()),
|
|
1541
|
+
"",
|
|
1542
|
+
number_has_zero(parsed));
|
|
1543
|
+
nr->is_interpolant(false);
|
|
1544
|
+
nr->is_delayed(true);
|
|
1545
|
+
return nr;
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
Number_Ptr Parser::lexed_percentage(const ParserState& pstate, const std::string& parsed)
|
|
1549
|
+
{
|
|
1550
|
+
Number_Ptr nr = SASS_MEMORY_NEW(Number,
|
|
1551
|
+
pstate,
|
|
1552
|
+
sass_strtod(parsed.c_str()),
|
|
1553
|
+
"%",
|
|
1554
|
+
true);
|
|
1555
|
+
nr->is_interpolant(false);
|
|
1556
|
+
nr->is_delayed(true);
|
|
1557
|
+
return nr;
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
Number_Ptr Parser::lexed_dimension(const ParserState& pstate, const std::string& parsed)
|
|
1561
|
+
{
|
|
1562
|
+
size_t L = parsed.length();
|
|
1563
|
+
size_t num_pos = parsed.find_first_not_of(" \n\r\t");
|
|
1564
|
+
if (num_pos == std::string::npos) num_pos = L;
|
|
1565
|
+
size_t unit_pos = parsed.find_first_not_of("-+0123456789.", num_pos);
|
|
1566
|
+
if (parsed[unit_pos] == 'e' && is_number(parsed[unit_pos+1]) ) {
|
|
1567
|
+
unit_pos = parsed.find_first_not_of("-+0123456789.", ++ unit_pos);
|
|
1568
|
+
}
|
|
1569
|
+
if (unit_pos == std::string::npos) unit_pos = L;
|
|
1570
|
+
const std::string& num = parsed.substr(num_pos, unit_pos - num_pos);
|
|
1571
|
+
Number_Ptr nr = SASS_MEMORY_NEW(Number,
|
|
1572
|
+
pstate,
|
|
1573
|
+
sass_strtod(num.c_str()),
|
|
1574
|
+
Token(number(parsed.c_str())),
|
|
1575
|
+
number_has_zero(parsed));
|
|
1576
|
+
nr->is_interpolant(false);
|
|
1577
|
+
nr->is_delayed(true);
|
|
1578
|
+
return nr;
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
Value_Ptr Parser::lexed_hex_color(const ParserState& pstate, const std::string& parsed)
|
|
1582
|
+
{
|
|
1583
|
+
Color_Ptr color = NULL;
|
|
1584
|
+
if (parsed[0] != '#') {
|
|
1585
|
+
return SASS_MEMORY_NEW(String_Quoted, pstate, parsed);
|
|
1586
|
+
}
|
|
1587
|
+
// chop off the '#'
|
|
1588
|
+
std::string hext(parsed.substr(1));
|
|
1589
|
+
if (parsed.length() == 4) {
|
|
1590
|
+
std::string r(2, parsed[1]);
|
|
1591
|
+
std::string g(2, parsed[2]);
|
|
1592
|
+
std::string b(2, parsed[3]);
|
|
1593
|
+
color = SASS_MEMORY_NEW(Color,
|
|
1594
|
+
pstate,
|
|
1595
|
+
static_cast<double>(strtol(r.c_str(), NULL, 16)),
|
|
1596
|
+
static_cast<double>(strtol(g.c_str(), NULL, 16)),
|
|
1597
|
+
static_cast<double>(strtol(b.c_str(), NULL, 16)),
|
|
1598
|
+
1, // alpha channel
|
|
1599
|
+
parsed);
|
|
1600
|
+
}
|
|
1601
|
+
else if (parsed.length() == 7) {
|
|
1602
|
+
std::string r(parsed.substr(1,2));
|
|
1603
|
+
std::string g(parsed.substr(3,2));
|
|
1604
|
+
std::string b(parsed.substr(5,2));
|
|
1605
|
+
color = SASS_MEMORY_NEW(Color,
|
|
1606
|
+
pstate,
|
|
1607
|
+
static_cast<double>(strtol(r.c_str(), NULL, 16)),
|
|
1608
|
+
static_cast<double>(strtol(g.c_str(), NULL, 16)),
|
|
1609
|
+
static_cast<double>(strtol(b.c_str(), NULL, 16)),
|
|
1610
|
+
1, // alpha channel
|
|
1611
|
+
parsed);
|
|
1612
|
+
}
|
|
1613
|
+
else if (parsed.length() == 9) {
|
|
1614
|
+
std::string r(parsed.substr(1,2));
|
|
1615
|
+
std::string g(parsed.substr(3,2));
|
|
1616
|
+
std::string b(parsed.substr(5,2));
|
|
1617
|
+
std::string a(parsed.substr(7,2));
|
|
1618
|
+
color = SASS_MEMORY_NEW(Color,
|
|
1619
|
+
pstate,
|
|
1620
|
+
static_cast<double>(strtol(r.c_str(), NULL, 16)),
|
|
1621
|
+
static_cast<double>(strtol(g.c_str(), NULL, 16)),
|
|
1622
|
+
static_cast<double>(strtol(b.c_str(), NULL, 16)),
|
|
1623
|
+
static_cast<double>(strtol(a.c_str(), NULL, 16)) / 255,
|
|
1624
|
+
parsed);
|
|
1625
|
+
}
|
|
1626
|
+
color->is_interpolant(false);
|
|
1627
|
+
color->is_delayed(false);
|
|
1628
|
+
return color;
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
Value_Ptr Parser::color_or_string(const std::string& lexed) const
|
|
1632
|
+
{
|
|
1633
|
+
if (auto color = name_to_color(lexed)) {
|
|
1634
|
+
auto c = SASS_MEMORY_NEW(Color, color);
|
|
1635
|
+
c->is_delayed(true);
|
|
1636
|
+
c->pstate(pstate);
|
|
1637
|
+
c->disp(lexed);
|
|
1638
|
+
return c;
|
|
1639
|
+
} else {
|
|
1640
|
+
return SASS_MEMORY_NEW(String_Constant, pstate, lexed);
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1413
1644
|
// parse one value for a list
|
|
1414
1645
|
Expression_Obj Parser::parse_value()
|
|
1415
1646
|
{
|
|
1416
1647
|
lex< css_comments >(false);
|
|
1417
1648
|
if (lex< ampersand >())
|
|
1418
1649
|
{
|
|
1650
|
+
if (match< ampersand >()) {
|
|
1651
|
+
warning("In Sass, \"&&\" means two copies of the parent selector. You probably want to use \"and\" instead.", pstate);
|
|
1652
|
+
}
|
|
1419
1653
|
return SASS_MEMORY_NEW(Parent_Selector, pstate); }
|
|
1420
1654
|
|
|
1421
1655
|
if (lex< kwd_important >())
|
|
@@ -1423,21 +1657,21 @@ namespace Sass {
|
|
|
1423
1657
|
|
|
1424
1658
|
// parse `10%4px` into separated items and not a schema
|
|
1425
1659
|
if (lex< sequence < percentage, lookahead < number > > >())
|
|
1426
|
-
{ return
|
|
1660
|
+
{ return lexed_percentage(lexed); }
|
|
1427
1661
|
|
|
1428
1662
|
if (lex< sequence < number, lookahead< sequence < op, number > > > >())
|
|
1429
|
-
{ return
|
|
1663
|
+
{ return lexed_number(lexed); }
|
|
1430
1664
|
|
|
1431
1665
|
// string may be interpolated
|
|
1432
1666
|
if (lex< sequence < quoted_string, lookahead < exactly <'-'> > > >())
|
|
1433
|
-
{ return
|
|
1667
|
+
{ return parse_string(); }
|
|
1434
1668
|
|
|
1435
1669
|
if (const char* stop = peek< value_schema >())
|
|
1436
|
-
{ return
|
|
1670
|
+
{ return parse_value_schema(stop); }
|
|
1437
1671
|
|
|
1438
1672
|
// string may be interpolated
|
|
1439
1673
|
if (lex< quoted_string >())
|
|
1440
|
-
{ return
|
|
1674
|
+
{ return parse_string(); }
|
|
1441
1675
|
|
|
1442
1676
|
if (lex< kwd_true >())
|
|
1443
1677
|
{ return SASS_MEMORY_NEW(Boolean, pstate, true); }
|
|
@@ -1449,15 +1683,28 @@ namespace Sass {
|
|
|
1449
1683
|
{ return SASS_MEMORY_NEW(Null, pstate); }
|
|
1450
1684
|
|
|
1451
1685
|
if (lex< identifier >()) {
|
|
1452
|
-
return
|
|
1686
|
+
return color_or_string(lexed);
|
|
1453
1687
|
}
|
|
1454
1688
|
|
|
1455
1689
|
if (lex< percentage >())
|
|
1456
|
-
{ return
|
|
1690
|
+
{ return lexed_percentage(lexed); }
|
|
1457
1691
|
|
|
1458
1692
|
// match hex number first because 0x000 looks like a number followed by an identifier
|
|
1459
1693
|
if (lex< sequence < alternatives< hex, hex0 >, negate < exactly<'-'> > > >())
|
|
1460
|
-
{ return
|
|
1694
|
+
{ return lexed_hex_color(lexed); }
|
|
1695
|
+
|
|
1696
|
+
if (lex< hexa >())
|
|
1697
|
+
{
|
|
1698
|
+
std::string s = lexed.to_string();
|
|
1699
|
+
|
|
1700
|
+
deprecated(
|
|
1701
|
+
"The value \""+s+"\" is currently parsed as a string, but it will be parsed as a color in",
|
|
1702
|
+
"future versions of Sass. Use \"unquote('"+s+"')\" to continue parsing it as a string.",
|
|
1703
|
+
true, pstate
|
|
1704
|
+
);
|
|
1705
|
+
|
|
1706
|
+
return SASS_MEMORY_NEW(String_Quoted, pstate, lexed);
|
|
1707
|
+
}
|
|
1461
1708
|
|
|
1462
1709
|
if (lex< sequence < exactly <'#'>, identifier > >())
|
|
1463
1710
|
{ return SASS_MEMORY_NEW(String_Quoted, pstate, lexed); }
|
|
@@ -1465,13 +1712,13 @@ namespace Sass {
|
|
|
1465
1712
|
// also handle the 10em- foo special case
|
|
1466
1713
|
// alternatives < exactly < '.' >, .. > -- `1.5em-.75em` is split into a list, not a binary expression
|
|
1467
1714
|
if (lex< sequence< dimension, optional< sequence< exactly<'-'>, lookahead< alternatives < space > > > > > >())
|
|
1468
|
-
{ return
|
|
1715
|
+
{ return lexed_dimension(lexed); }
|
|
1469
1716
|
|
|
1470
1717
|
if (lex< sequence< static_component, one_plus< strict_identifier > > >())
|
|
1471
1718
|
{ return SASS_MEMORY_NEW(String_Constant, pstate, lexed); }
|
|
1472
1719
|
|
|
1473
1720
|
if (lex< number >())
|
|
1474
|
-
{ return
|
|
1721
|
+
{ return lexed_number(lexed); }
|
|
1475
1722
|
|
|
1476
1723
|
if (lex< variable >())
|
|
1477
1724
|
{ return SASS_MEMORY_NEW(Variable, pstate, Util::normalize_underscores(lexed)); }
|
|
@@ -1488,7 +1735,7 @@ namespace Sass {
|
|
|
1488
1735
|
|
|
1489
1736
|
// this parses interpolation inside other strings
|
|
1490
1737
|
// means the result should later be quoted again
|
|
1491
|
-
String_Obj Parser::parse_interpolated_chunk(Token chunk, bool constant)
|
|
1738
|
+
String_Obj Parser::parse_interpolated_chunk(Token chunk, bool constant, bool css)
|
|
1492
1739
|
{
|
|
1493
1740
|
const char* i = chunk.begin;
|
|
1494
1741
|
// see if there any interpolants
|
|
@@ -1496,12 +1743,12 @@ namespace Sass {
|
|
|
1496
1743
|
find_first_in_interval< exactly<hash_lbrace>, block_comment >(i, chunk.end);
|
|
1497
1744
|
|
|
1498
1745
|
if (!p) {
|
|
1499
|
-
String_Quoted_Ptr str_quoted = SASS_MEMORY_NEW(String_Quoted, pstate, std::string(i, chunk.end));
|
|
1746
|
+
String_Quoted_Ptr str_quoted = SASS_MEMORY_NEW(String_Quoted, pstate, std::string(i, chunk.end), 0, false, false, true, css);
|
|
1500
1747
|
if (!constant && str_quoted->quote_mark()) str_quoted->quote_mark('*');
|
|
1501
1748
|
return str_quoted;
|
|
1502
1749
|
}
|
|
1503
1750
|
|
|
1504
|
-
|
|
1751
|
+
String_Schema_Obj schema = SASS_MEMORY_NEW(String_Schema, pstate, 0, css);
|
|
1505
1752
|
schema->is_interpolant(true);
|
|
1506
1753
|
while (i < chunk.end) {
|
|
1507
1754
|
p = constant ? find_first_in_interval< exactly<hash_lbrace> >(i, chunk.end) :
|
|
@@ -1509,7 +1756,7 @@ namespace Sass {
|
|
|
1509
1756
|
if (p) {
|
|
1510
1757
|
if (i < p) {
|
|
1511
1758
|
// accumulate the preceding segment if it's nonempty
|
|
1512
|
-
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string(i, p)));
|
|
1759
|
+
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string(i, p), css));
|
|
1513
1760
|
}
|
|
1514
1761
|
// we need to skip anything inside strings
|
|
1515
1762
|
// create a new target in parser/prelexer
|
|
@@ -1519,39 +1766,106 @@ namespace Sass {
|
|
|
1519
1766
|
const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p + 2, chunk.end); // find the closing brace
|
|
1520
1767
|
if (j) { --j;
|
|
1521
1768
|
// parse the interpolant and accumulate it
|
|
1522
|
-
Expression_Obj interp_node = Parser::from_token(Token(p+2, j), ctx, pstate, source).parse_list();
|
|
1769
|
+
Expression_Obj interp_node = Parser::from_token(Token(p+2, j), ctx, traces, pstate, source).parse_list();
|
|
1523
1770
|
interp_node->is_interpolant(true);
|
|
1524
|
-
schema->append(
|
|
1771
|
+
schema->append(interp_node);
|
|
1525
1772
|
i = j;
|
|
1526
1773
|
}
|
|
1527
1774
|
else {
|
|
1528
1775
|
// throw an error if the interpolant is unterminated
|
|
1529
|
-
error("unterminated interpolant inside string constant " + chunk.to_string()
|
|
1776
|
+
error("unterminated interpolant inside string constant " + chunk.to_string());
|
|
1530
1777
|
}
|
|
1531
1778
|
}
|
|
1532
1779
|
else { // no interpolants left; add the last segment if nonempty
|
|
1533
1780
|
// check if we need quotes here (was not sure after merge)
|
|
1534
|
-
if (i < chunk.end) schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string(i, chunk.end)));
|
|
1781
|
+
if (i < chunk.end) schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string(i, chunk.end), css));
|
|
1535
1782
|
break;
|
|
1536
1783
|
}
|
|
1537
1784
|
++ i;
|
|
1538
1785
|
}
|
|
1539
1786
|
|
|
1540
|
-
return schema;
|
|
1787
|
+
return schema.detach();
|
|
1541
1788
|
}
|
|
1542
1789
|
|
|
1543
|
-
|
|
1790
|
+
String_Schema_Obj Parser::parse_css_variable_value(bool top_level)
|
|
1791
|
+
{
|
|
1792
|
+
String_Schema_Obj schema = SASS_MEMORY_NEW(String_Schema, pstate);
|
|
1793
|
+
String_Schema_Obj tok;
|
|
1794
|
+
if (!(tok = parse_css_variable_value_token(top_level))) {
|
|
1795
|
+
return NULL;
|
|
1796
|
+
}
|
|
1797
|
+
|
|
1798
|
+
schema->concat(tok);
|
|
1799
|
+
while ((tok = parse_css_variable_value_token(top_level))) {
|
|
1800
|
+
schema->concat(tok);
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
return schema.detach();
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
String_Schema_Obj Parser::parse_css_variable_value_token(bool top_level)
|
|
1807
|
+
{
|
|
1808
|
+
String_Schema_Obj schema = SASS_MEMORY_NEW(String_Schema, pstate);
|
|
1809
|
+
if (
|
|
1810
|
+
(top_level && lex< css_variable_top_level_value >(false)) ||
|
|
1811
|
+
(!top_level && lex< css_variable_value >(false))
|
|
1812
|
+
) {
|
|
1813
|
+
Token str(lexed);
|
|
1814
|
+
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, str));
|
|
1815
|
+
}
|
|
1816
|
+
else if (Expression_Obj tok = lex_interpolation()) {
|
|
1817
|
+
if (String_Schema_Ptr s = Cast<String_Schema>(tok)) {
|
|
1818
|
+
schema->concat(s);
|
|
1819
|
+
} else {
|
|
1820
|
+
schema->append(tok);
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
else if (lex< quoted_string >()) {
|
|
1824
|
+
Expression_Obj tok = parse_string();
|
|
1825
|
+
if (String_Schema_Ptr s = Cast<String_Schema>(tok)) {
|
|
1826
|
+
schema->concat(s);
|
|
1827
|
+
} else {
|
|
1828
|
+
schema->append(tok);
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
else {
|
|
1832
|
+
if (peek< alternatives< exactly<'('>, exactly<'['>, exactly<'{'> > >()) {
|
|
1833
|
+
if (lex< exactly<'('> >()) {
|
|
1834
|
+
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string("(")));
|
|
1835
|
+
if (String_Schema_Obj tok = parse_css_variable_value(false)) schema->concat(tok);
|
|
1836
|
+
if (!lex< exactly<')'> >()) css_error("Invalid CSS", " after ", ": expected \")\", was ");
|
|
1837
|
+
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string(")")));
|
|
1838
|
+
}
|
|
1839
|
+
else if (lex< exactly<'['> >()) {
|
|
1840
|
+
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string("[")));
|
|
1841
|
+
if (String_Schema_Obj tok = parse_css_variable_value(false)) schema->concat(tok);
|
|
1842
|
+
if (!lex< exactly<']'> >()) css_error("Invalid CSS", " after ", ": expected \"]\", was ");
|
|
1843
|
+
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string("]")));
|
|
1844
|
+
}
|
|
1845
|
+
else if (lex< exactly<'{'> >()) {
|
|
1846
|
+
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string("{")));
|
|
1847
|
+
if (String_Schema_Obj tok = parse_css_variable_value(false)) schema->concat(tok);
|
|
1848
|
+
if (!lex< exactly<'}'> >()) css_error("Invalid CSS", " after ", ": expected \"}\", was ");
|
|
1849
|
+
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string("}")));
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
return schema->length() > 0 ? schema.detach() : NULL;
|
|
1855
|
+
}
|
|
1856
|
+
|
|
1857
|
+
Value_Obj Parser::parse_static_value()
|
|
1544
1858
|
{
|
|
1545
1859
|
lex< static_value >();
|
|
1546
1860
|
Token str(lexed);
|
|
1547
1861
|
// static values always have trailing white-
|
|
1548
1862
|
// space and end delimiter (\s*[;]$) included
|
|
1549
|
-
--
|
|
1863
|
+
--pstate.offset.column;
|
|
1864
|
+
--after_token.column;
|
|
1550
1865
|
--str.end;
|
|
1551
1866
|
--position;
|
|
1552
1867
|
|
|
1553
|
-
|
|
1554
|
-
return str_node;
|
|
1868
|
+
return color_or_string(str.time_wspace());;
|
|
1555
1869
|
}
|
|
1556
1870
|
|
|
1557
1871
|
String_Obj Parser::parse_string()
|
|
@@ -1583,14 +1897,14 @@ namespace Sass {
|
|
|
1583
1897
|
const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p+2, str.end); // find the closing brace
|
|
1584
1898
|
if (j) {
|
|
1585
1899
|
// parse the interpolant and accumulate it
|
|
1586
|
-
Expression_Obj interp_node = Parser::from_token(Token(p+2, j), ctx, pstate, source).parse_list();
|
|
1900
|
+
Expression_Obj interp_node = Parser::from_token(Token(p+2, j), ctx, traces, pstate, source).parse_list();
|
|
1587
1901
|
interp_node->is_interpolant(true);
|
|
1588
|
-
schema->append(
|
|
1902
|
+
schema->append(interp_node);
|
|
1589
1903
|
i = j;
|
|
1590
1904
|
}
|
|
1591
1905
|
else {
|
|
1592
1906
|
// throw an error if the interpolant is unterminated
|
|
1593
|
-
error("unterminated interpolant inside IE function " + str.to_string()
|
|
1907
|
+
error("unterminated interpolant inside IE function " + str.to_string());
|
|
1594
1908
|
}
|
|
1595
1909
|
}
|
|
1596
1910
|
else { // no interpolants left; add the last segment if nonempty
|
|
@@ -1614,9 +1928,13 @@ namespace Sass {
|
|
|
1614
1928
|
}
|
|
1615
1929
|
lex< exactly<'='> >();
|
|
1616
1930
|
kwd_arg->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed));
|
|
1617
|
-
if (peek< variable >()) kwd_arg->append(
|
|
1618
|
-
else if (lex< number >())
|
|
1619
|
-
|
|
1931
|
+
if (peek< variable >()) kwd_arg->append(parse_list());
|
|
1932
|
+
else if (lex< number >()) {
|
|
1933
|
+
std::string parsed(lexed);
|
|
1934
|
+
Util::normalize_decimals(parsed);
|
|
1935
|
+
kwd_arg->append(lexed_number(parsed));
|
|
1936
|
+
}
|
|
1937
|
+
else if (peek < ie_keyword_arg_value >()) { kwd_arg->append(parse_list()); }
|
|
1620
1938
|
return kwd_arg;
|
|
1621
1939
|
}
|
|
1622
1940
|
|
|
@@ -1629,7 +1947,7 @@ namespace Sass {
|
|
|
1629
1947
|
css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
|
|
1630
1948
|
}
|
|
1631
1949
|
|
|
1632
|
-
const char* e
|
|
1950
|
+
const char* e;
|
|
1633
1951
|
const char* ee = end;
|
|
1634
1952
|
end = stop;
|
|
1635
1953
|
size_t num_items = 0;
|
|
@@ -1644,7 +1962,7 @@ namespace Sass {
|
|
|
1644
1962
|
// schema->append(SASS_MEMORY_NEW(String_Constant, pstate, " "));
|
|
1645
1963
|
}
|
|
1646
1964
|
if ((e = peek< re_functional >()) && e < stop) {
|
|
1647
|
-
schema->append(
|
|
1965
|
+
schema->append(parse_function_call());
|
|
1648
1966
|
}
|
|
1649
1967
|
// lex an interpolant /#{...}/
|
|
1650
1968
|
else if (lex< exactly < hash_lbrace > >()) {
|
|
@@ -1652,11 +1970,11 @@ namespace Sass {
|
|
|
1652
1970
|
if (peek< exactly< rbrace > >()) {
|
|
1653
1971
|
css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
|
|
1654
1972
|
}
|
|
1655
|
-
Expression_Obj ex
|
|
1973
|
+
Expression_Obj ex;
|
|
1656
1974
|
if (lex< re_static_expression >()) {
|
|
1657
1975
|
ex = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
|
|
1658
1976
|
} else {
|
|
1659
|
-
ex = parse_list();
|
|
1977
|
+
ex = parse_list(true);
|
|
1660
1978
|
}
|
|
1661
1979
|
ex->is_interpolant(true);
|
|
1662
1980
|
schema->append(ex);
|
|
@@ -1674,13 +1992,13 @@ namespace Sass {
|
|
|
1674
1992
|
// need_space = true;
|
|
1675
1993
|
// if (schema->length()) schema->append(SASS_MEMORY_NEW(String_Constant, pstate, " "));
|
|
1676
1994
|
// else need_space = true;
|
|
1677
|
-
schema->append(
|
|
1995
|
+
schema->append(parse_string());
|
|
1678
1996
|
if ((*position == '"' || *position == '\'') || peek < alternatives < alpha > >()) {
|
|
1679
1997
|
// need_space = true;
|
|
1680
1998
|
}
|
|
1681
1999
|
if (peek < exactly < '-' > >()) break;
|
|
1682
2000
|
}
|
|
1683
|
-
else if (lex<
|
|
2001
|
+
else if (lex< identifier >()) {
|
|
1684
2002
|
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed));
|
|
1685
2003
|
if ((*position == '"' || *position == '\'') || peek < alternatives < alpha > >()) {
|
|
1686
2004
|
// need_space = true;
|
|
@@ -1693,26 +2011,26 @@ namespace Sass {
|
|
|
1693
2011
|
}
|
|
1694
2012
|
// lex percentage value
|
|
1695
2013
|
else if (lex< percentage >()) {
|
|
1696
|
-
schema->append(
|
|
2014
|
+
schema->append(lexed_percentage(lexed));
|
|
1697
2015
|
}
|
|
1698
2016
|
// lex dimension value
|
|
1699
2017
|
else if (lex< dimension >()) {
|
|
1700
|
-
schema->append(
|
|
2018
|
+
schema->append(lexed_dimension(lexed));
|
|
1701
2019
|
}
|
|
1702
2020
|
// lex number value
|
|
1703
2021
|
else if (lex< number >()) {
|
|
1704
|
-
schema->append(
|
|
2022
|
+
schema->append(lexed_number(lexed));
|
|
1705
2023
|
}
|
|
1706
2024
|
// lex hex color value
|
|
1707
2025
|
else if (lex< sequence < hex, negate < exactly < '-' > > > >()) {
|
|
1708
|
-
schema->append(
|
|
2026
|
+
schema->append(lexed_hex_color(lexed));
|
|
1709
2027
|
}
|
|
1710
2028
|
else if (lex< sequence < exactly <'#'>, identifier > >()) {
|
|
1711
2029
|
schema->append(SASS_MEMORY_NEW(String_Quoted, pstate, lexed));
|
|
1712
2030
|
}
|
|
1713
2031
|
// lex a value in parentheses
|
|
1714
2032
|
else if (peek< parenthese_scope >()) {
|
|
1715
|
-
schema->append(
|
|
2033
|
+
schema->append(parse_factor());
|
|
1716
2034
|
}
|
|
1717
2035
|
else {
|
|
1718
2036
|
break;
|
|
@@ -1746,7 +2064,7 @@ namespace Sass {
|
|
|
1746
2064
|
if (i < p) {
|
|
1747
2065
|
// accumulate the preceding segment if it's nonempty
|
|
1748
2066
|
const char* o = position; position = i;
|
|
1749
|
-
schema->append(
|
|
2067
|
+
schema->append(parse_value_schema(p));
|
|
1750
2068
|
position = o;
|
|
1751
2069
|
}
|
|
1752
2070
|
// we need to skip anything inside strings
|
|
@@ -1757,7 +2075,7 @@ namespace Sass {
|
|
|
1757
2075
|
const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p+2, id.end); // find the closing brace
|
|
1758
2076
|
if (j) {
|
|
1759
2077
|
// parse the interpolant and accumulate it
|
|
1760
|
-
Expression_Obj interp_node = Parser::from_token(Token(p+2, j), ctx, pstate, source).parse_list(DELAYED);
|
|
2078
|
+
Expression_Obj interp_node = Parser::from_token(Token(p+2, j), ctx, traces, pstate, source).parse_list(DELAYED);
|
|
1761
2079
|
interp_node->is_interpolant(true);
|
|
1762
2080
|
schema->append(interp_node);
|
|
1763
2081
|
// schema->has_interpolants(true);
|
|
@@ -1765,13 +2083,13 @@ namespace Sass {
|
|
|
1765
2083
|
}
|
|
1766
2084
|
else {
|
|
1767
2085
|
// throw an error if the interpolant is unterminated
|
|
1768
|
-
error("unterminated interpolant inside interpolated identifier " + id.to_string()
|
|
2086
|
+
error("unterminated interpolant inside interpolated identifier " + id.to_string());
|
|
1769
2087
|
}
|
|
1770
2088
|
}
|
|
1771
2089
|
else { // no interpolants left; add the last segment if nonempty
|
|
1772
2090
|
if (i < end) {
|
|
1773
2091
|
const char* o = position; position = i;
|
|
1774
|
-
schema->append(
|
|
2092
|
+
schema->append(parse_value_schema(id.end));
|
|
1775
2093
|
position = o;
|
|
1776
2094
|
}
|
|
1777
2095
|
break;
|
|
@@ -1796,9 +2114,9 @@ namespace Sass {
|
|
|
1796
2114
|
exactly < ')' >
|
|
1797
2115
|
> >();
|
|
1798
2116
|
|
|
1799
|
-
Argument_Obj arg = SASS_MEMORY_NEW(Argument, arg_pos,
|
|
2117
|
+
Argument_Obj arg = SASS_MEMORY_NEW(Argument, arg_pos, parse_interpolated_chunk(Token(arg_beg, arg_end)));
|
|
1800
2118
|
Arguments_Obj args = SASS_MEMORY_NEW(Arguments, arg_pos);
|
|
1801
|
-
args->append(
|
|
2119
|
+
args->append(arg);
|
|
1802
2120
|
return SASS_MEMORY_NEW(Function_Call, call_pos, name, args);
|
|
1803
2121
|
}
|
|
1804
2122
|
|
|
@@ -1818,16 +2136,16 @@ namespace Sass {
|
|
|
1818
2136
|
}
|
|
1819
2137
|
|
|
1820
2138
|
std::string uri("");
|
|
1821
|
-
if (
|
|
2139
|
+
if (url_string) {
|
|
1822
2140
|
uri = url_string->to_string({ NESTED, 5 });
|
|
1823
2141
|
}
|
|
1824
2142
|
|
|
1825
|
-
if (String_Schema_Ptr schema =
|
|
2143
|
+
if (String_Schema_Ptr schema = Cast<String_Schema>(url_string)) {
|
|
1826
2144
|
String_Schema_Obj res = SASS_MEMORY_NEW(String_Schema, pstate);
|
|
1827
2145
|
res->append(SASS_MEMORY_NEW(String_Constant, pstate, prefix));
|
|
1828
2146
|
res->append(schema);
|
|
1829
2147
|
res->append(SASS_MEMORY_NEW(String_Constant, pstate, suffix));
|
|
1830
|
-
return
|
|
2148
|
+
return res;
|
|
1831
2149
|
} else {
|
|
1832
2150
|
std::string res = prefix + uri + suffix;
|
|
1833
2151
|
return SASS_MEMORY_NEW(String_Constant, pstate, res);
|
|
@@ -1850,7 +2168,7 @@ namespace Sass {
|
|
|
1850
2168
|
pp = sequence< interpolant, real_uri_value >(pp);
|
|
1851
2169
|
}
|
|
1852
2170
|
position = pp;
|
|
1853
|
-
return
|
|
2171
|
+
return parse_interpolated_chunk(Token(p, position));
|
|
1854
2172
|
}
|
|
1855
2173
|
else if (uri != "") {
|
|
1856
2174
|
std::string res = Util::rtrim(uri);
|
|
@@ -1865,6 +2183,9 @@ namespace Sass {
|
|
|
1865
2183
|
lex< identifier >();
|
|
1866
2184
|
std::string name(lexed);
|
|
1867
2185
|
|
|
2186
|
+
if (Util::normalize_underscores(name) == "content-exists" && stack.back() != Scope::Mixin)
|
|
2187
|
+
{ error("Cannot call content-exists() except within a mixin."); }
|
|
2188
|
+
|
|
1868
2189
|
ParserState call_pos = pstate;
|
|
1869
2190
|
Arguments_Obj args = parse_arguments();
|
|
1870
2191
|
return SASS_MEMORY_NEW(Function_Call, call_pos, name, args);
|
|
@@ -1897,10 +2218,10 @@ namespace Sass {
|
|
|
1897
2218
|
// we want all other comments to be parsed
|
|
1898
2219
|
if (lex_css< elseif_directive >()) {
|
|
1899
2220
|
alternative = SASS_MEMORY_NEW(Block, pstate);
|
|
1900
|
-
alternative->append(
|
|
2221
|
+
alternative->append(parse_if_directive(true));
|
|
1901
2222
|
}
|
|
1902
2223
|
else if (lex_css< kwd_else_directive >()) {
|
|
1903
|
-
alternative =
|
|
2224
|
+
alternative = parse_block(root);
|
|
1904
2225
|
}
|
|
1905
2226
|
stack.pop_back();
|
|
1906
2227
|
return SASS_MEMORY_NEW(If, if_source_position, predicate, block, alternative);
|
|
@@ -1913,12 +2234,12 @@ namespace Sass {
|
|
|
1913
2234
|
bool root = block_stack.back()->is_root();
|
|
1914
2235
|
lex_variable();
|
|
1915
2236
|
std::string var(Util::normalize_underscores(lexed));
|
|
1916
|
-
if (!lex< kwd_from >()) error("expected 'from' keyword in @for directive"
|
|
2237
|
+
if (!lex< kwd_from >()) error("expected 'from' keyword in @for directive");
|
|
1917
2238
|
Expression_Obj lower_bound = parse_expression();
|
|
1918
2239
|
bool inclusive = false;
|
|
1919
2240
|
if (lex< kwd_through >()) inclusive = true;
|
|
1920
2241
|
else if (lex< kwd_to >()) inclusive = false;
|
|
1921
|
-
else error("expected 'through' or 'to' keyword in @for directive"
|
|
2242
|
+
else error("expected 'through' or 'to' keyword in @for directive");
|
|
1922
2243
|
Expression_Obj upper_bound = parse_expression();
|
|
1923
2244
|
Block_Obj body = parse_block(root);
|
|
1924
2245
|
stack.pop_back();
|
|
@@ -1960,10 +2281,10 @@ namespace Sass {
|
|
|
1960
2281
|
lex_variable();
|
|
1961
2282
|
vars.push_back(Util::normalize_underscores(lexed));
|
|
1962
2283
|
while (lex< exactly<','> >()) {
|
|
1963
|
-
if (!lex< variable >()) error("@each directive requires an iteration variable"
|
|
2284
|
+
if (!lex< variable >()) error("@each directive requires an iteration variable");
|
|
1964
2285
|
vars.push_back(Util::normalize_underscores(lexed));
|
|
1965
2286
|
}
|
|
1966
|
-
if (!lex< kwd_in >()) error("expected 'in' keyword in @each directive"
|
|
2287
|
+
if (!lex< kwd_in >()) error("expected 'in' keyword in @each directive");
|
|
1967
2288
|
Expression_Obj list = parse_list();
|
|
1968
2289
|
Block_Obj body = parse_block(root);
|
|
1969
2290
|
stack.pop_back();
|
|
@@ -1979,6 +2300,10 @@ namespace Sass {
|
|
|
1979
2300
|
While_Obj call = SASS_MEMORY_NEW(While, pstate, 0, 0);
|
|
1980
2301
|
// parse mandatory predicate
|
|
1981
2302
|
Expression_Obj predicate = parse_list();
|
|
2303
|
+
List_Obj l = Cast<List>(predicate);
|
|
2304
|
+
if (!predicate || (l && !l->length())) {
|
|
2305
|
+
css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ", false);
|
|
2306
|
+
}
|
|
1982
2307
|
call->predicate(predicate);
|
|
1983
2308
|
// parse mandatory block
|
|
1984
2309
|
call->block(parse_block(root));
|
|
@@ -1997,9 +2322,9 @@ namespace Sass {
|
|
|
1997
2322
|
media_block->media_queries(parse_media_queries());
|
|
1998
2323
|
|
|
1999
2324
|
Media_Block_Obj prev_media_block = last_media_block;
|
|
2000
|
-
last_media_block =
|
|
2325
|
+
last_media_block = media_block;
|
|
2001
2326
|
media_block->block(parse_css_block());
|
|
2002
|
-
last_media_block =
|
|
2327
|
+
last_media_block = prev_media_block;
|
|
2003
2328
|
stack.pop_back();
|
|
2004
2329
|
return media_block.detach();
|
|
2005
2330
|
}
|
|
@@ -2008,8 +2333,8 @@ namespace Sass {
|
|
|
2008
2333
|
{
|
|
2009
2334
|
advanceToNextToken();
|
|
2010
2335
|
List_Obj queries = SASS_MEMORY_NEW(List, pstate, 0, SASS_COMMA);
|
|
2011
|
-
if (!peek_css < exactly <'{'> >()) queries->append(
|
|
2012
|
-
while (lex_css < exactly <','> >()) queries->append(
|
|
2336
|
+
if (!peek_css < exactly <'{'> >()) queries->append(parse_media_query());
|
|
2337
|
+
while (lex_css < exactly <','> >()) queries->append(parse_media_query());
|
|
2013
2338
|
queries->update_pstate(pstate);
|
|
2014
2339
|
return queries.detach();
|
|
2015
2340
|
}
|
|
@@ -2022,19 +2347,19 @@ namespace Sass {
|
|
|
2022
2347
|
if (lex < kwd_not >()) { media_query->is_negated(true); lex < css_comments >(false); }
|
|
2023
2348
|
else if (lex < kwd_only >()) { media_query->is_restricted(true); lex < css_comments >(false); }
|
|
2024
2349
|
|
|
2025
|
-
if (lex < identifier_schema >()) media_query->media_type(
|
|
2026
|
-
else if (lex < identifier >()) media_query->media_type(
|
|
2027
|
-
else media_query->append(
|
|
2350
|
+
if (lex < identifier_schema >()) media_query->media_type(parse_identifier_schema());
|
|
2351
|
+
else if (lex < identifier >()) media_query->media_type(parse_interpolated_chunk(lexed));
|
|
2352
|
+
else media_query->append(parse_media_expression());
|
|
2028
2353
|
|
|
2029
|
-
while (lex_css < kwd_and >()) media_query->append(
|
|
2354
|
+
while (lex_css < kwd_and >()) media_query->append(parse_media_expression());
|
|
2030
2355
|
if (lex < identifier_schema >()) {
|
|
2031
2356
|
String_Schema_Ptr schema = SASS_MEMORY_NEW(String_Schema, pstate);
|
|
2032
|
-
schema->append(
|
|
2357
|
+
schema->append(media_query->media_type());
|
|
2033
2358
|
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, " "));
|
|
2034
|
-
schema->append(
|
|
2359
|
+
schema->append(parse_identifier_schema());
|
|
2035
2360
|
media_query->media_type(schema);
|
|
2036
2361
|
}
|
|
2037
|
-
while (lex_css < kwd_and >()) media_query->append(
|
|
2362
|
+
while (lex_css < kwd_and >()) media_query->append(parse_media_expression());
|
|
2038
2363
|
|
|
2039
2364
|
media_query->update_pstate(pstate);
|
|
2040
2365
|
|
|
@@ -2045,22 +2370,22 @@ namespace Sass {
|
|
|
2045
2370
|
{
|
|
2046
2371
|
if (lex < identifier_schema >()) {
|
|
2047
2372
|
String_Obj ss = parse_identifier_schema();
|
|
2048
|
-
return SASS_MEMORY_NEW(Media_Query_Expression, pstate,
|
|
2373
|
+
return SASS_MEMORY_NEW(Media_Query_Expression, pstate, ss, 0, true);
|
|
2049
2374
|
}
|
|
2050
2375
|
if (!lex_css< exactly<'('> >()) {
|
|
2051
|
-
error("media query expression must begin with '('"
|
|
2376
|
+
error("media query expression must begin with '('");
|
|
2052
2377
|
}
|
|
2053
|
-
Expression_Obj feature
|
|
2378
|
+
Expression_Obj feature;
|
|
2054
2379
|
if (peek_css< exactly<')'> >()) {
|
|
2055
|
-
error("media feature required in media query expression"
|
|
2380
|
+
error("media feature required in media query expression");
|
|
2056
2381
|
}
|
|
2057
|
-
feature =
|
|
2382
|
+
feature = parse_expression();
|
|
2058
2383
|
Expression_Obj expression = 0;
|
|
2059
2384
|
if (lex_css< exactly<':'> >()) {
|
|
2060
|
-
expression =
|
|
2385
|
+
expression = parse_list(DELAYED);
|
|
2061
2386
|
}
|
|
2062
2387
|
if (!lex_css< exactly<')'> >()) {
|
|
2063
|
-
error("unclosed parenthesis in media query expression"
|
|
2388
|
+
error("unclosed parenthesis in media query expression");
|
|
2064
2389
|
}
|
|
2065
2390
|
return SASS_MEMORY_NEW(Media_Query_Expression, feature->pstate(), feature, expression);
|
|
2066
2391
|
}
|
|
@@ -2070,6 +2395,9 @@ namespace Sass {
|
|
|
2070
2395
|
Supports_Block_Obj Parser::parse_supports_directive()
|
|
2071
2396
|
{
|
|
2072
2397
|
Supports_Condition_Obj cond = parse_supports_condition();
|
|
2398
|
+
if (!cond) {
|
|
2399
|
+
css_error("Invalid CSS", " after ", ": expected @supports condition (e.g. (display: flexbox)), was ", false);
|
|
2400
|
+
}
|
|
2073
2401
|
// create the ast node object for the support queries
|
|
2074
2402
|
Supports_Block_Obj query = SASS_MEMORY_NEW(Supports_Block, pstate, cond);
|
|
2075
2403
|
// additional block is mandatory
|
|
@@ -2084,7 +2412,7 @@ namespace Sass {
|
|
|
2084
2412
|
Supports_Condition_Obj Parser::parse_supports_condition()
|
|
2085
2413
|
{
|
|
2086
2414
|
lex < css_whitespace >();
|
|
2087
|
-
Supports_Condition_Obj cond
|
|
2415
|
+
Supports_Condition_Obj cond;
|
|
2088
2416
|
if ((cond = parse_supports_negation())) return cond;
|
|
2089
2417
|
if ((cond = parse_supports_operator())) return cond;
|
|
2090
2418
|
if ((cond = parse_supports_interpolation())) return cond;
|
|
@@ -2095,13 +2423,13 @@ namespace Sass {
|
|
|
2095
2423
|
{
|
|
2096
2424
|
if (!lex < kwd_not >()) return 0;
|
|
2097
2425
|
Supports_Condition_Obj cond = parse_supports_condition_in_parens();
|
|
2098
|
-
return SASS_MEMORY_NEW(Supports_Negation, pstate,
|
|
2426
|
+
return SASS_MEMORY_NEW(Supports_Negation, pstate, cond);
|
|
2099
2427
|
}
|
|
2100
2428
|
|
|
2101
2429
|
Supports_Condition_Obj Parser::parse_supports_operator()
|
|
2102
2430
|
{
|
|
2103
2431
|
Supports_Condition_Obj cond = parse_supports_condition_in_parens();
|
|
2104
|
-
if (
|
|
2432
|
+
if (cond.isNull()) return 0;
|
|
2105
2433
|
|
|
2106
2434
|
while (true) {
|
|
2107
2435
|
Supports_Operator::Operand op = Supports_Operator::OR;
|
|
@@ -2112,7 +2440,7 @@ namespace Sass {
|
|
|
2112
2440
|
Supports_Condition_Obj right = parse_supports_condition_in_parens();
|
|
2113
2441
|
|
|
2114
2442
|
// Supports_Condition_Ptr cc = SASS_MEMORY_NEW(Supports_Condition, *static_cast<Supports_Condition_Ptr>(cond));
|
|
2115
|
-
cond = SASS_MEMORY_NEW(Supports_Operator, pstate,
|
|
2443
|
+
cond = SASS_MEMORY_NEW(Supports_Operator, pstate, cond, right, op);
|
|
2116
2444
|
}
|
|
2117
2445
|
return cond;
|
|
2118
2446
|
}
|
|
@@ -2124,21 +2452,25 @@ namespace Sass {
|
|
|
2124
2452
|
String_Obj interp = parse_interpolated_chunk(lexed);
|
|
2125
2453
|
if (!interp) return 0;
|
|
2126
2454
|
|
|
2127
|
-
return SASS_MEMORY_NEW(Supports_Interpolation, pstate,
|
|
2455
|
+
return SASS_MEMORY_NEW(Supports_Interpolation, pstate, interp);
|
|
2128
2456
|
}
|
|
2129
2457
|
|
|
2130
2458
|
// TODO: This needs some major work. Although feature conditions
|
|
2131
2459
|
// look like declarations their semantics differ significantly
|
|
2132
2460
|
Supports_Condition_Obj Parser::parse_supports_declaration()
|
|
2133
2461
|
{
|
|
2134
|
-
Supports_Condition_Ptr cond
|
|
2462
|
+
Supports_Condition_Ptr cond;
|
|
2135
2463
|
// parse something declaration like
|
|
2136
|
-
|
|
2137
|
-
|
|
2464
|
+
Expression_Obj feature = parse_expression();
|
|
2465
|
+
Expression_Obj expression = 0;
|
|
2466
|
+
if (lex_css< exactly<':'> >()) {
|
|
2467
|
+
expression = parse_list(DELAYED);
|
|
2468
|
+
}
|
|
2469
|
+
if (!feature || !expression) error("@supports condition expected declaration");
|
|
2138
2470
|
cond = SASS_MEMORY_NEW(Supports_Declaration,
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2471
|
+
feature->pstate(),
|
|
2472
|
+
feature,
|
|
2473
|
+
expression);
|
|
2142
2474
|
// ToDo: maybe we need an additional error condition?
|
|
2143
2475
|
return cond;
|
|
2144
2476
|
}
|
|
@@ -2146,17 +2478,17 @@ namespace Sass {
|
|
|
2146
2478
|
Supports_Condition_Obj Parser::parse_supports_condition_in_parens()
|
|
2147
2479
|
{
|
|
2148
2480
|
Supports_Condition_Obj interp = parse_supports_interpolation();
|
|
2149
|
-
if (
|
|
2481
|
+
if (interp != 0) return interp;
|
|
2150
2482
|
|
|
2151
2483
|
if (!lex < exactly <'('> >()) return 0;
|
|
2152
2484
|
lex < css_whitespace >();
|
|
2153
2485
|
|
|
2154
2486
|
Supports_Condition_Obj cond = parse_supports_condition();
|
|
2155
|
-
if (
|
|
2156
|
-
if (!lex < exactly <')'> >()) error("unclosed parenthesis in @supports declaration"
|
|
2487
|
+
if (cond != 0) {
|
|
2488
|
+
if (!lex < exactly <')'> >()) error("unclosed parenthesis in @supports declaration");
|
|
2157
2489
|
} else {
|
|
2158
2490
|
cond = parse_supports_declaration();
|
|
2159
|
-
if (!lex < exactly <')'> >()) error("unclosed parenthesis in @supports declaration"
|
|
2491
|
+
if (!lex < exactly <')'> >()) error("unclosed parenthesis in @supports declaration");
|
|
2160
2492
|
}
|
|
2161
2493
|
lex < css_whitespace >();
|
|
2162
2494
|
return cond;
|
|
@@ -2164,51 +2496,52 @@ namespace Sass {
|
|
|
2164
2496
|
|
|
2165
2497
|
At_Root_Block_Obj Parser::parse_at_root_block()
|
|
2166
2498
|
{
|
|
2499
|
+
stack.push_back(Scope::AtRoot);
|
|
2167
2500
|
ParserState at_source_position = pstate;
|
|
2168
2501
|
Block_Obj body = 0;
|
|
2169
2502
|
At_Root_Query_Obj expr;
|
|
2170
2503
|
Lookahead lookahead_result;
|
|
2171
|
-
LOCAL_FLAG(in_at_root, true);
|
|
2172
2504
|
if (lex_css< exactly<'('> >()) {
|
|
2173
2505
|
expr = parse_at_root_query();
|
|
2174
2506
|
}
|
|
2175
2507
|
if (peek_css < exactly<'{'> >()) {
|
|
2176
2508
|
lex <optional_spaces>();
|
|
2177
|
-
body =
|
|
2509
|
+
body = parse_block(true);
|
|
2178
2510
|
}
|
|
2179
2511
|
else if ((lookahead_result = lookahead_for_selector(position)).found) {
|
|
2180
|
-
Ruleset_Obj r = parse_ruleset(lookahead_result
|
|
2512
|
+
Ruleset_Obj r = parse_ruleset(lookahead_result);
|
|
2181
2513
|
body = SASS_MEMORY_NEW(Block, r->pstate(), 1, true);
|
|
2182
|
-
body->append(
|
|
2514
|
+
body->append(r);
|
|
2183
2515
|
}
|
|
2184
2516
|
At_Root_Block_Obj at_root = SASS_MEMORY_NEW(At_Root_Block, at_source_position, body);
|
|
2185
|
-
if (
|
|
2517
|
+
if (!expr.isNull()) at_root->expression(expr);
|
|
2518
|
+
stack.pop_back();
|
|
2186
2519
|
return at_root;
|
|
2187
2520
|
}
|
|
2188
2521
|
|
|
2189
2522
|
At_Root_Query_Obj Parser::parse_at_root_query()
|
|
2190
2523
|
{
|
|
2191
|
-
if (peek< exactly<')'> >()) error("at-root feature required in at-root expression"
|
|
2524
|
+
if (peek< exactly<')'> >()) error("at-root feature required in at-root expression");
|
|
2192
2525
|
|
|
2193
2526
|
if (!peek< alternatives< kwd_with_directive, kwd_without_directive > >()) {
|
|
2194
2527
|
css_error("Invalid CSS", " after ", ": expected \"with\" or \"without\", was ");
|
|
2195
2528
|
}
|
|
2196
2529
|
|
|
2197
2530
|
Expression_Obj feature = parse_list();
|
|
2198
|
-
if (!lex_css< exactly<':'> >()) error("style declaration must contain a value"
|
|
2531
|
+
if (!lex_css< exactly<':'> >()) error("style declaration must contain a value");
|
|
2199
2532
|
Expression_Obj expression = parse_list();
|
|
2200
2533
|
List_Obj value = SASS_MEMORY_NEW(List, feature->pstate(), 1);
|
|
2201
2534
|
|
|
2202
2535
|
if (expression->concrete_type() == Expression::LIST) {
|
|
2203
|
-
value =
|
|
2536
|
+
value = Cast<List>(expression);
|
|
2204
2537
|
}
|
|
2205
2538
|
else value->append(expression);
|
|
2206
2539
|
|
|
2207
2540
|
At_Root_Query_Obj cond = SASS_MEMORY_NEW(At_Root_Query,
|
|
2208
2541
|
value->pstate(),
|
|
2209
2542
|
feature,
|
|
2210
|
-
|
|
2211
|
-
if (!lex_css< exactly<')'> >()) error("unclosed parenthesis in @at-root expression"
|
|
2543
|
+
value);
|
|
2544
|
+
if (!lex_css< exactly<')'> >()) error("unclosed parenthesis in @at-root expression");
|
|
2212
2545
|
return cond;
|
|
2213
2546
|
}
|
|
2214
2547
|
|
|
@@ -2216,18 +2549,20 @@ namespace Sass {
|
|
|
2216
2549
|
{
|
|
2217
2550
|
std::string kwd(lexed);
|
|
2218
2551
|
|
|
2219
|
-
if (lexed == "@else") error("Invalid CSS: @else must come after @if"
|
|
2552
|
+
if (lexed == "@else") error("Invalid CSS: @else must come after @if");
|
|
2553
|
+
|
|
2554
|
+
// this whole branch is never hit via spec tests
|
|
2220
2555
|
|
|
2221
2556
|
Directive_Ptr at_rule = SASS_MEMORY_NEW(Directive, pstate, kwd);
|
|
2222
2557
|
Lookahead lookahead = lookahead_for_include(position);
|
|
2223
2558
|
if (lookahead.found && !lookahead.has_interpolants) {
|
|
2224
|
-
at_rule->selector(
|
|
2559
|
+
at_rule->selector(parse_selector_list(false));
|
|
2225
2560
|
}
|
|
2226
2561
|
|
|
2227
2562
|
lex < css_comments >(false);
|
|
2228
2563
|
|
|
2229
2564
|
if (lex < static_property >()) {
|
|
2230
|
-
at_rule->value(
|
|
2565
|
+
at_rule->value(parse_interpolated_chunk(Token(lexed)));
|
|
2231
2566
|
} else if (!(peek < alternatives < exactly<'{'>, exactly<'}'>, exactly<';'> > >())) {
|
|
2232
2567
|
at_rule->value(parse_list());
|
|
2233
2568
|
}
|
|
@@ -2241,24 +2576,25 @@ namespace Sass {
|
|
|
2241
2576
|
return at_rule;
|
|
2242
2577
|
}
|
|
2243
2578
|
|
|
2579
|
+
// this whole branch is never hit via spec tests
|
|
2244
2580
|
Directive_Obj Parser::parse_prefixed_directive()
|
|
2245
2581
|
{
|
|
2246
2582
|
std::string kwd(lexed);
|
|
2247
2583
|
|
|
2248
|
-
if (lexed == "@else") error("Invalid CSS: @else must come after @if"
|
|
2584
|
+
if (lexed == "@else") error("Invalid CSS: @else must come after @if");
|
|
2249
2585
|
|
|
2250
2586
|
Directive_Obj at_rule = SASS_MEMORY_NEW(Directive, pstate, kwd);
|
|
2251
2587
|
Lookahead lookahead = lookahead_for_include(position);
|
|
2252
2588
|
if (lookahead.found && !lookahead.has_interpolants) {
|
|
2253
|
-
at_rule->selector(
|
|
2589
|
+
at_rule->selector(parse_selector_list(false));
|
|
2254
2590
|
}
|
|
2255
2591
|
|
|
2256
2592
|
lex < css_comments >(false);
|
|
2257
2593
|
|
|
2258
2594
|
if (lex < static_property >()) {
|
|
2259
|
-
at_rule->value(
|
|
2595
|
+
at_rule->value(parse_interpolated_chunk(Token(lexed)));
|
|
2260
2596
|
} else if (!(peek < alternatives < exactly<'{'>, exactly<'}'>, exactly<';'> > >())) {
|
|
2261
|
-
at_rule->value(
|
|
2597
|
+
at_rule->value(parse_list());
|
|
2262
2598
|
}
|
|
2263
2599
|
|
|
2264
2600
|
lex < css_comments >(false);
|
|
@@ -2276,7 +2612,7 @@ namespace Sass {
|
|
|
2276
2612
|
Directive_Obj directive = SASS_MEMORY_NEW(Directive, pstate, lexed);
|
|
2277
2613
|
String_Schema_Obj val = parse_almost_any_value();
|
|
2278
2614
|
// strip left and right if they are of type string
|
|
2279
|
-
directive->value(
|
|
2615
|
+
directive->value(val);
|
|
2280
2616
|
if (peek< exactly<'{'> >()) {
|
|
2281
2617
|
directive->block(parse_block());
|
|
2282
2618
|
}
|
|
@@ -2286,7 +2622,7 @@ namespace Sass {
|
|
|
2286
2622
|
Expression_Obj Parser::lex_interpolation()
|
|
2287
2623
|
{
|
|
2288
2624
|
if (lex < interpolant >(true) != NULL) {
|
|
2289
|
-
return
|
|
2625
|
+
return parse_interpolated_chunk(lexed, true);
|
|
2290
2626
|
}
|
|
2291
2627
|
return 0;
|
|
2292
2628
|
}
|
|
@@ -2299,7 +2635,7 @@ namespace Sass {
|
|
|
2299
2635
|
|
|
2300
2636
|
Expression_Obj Parser::lex_interp_string()
|
|
2301
2637
|
{
|
|
2302
|
-
Expression_Obj rv
|
|
2638
|
+
Expression_Obj rv;
|
|
2303
2639
|
if ((rv = lex_interp< re_string_double_open, re_string_double_close >())) return rv;
|
|
2304
2640
|
if ((rv = lex_interp< re_string_single_open, re_string_single_close >())) return rv;
|
|
2305
2641
|
return rv;
|
|
@@ -2359,15 +2695,17 @@ namespace Sass {
|
|
|
2359
2695
|
|
|
2360
2696
|
Expression_Obj Parser::lex_almost_any_value_token()
|
|
2361
2697
|
{
|
|
2362
|
-
Expression_Obj rv
|
|
2698
|
+
Expression_Obj rv;
|
|
2363
2699
|
if (*position == 0) return 0;
|
|
2364
|
-
if ((rv =
|
|
2700
|
+
if ((rv = lex_almost_any_value_chars())) return rv;
|
|
2365
2701
|
// if ((rv = lex_block_comment())) return rv;
|
|
2366
2702
|
// if ((rv = lex_single_line_comment())) return rv;
|
|
2367
|
-
if ((rv =
|
|
2368
|
-
if ((rv =
|
|
2369
|
-
if ((rv =
|
|
2370
|
-
|
|
2703
|
+
if ((rv = lex_interp_string())) return rv;
|
|
2704
|
+
if ((rv = lex_interp_uri())) return rv;
|
|
2705
|
+
if ((rv = lex_interpolation())) return rv;
|
|
2706
|
+
if (lex< alternatives< hex, hex0 > >())
|
|
2707
|
+
{ return lexed_hex_color(lexed); }
|
|
2708
|
+
return rv;
|
|
2371
2709
|
}
|
|
2372
2710
|
|
|
2373
2711
|
String_Schema_Obj Parser::parse_almost_any_value()
|
|
@@ -2384,7 +2722,7 @@ namespace Sass {
|
|
|
2384
2722
|
return schema.detach();
|
|
2385
2723
|
}
|
|
2386
2724
|
|
|
2387
|
-
while ((token =
|
|
2725
|
+
while ((token = lex_almost_any_value_token())) {
|
|
2388
2726
|
schema->append(token);
|
|
2389
2727
|
}
|
|
2390
2728
|
|
|
@@ -2402,7 +2740,7 @@ namespace Sass {
|
|
|
2402
2740
|
stack.back() != Scope::Mixin &&
|
|
2403
2741
|
stack.back() != Scope::Control &&
|
|
2404
2742
|
stack.back() != Scope::Rules) {
|
|
2405
|
-
error("Illegal nesting: Only properties may be nested beneath properties."
|
|
2743
|
+
error("Illegal nesting: Only properties may be nested beneath properties.");
|
|
2406
2744
|
}
|
|
2407
2745
|
return SASS_MEMORY_NEW(Warning, pstate, parse_list(DELAYED));
|
|
2408
2746
|
}
|
|
@@ -2414,7 +2752,7 @@ namespace Sass {
|
|
|
2414
2752
|
stack.back() != Scope::Mixin &&
|
|
2415
2753
|
stack.back() != Scope::Control &&
|
|
2416
2754
|
stack.back() != Scope::Rules) {
|
|
2417
|
-
error("Illegal nesting: Only properties may be nested beneath properties."
|
|
2755
|
+
error("Illegal nesting: Only properties may be nested beneath properties.");
|
|
2418
2756
|
}
|
|
2419
2757
|
return SASS_MEMORY_NEW(Error, pstate, parse_list(DELAYED));
|
|
2420
2758
|
}
|
|
@@ -2426,7 +2764,7 @@ namespace Sass {
|
|
|
2426
2764
|
stack.back() != Scope::Mixin &&
|
|
2427
2765
|
stack.back() != Scope::Control &&
|
|
2428
2766
|
stack.back() != Scope::Rules) {
|
|
2429
|
-
error("Illegal nesting: Only properties may be nested beneath properties."
|
|
2767
|
+
error("Illegal nesting: Only properties may be nested beneath properties.");
|
|
2430
2768
|
}
|
|
2431
2769
|
return SASS_MEMORY_NEW(Debug, pstate, parse_list(DELAYED));
|
|
2432
2770
|
}
|
|
@@ -2436,7 +2774,7 @@ namespace Sass {
|
|
|
2436
2774
|
// check that we do not have an empty list (ToDo: check if we got all cases)
|
|
2437
2775
|
if (peek_css < alternatives < exactly < ';' >, exactly < '}' >, end_of_file > >())
|
|
2438
2776
|
{ css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was "); }
|
|
2439
|
-
return SASS_MEMORY_NEW(Return, pstate,
|
|
2777
|
+
return SASS_MEMORY_NEW(Return, pstate, parse_list());
|
|
2440
2778
|
}
|
|
2441
2779
|
|
|
2442
2780
|
Lookahead Parser::lookahead_for_selector(const char* start)
|
|
@@ -2452,12 +2790,20 @@ namespace Sass {
|
|
|
2452
2790
|
re_selector_list
|
|
2453
2791
|
>(p)
|
|
2454
2792
|
) {
|
|
2793
|
+
bool could_be_property = peek< sequence< exactly<'-'>, exactly<'-'> > >(p) != 0;
|
|
2794
|
+
bool could_be_escaped = false;
|
|
2455
2795
|
while (p < q) {
|
|
2456
2796
|
// did we have interpolations?
|
|
2457
2797
|
if (*p == '#' && *(p+1) == '{') {
|
|
2458
2798
|
rv.has_interpolants = true;
|
|
2459
2799
|
p = q; break;
|
|
2460
2800
|
}
|
|
2801
|
+
// A property that's ambiguous with a nested selector is interpreted as a
|
|
2802
|
+
// custom property.
|
|
2803
|
+
if (*p == ':' && !could_be_escaped) {
|
|
2804
|
+
rv.is_custom_property = could_be_property || p+1 == q || peek< space >(p+1);
|
|
2805
|
+
}
|
|
2806
|
+
could_be_escaped = *p == '\\';
|
|
2461
2807
|
++ p;
|
|
2462
2808
|
}
|
|
2463
2809
|
// store anyway }
|
|
@@ -2469,6 +2815,7 @@ namespace Sass {
|
|
|
2469
2815
|
// check expected opening bracket
|
|
2470
2816
|
// only after successfull matching
|
|
2471
2817
|
if (peek < exactly<'{'> >(q)) rv.found = q;
|
|
2818
|
+
// else if (peek < end_of_file >(q)) rv.found = q;
|
|
2472
2819
|
else if (peek < exactly<'('> >(q)) rv.found = q;
|
|
2473
2820
|
// else if (peek < exactly<';'> >(q)) rv.found = q;
|
|
2474
2821
|
// else if (peek < exactly<'}'> >(q)) rv.found = q;
|
|
@@ -2538,6 +2885,7 @@ namespace Sass {
|
|
|
2538
2885
|
sequence <
|
|
2539
2886
|
// optional_spaces,
|
|
2540
2887
|
alternatives <
|
|
2888
|
+
// end_of_file,
|
|
2541
2889
|
exactly<'{'>,
|
|
2542
2890
|
exactly<'}'>,
|
|
2543
2891
|
exactly<';'>
|
|
@@ -2622,8 +2970,9 @@ namespace Sass {
|
|
|
2622
2970
|
skip = check_bom_chars(source, end, gb_18030_bom, 4);
|
|
2623
2971
|
encoding = "GB-18030";
|
|
2624
2972
|
break;
|
|
2973
|
+
default: break;
|
|
2625
2974
|
}
|
|
2626
|
-
if (skip > 0 && !utf_8) error("only UTF-8 documents are currently supported; your document appears to be " + encoding
|
|
2975
|
+
if (skip > 0 && !utf_8) error("only UTF-8 documents are currently supported; your document appears to be " + encoding);
|
|
2627
2976
|
position += skip;
|
|
2628
2977
|
}
|
|
2629
2978
|
|
|
@@ -2641,14 +2990,14 @@ namespace Sass {
|
|
|
2641
2990
|
Expression_Obj Parser::fold_operands(Expression_Obj base, std::vector<Expression_Obj>& operands, Operand op)
|
|
2642
2991
|
{
|
|
2643
2992
|
for (size_t i = 0, S = operands.size(); i < S; ++i) {
|
|
2644
|
-
base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), op,
|
|
2993
|
+
base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), op, base, operands[i]);
|
|
2645
2994
|
}
|
|
2646
2995
|
return base;
|
|
2647
2996
|
}
|
|
2648
2997
|
|
|
2649
2998
|
Expression_Obj Parser::fold_operands(Expression_Obj base, std::vector<Expression_Obj>& operands, std::vector<Operand>& ops, size_t i)
|
|
2650
2999
|
{
|
|
2651
|
-
if (String_Schema_Ptr schema =
|
|
3000
|
+
if (String_Schema_Ptr schema = Cast<String_Schema>(base)) {
|
|
2652
3001
|
// return schema;
|
|
2653
3002
|
if (schema->has_interpolants()) {
|
|
2654
3003
|
if (i + 1 < operands.size() && (
|
|
@@ -2663,7 +3012,7 @@ namespace Sass {
|
|
|
2663
3012
|
|| (ops[0].operand == Sass_OP::GTE)
|
|
2664
3013
|
)) {
|
|
2665
3014
|
Expression_Obj rhs = fold_operands(operands[i], operands, ops, i + 1);
|
|
2666
|
-
rhs = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[0], schema,
|
|
3015
|
+
rhs = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[0], schema, rhs);
|
|
2667
3016
|
return rhs;
|
|
2668
3017
|
}
|
|
2669
3018
|
// return schema;
|
|
@@ -2671,54 +3020,64 @@ namespace Sass {
|
|
|
2671
3020
|
}
|
|
2672
3021
|
|
|
2673
3022
|
for (size_t S = operands.size(); i < S; ++i) {
|
|
2674
|
-
if (String_Schema_Ptr schema =
|
|
3023
|
+
if (String_Schema_Ptr schema = Cast<String_Schema>(operands[i])) {
|
|
2675
3024
|
if (schema->has_interpolants()) {
|
|
2676
3025
|
if (i + 1 < S) {
|
|
3026
|
+
// this whole branch is never hit via spec tests
|
|
2677
3027
|
Expression_Obj rhs = fold_operands(operands[i+1], operands, ops, i + 2);
|
|
2678
|
-
rhs = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], schema,
|
|
2679
|
-
base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i],
|
|
3028
|
+
rhs = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], schema, rhs);
|
|
3029
|
+
base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], base, rhs);
|
|
2680
3030
|
return base;
|
|
2681
3031
|
}
|
|
2682
|
-
base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i],
|
|
3032
|
+
base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], base, operands[i]);
|
|
2683
3033
|
return base;
|
|
2684
3034
|
} else {
|
|
2685
|
-
base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i],
|
|
3035
|
+
base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], base, operands[i]);
|
|
2686
3036
|
}
|
|
2687
3037
|
} else {
|
|
2688
|
-
base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i],
|
|
3038
|
+
base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], base, operands[i]);
|
|
2689
3039
|
}
|
|
2690
|
-
Binary_Expression_Ptr b =
|
|
3040
|
+
Binary_Expression_Ptr b = Cast<Binary_Expression>(base.ptr());
|
|
2691
3041
|
if (b && ops[i].operand == Sass_OP::DIV && b->left()->is_delayed() && b->right()->is_delayed()) {
|
|
2692
3042
|
base->is_delayed(true);
|
|
2693
3043
|
}
|
|
2694
3044
|
}
|
|
2695
3045
|
// nested binary expression are never to be delayed
|
|
2696
|
-
if (Binary_Expression_Ptr b =
|
|
2697
|
-
if (
|
|
2698
|
-
if (
|
|
3046
|
+
if (Binary_Expression_Ptr b = Cast<Binary_Expression>(base)) {
|
|
3047
|
+
if (Cast<Binary_Expression>(b->left())) base->set_delayed(false);
|
|
3048
|
+
if (Cast<Binary_Expression>(b->right())) base->set_delayed(false);
|
|
2699
3049
|
}
|
|
2700
3050
|
return base;
|
|
2701
3051
|
}
|
|
2702
3052
|
|
|
2703
3053
|
void Parser::error(std::string msg, Position pos)
|
|
2704
3054
|
{
|
|
2705
|
-
|
|
3055
|
+
Position p(pos.line ? pos : before_token);
|
|
3056
|
+
ParserState pstate(path, source, p, Offset(0, 0));
|
|
3057
|
+
traces.push_back(Backtrace(pstate));
|
|
3058
|
+
throw Exception::InvalidSass(pstate, traces, msg);
|
|
3059
|
+
}
|
|
3060
|
+
|
|
3061
|
+
void Parser::error(std::string msg)
|
|
3062
|
+
{
|
|
3063
|
+
error(msg, pstate);
|
|
2706
3064
|
}
|
|
2707
3065
|
|
|
2708
3066
|
// print a css parsing error with actual context information from parsed source
|
|
2709
|
-
void Parser::css_error(const std::string& msg, const std::string& prefix, const std::string& middle)
|
|
3067
|
+
void Parser::css_error(const std::string& msg, const std::string& prefix, const std::string& middle, const bool trim)
|
|
2710
3068
|
{
|
|
2711
3069
|
int max_len = 18;
|
|
2712
3070
|
const char* end = this->end;
|
|
2713
3071
|
while (*end != 0) ++ end;
|
|
2714
3072
|
const char* pos = peek < optional_spaces >();
|
|
3073
|
+
if (!pos) pos = position;
|
|
2715
3074
|
|
|
2716
3075
|
const char* last_pos(pos);
|
|
2717
3076
|
if (last_pos > source) {
|
|
2718
3077
|
utf8::prior(last_pos, source);
|
|
2719
3078
|
}
|
|
2720
3079
|
// backup position to last significant char
|
|
2721
|
-
while (last_pos > source && last_pos < end) {
|
|
3080
|
+
while (trim && last_pos > source && last_pos < end) {
|
|
2722
3081
|
if (!Prelexer::is_space(*last_pos)) break;
|
|
2723
3082
|
utf8::prior(last_pos, source);
|
|
2724
3083
|
}
|
|
@@ -2727,8 +3086,8 @@ namespace Sass {
|
|
|
2727
3086
|
const char* pos_left(last_pos);
|
|
2728
3087
|
const char* end_left(last_pos);
|
|
2729
3088
|
|
|
2730
|
-
utf8::next(pos_left, end);
|
|
2731
|
-
utf8::next(end_left, end);
|
|
3089
|
+
if (*pos_left) utf8::next(pos_left, end);
|
|
3090
|
+
if (*end_left) utf8::next(end_left, end);
|
|
2732
3091
|
while (pos_left > source) {
|
|
2733
3092
|
if (utf8::distance(pos_left, end_left) >= max_len) {
|
|
2734
3093
|
utf8::prior(pos_left, source);
|
|
@@ -2769,8 +3128,10 @@ namespace Sass {
|
|
|
2769
3128
|
size_t right_subpos = right.size() > 15 ? right.size() - 15 : 0;
|
|
2770
3129
|
if (left_subpos && ellipsis_left) left = ellipsis + left.substr(left_subpos);
|
|
2771
3130
|
if (right_subpos && ellipsis_right) right = right.substr(right_subpos) + ellipsis;
|
|
3131
|
+
// Hotfix when source is null, probably due to interpolation parsing!?
|
|
3132
|
+
if (source == NULL || *source == 0) source = pstate.src;
|
|
2772
3133
|
// now pass new message to the more generic error function
|
|
2773
|
-
error(msg + prefix + quote(left) + middle + quote(right)
|
|
3134
|
+
error(msg + prefix + quote(left) + middle + quote(right));
|
|
2774
3135
|
}
|
|
2775
3136
|
|
|
2776
3137
|
}
|