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