sassc 1.8.3 → 1.8.4
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/README.md +3 -1
- data/ext/libsass/.editorconfig +1 -1
- data/ext/libsass/.gitignore +1 -0
- data/ext/libsass/LICENSE +1 -1
- data/ext/libsass/Makefile +20 -14
- data/ext/libsass/Makefile.conf +0 -1
- data/ext/libsass/Readme.md +3 -1
- data/ext/libsass/appveyor.yml +19 -11
- data/ext/libsass/docs/api-importer-example.md +2 -1235
- data/ext/libsass/docs/build-with-autotools.md +10 -0
- data/ext/libsass/docs/build-with-makefiles.md +18 -0
- data/ext/libsass/include/sass/base.h +4 -1
- data/ext/libsass/include/sass/values.h +2 -1
- data/ext/libsass/src/ast.cpp +279 -346
- data/ext/libsass/src/ast.hpp +234 -60
- data/ext/libsass/src/base64vlq.cpp +1 -0
- data/ext/libsass/src/bind.cpp +35 -45
- data/ext/libsass/src/bind.hpp +1 -0
- data/ext/libsass/src/color_maps.cpp +1 -0
- data/ext/libsass/src/constants.cpp +4 -1
- data/ext/libsass/src/constants.hpp +2 -1
- data/ext/libsass/src/context.cpp +41 -31
- data/ext/libsass/src/context.hpp +10 -10
- data/ext/libsass/src/cssize.cpp +7 -4
- data/ext/libsass/src/cssize.hpp +1 -3
- data/ext/libsass/src/debugger.hpp +73 -14
- data/ext/libsass/src/emitter.cpp +37 -25
- data/ext/libsass/src/emitter.hpp +10 -9
- data/ext/libsass/src/environment.cpp +16 -5
- data/ext/libsass/src/environment.hpp +5 -3
- data/ext/libsass/src/error_handling.cpp +91 -14
- data/ext/libsass/src/error_handling.hpp +105 -4
- data/ext/libsass/src/eval.cpp +519 -330
- data/ext/libsass/src/eval.hpp +12 -13
- data/ext/libsass/src/expand.cpp +92 -56
- data/ext/libsass/src/expand.hpp +5 -3
- data/ext/libsass/src/extend.cpp +60 -51
- data/ext/libsass/src/extend.hpp +1 -3
- data/ext/libsass/src/file.cpp +37 -27
- data/ext/libsass/src/functions.cpp +78 -62
- data/ext/libsass/src/functions.hpp +1 -0
- data/ext/libsass/src/inspect.cpp +293 -64
- data/ext/libsass/src/inspect.hpp +2 -0
- data/ext/libsass/src/lexer.cpp +1 -0
- data/ext/libsass/src/listize.cpp +14 -15
- data/ext/libsass/src/listize.hpp +3 -5
- data/ext/libsass/src/memory_manager.cpp +1 -0
- data/ext/libsass/src/node.cpp +2 -3
- data/ext/libsass/src/operation.hpp +70 -71
- data/ext/libsass/src/output.cpp +28 -32
- data/ext/libsass/src/output.hpp +1 -2
- data/ext/libsass/src/parser.cpp +402 -183
- data/ext/libsass/src/parser.hpp +19 -9
- data/ext/libsass/src/plugins.cpp +1 -0
- data/ext/libsass/src/position.cpp +1 -0
- data/ext/libsass/src/prelexer.cpp +134 -56
- data/ext/libsass/src/prelexer.hpp +51 -3
- data/ext/libsass/src/remove_placeholders.cpp +35 -9
- data/ext/libsass/src/remove_placeholders.hpp +4 -3
- data/ext/libsass/src/sass.cpp +1 -0
- data/ext/libsass/src/sass.hpp +129 -0
- data/ext/libsass/src/sass_context.cpp +31 -14
- data/ext/libsass/src/sass_context.hpp +2 -31
- data/ext/libsass/src/sass_functions.cpp +1 -0
- data/ext/libsass/src/sass_interface.cpp +5 -6
- data/ext/libsass/src/sass_util.cpp +1 -2
- data/ext/libsass/src/sass_util.hpp +5 -5
- data/ext/libsass/src/sass_values.cpp +13 -10
- data/ext/libsass/src/source_map.cpp +4 -3
- data/ext/libsass/src/source_map.hpp +2 -2
- data/ext/libsass/src/subset_map.hpp +0 -1
- data/ext/libsass/src/to_c.cpp +1 -0
- data/ext/libsass/src/to_c.hpp +1 -3
- data/ext/libsass/src/to_value.cpp +3 -5
- data/ext/libsass/src/to_value.hpp +1 -1
- data/ext/libsass/src/units.cpp +96 -59
- data/ext/libsass/src/units.hpp +10 -8
- data/ext/libsass/src/utf8_string.cpp +5 -0
- data/ext/libsass/src/util.cpp +23 -156
- data/ext/libsass/src/util.hpp +10 -14
- data/ext/libsass/src/values.cpp +1 -0
- data/ext/libsass/test/test_node.cpp +2 -6
- data/ext/libsass/test/test_selector_difference.cpp +1 -3
- data/ext/libsass/test/test_specificity.cpp +0 -2
- data/ext/libsass/test/test_superselector.cpp +0 -2
- data/ext/libsass/test/test_unification.cpp +1 -3
- data/ext/libsass/win/libsass.targets +18 -5
- data/ext/libsass/win/libsass.vcxproj +9 -7
- data/ext/libsass/win/libsass.vcxproj.filters +148 -106
- data/lib/sassc/version.rb +1 -1
- data/test/engine_test.rb +12 -0
- data/test/native_test.rb +1 -1
- metadata +3 -4
- data/ext/libsass/src/to_string.cpp +0 -48
- data/ext/libsass/src/to_string.hpp +0 -38
data/ext/libsass/src/output.hpp
CHANGED
data/ext/libsass/src/parser.cpp
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
#include "sass.hpp"
|
|
1
2
|
#include <cstdlib>
|
|
2
3
|
#include <iostream>
|
|
3
4
|
#include <vector>
|
|
4
5
|
#include "parser.hpp"
|
|
5
6
|
#include "file.hpp"
|
|
6
7
|
#include "inspect.hpp"
|
|
7
|
-
#include "to_string.hpp"
|
|
8
8
|
#include "constants.hpp"
|
|
9
9
|
#include "util.hpp"
|
|
10
10
|
#include "prelexer.hpp"
|
|
@@ -19,33 +19,33 @@ namespace Sass {
|
|
|
19
19
|
using namespace Constants;
|
|
20
20
|
using namespace Prelexer;
|
|
21
21
|
|
|
22
|
-
Parser Parser::from_c_str(const char*
|
|
22
|
+
Parser Parser::from_c_str(const char* beg, Context& ctx, ParserState pstate, const char* source)
|
|
23
23
|
{
|
|
24
24
|
Parser p(ctx, pstate);
|
|
25
|
-
p.source =
|
|
26
|
-
p.position = p.source;
|
|
27
|
-
p.end =
|
|
25
|
+
p.source = source ? source : beg;
|
|
26
|
+
p.position = beg ? beg : p.source;
|
|
27
|
+
p.end = p.position + strlen(p.position);
|
|
28
28
|
Block* root = SASS_MEMORY_NEW(ctx.mem, Block, pstate);
|
|
29
29
|
p.block_stack.push_back(root);
|
|
30
30
|
root->is_root(true);
|
|
31
31
|
return p;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
Parser Parser::from_c_str(const char* beg, const char* end, Context& ctx, ParserState pstate)
|
|
34
|
+
Parser Parser::from_c_str(const char* beg, const char* end, Context& ctx, ParserState pstate, const char* source)
|
|
35
35
|
{
|
|
36
36
|
Parser p(ctx, pstate);
|
|
37
|
-
p.source = beg;
|
|
38
|
-
p.position = p.source;
|
|
39
|
-
p.end = end;
|
|
37
|
+
p.source = source ? source : beg;
|
|
38
|
+
p.position = beg ? beg : p.source;
|
|
39
|
+
p.end = end ? end : p.position + strlen(p.position);
|
|
40
40
|
Block* root = SASS_MEMORY_NEW(ctx.mem, Block, pstate);
|
|
41
41
|
p.block_stack.push_back(root);
|
|
42
42
|
root->is_root(true);
|
|
43
43
|
return p;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
Selector_List* Parser::parse_selector(const char*
|
|
46
|
+
Selector_List* Parser::parse_selector(const char* beg, Context& ctx, ParserState pstate, const char* source)
|
|
47
47
|
{
|
|
48
|
-
Parser p = Parser::from_c_str(
|
|
48
|
+
Parser p = Parser::from_c_str(beg, ctx, pstate, source);
|
|
49
49
|
// ToDo: ruby sass errors on parent references
|
|
50
50
|
// ToDo: remap the source-map entries somehow
|
|
51
51
|
return p.parse_selector_list(false);
|
|
@@ -57,12 +57,12 @@ namespace Sass {
|
|
|
57
57
|
&& ! peek_css<exactly<'{'>>(start);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
Parser Parser::from_token(Token t, Context& ctx, ParserState pstate)
|
|
60
|
+
Parser Parser::from_token(Token t, Context& ctx, ParserState pstate, const char* source)
|
|
61
61
|
{
|
|
62
62
|
Parser p(ctx, pstate);
|
|
63
|
-
p.source = t.begin;
|
|
64
|
-
p.position = p.source;
|
|
65
|
-
p.end = t.end;
|
|
63
|
+
p.source = source ? source : t.begin;
|
|
64
|
+
p.position = t.begin ? t.begin : p.source;
|
|
65
|
+
p.end = t.end ? t.end : p.position + strlen(p.position);
|
|
66
66
|
Block* root = SASS_MEMORY_NEW(ctx.mem, Block, pstate);
|
|
67
67
|
p.block_stack.push_back(root);
|
|
68
68
|
root->is_root(true);
|
|
@@ -177,11 +177,7 @@ namespace Sass {
|
|
|
177
177
|
|
|
178
178
|
Block* block = block_stack.back();
|
|
179
179
|
|
|
180
|
-
|
|
181
|
-
bool is_important = lexed.begin[2] == '!';
|
|
182
|
-
String* contents = parse_interpolated_chunk(lexed);
|
|
183
|
-
(*block) << SASS_MEMORY_NEW(ctx.mem, Comment, pstate, contents, is_important);
|
|
184
|
-
}
|
|
180
|
+
parse_block_comments();
|
|
185
181
|
|
|
186
182
|
// throw away white-space
|
|
187
183
|
// includes line comments
|
|
@@ -203,14 +199,17 @@ namespace Sass {
|
|
|
203
199
|
else if (lex < kwd_return_directive >(true)) { (*block) << parse_return_directive(); }
|
|
204
200
|
|
|
205
201
|
// abort if we are in function context and have nothing parsed yet
|
|
206
|
-
else if (stack.back() ==
|
|
202
|
+
else if (stack.back() == Scope::Function) {
|
|
207
203
|
error("Functions can only contain variable declarations and control directives", pstate);
|
|
208
204
|
}
|
|
209
205
|
|
|
210
206
|
// parse imports to process later
|
|
211
207
|
else if (lex < kwd_import >(true)) {
|
|
212
|
-
|
|
213
|
-
|
|
208
|
+
Scope parent = stack.empty() ? Scope::Rules : stack.back();
|
|
209
|
+
if (parent != Scope::Function && parent != Scope::Root && parent != Scope::Rules && parent != Scope::Media) {
|
|
210
|
+
if (! peek_css< uri_prefix >(position)) { // this seems to go in ruby sass 3.4.20
|
|
211
|
+
error("Import directives may not be used within control directives or mixins.", pstate);
|
|
212
|
+
}
|
|
214
213
|
}
|
|
215
214
|
Import* imp = parse_import();
|
|
216
215
|
// if it is a url, we only add the statement
|
|
@@ -222,7 +221,8 @@ namespace Sass {
|
|
|
222
221
|
}
|
|
223
222
|
|
|
224
223
|
else if (lex < kwd_extend >(true)) {
|
|
225
|
-
|
|
224
|
+
Scope parent = stack.empty() ? Scope::Rules : stack.back();
|
|
225
|
+
if (parent == Scope::Root) {
|
|
226
226
|
error("Extend directives may only be used within rules.", pstate);
|
|
227
227
|
}
|
|
228
228
|
|
|
@@ -270,7 +270,9 @@ namespace Sass {
|
|
|
270
270
|
if (peek< exactly<'{'> >()) {
|
|
271
271
|
if (decl->is_indented()) ++ indentation;
|
|
272
272
|
// parse a propset that rides on the declaration's property
|
|
273
|
+
stack.push_back(Scope::Properties);
|
|
273
274
|
(*block) << SASS_MEMORY_NEW(ctx.mem, Propset, pstate, decl->property(), parse_block());
|
|
275
|
+
stack.pop_back();
|
|
274
276
|
if (decl->is_indented()) -- indentation;
|
|
275
277
|
}
|
|
276
278
|
}
|
|
@@ -298,12 +300,12 @@ namespace Sass {
|
|
|
298
300
|
else if (lex< uri_prefix >()) {
|
|
299
301
|
Arguments* args = SASS_MEMORY_NEW(ctx.mem, Arguments, pstate);
|
|
300
302
|
Function_Call* result = SASS_MEMORY_NEW(ctx.mem, Function_Call, pstate, "url", args);
|
|
303
|
+
|
|
301
304
|
if (lex< quoted_string >()) {
|
|
302
305
|
Expression* the_url = parse_string();
|
|
303
306
|
*args << SASS_MEMORY_NEW(ctx.mem, Argument, the_url->pstate(), the_url);
|
|
304
307
|
}
|
|
305
|
-
else if (
|
|
306
|
-
String* the_url = parse_interpolated_chunk(lexed);
|
|
308
|
+
else if (String* the_url = parse_url_function_argument()) {
|
|
307
309
|
*args << SASS_MEMORY_NEW(ctx.mem, Argument, the_url->pstate(), the_url);
|
|
308
310
|
}
|
|
309
311
|
else if (peek < skip_over_scopes < exactly < '(' >, exactly < ')' > > >(position)) {
|
|
@@ -341,6 +343,10 @@ namespace Sass {
|
|
|
341
343
|
|
|
342
344
|
Definition* Parser::parse_definition(Definition::Type which_type)
|
|
343
345
|
{
|
|
346
|
+
Scope parent = stack.empty() ? Scope::Rules : stack.back();
|
|
347
|
+
if (parent != Scope::Root && parent != Scope::Rules && parent != Scope::Function) {
|
|
348
|
+
error("Functions may not be defined within control directives or other mixins.", pstate);
|
|
349
|
+
}
|
|
344
350
|
std::string which_str(lexed);
|
|
345
351
|
if (!lex< identifier >()) error("invalid name in " + which_str + " definition", pstate);
|
|
346
352
|
std::string name(Util::normalize_underscores(lexed));
|
|
@@ -348,8 +354,8 @@ namespace Sass {
|
|
|
348
354
|
{ error("Invalid function name \"" + name + "\".", pstate); }
|
|
349
355
|
ParserState source_position_of_def = pstate;
|
|
350
356
|
Parameters* params = parse_parameters();
|
|
351
|
-
if (which_type == Definition::MIXIN) stack.push_back(
|
|
352
|
-
else stack.push_back(
|
|
357
|
+
if (which_type == Definition::MIXIN) stack.push_back(Scope::Mixin);
|
|
358
|
+
else stack.push_back(Scope::Function);
|
|
353
359
|
Block* body = parse_block();
|
|
354
360
|
stack.pop_back();
|
|
355
361
|
Definition* def = SASS_MEMORY_NEW(ctx.mem, Definition, source_position_of_def, name, params, body, which_type);
|
|
@@ -431,8 +437,11 @@ namespace Sass {
|
|
|
431
437
|
bool is_keyword = false;
|
|
432
438
|
Expression* val = parse_space_list();
|
|
433
439
|
val->is_delayed(false);
|
|
440
|
+
List* l = dynamic_cast<List*>(val);
|
|
434
441
|
if (lex_css< exactly< ellipsis > >()) {
|
|
435
|
-
if (val->concrete_type() == Expression::MAP
|
|
442
|
+
if (val->concrete_type() == Expression::MAP || (
|
|
443
|
+
(l != NULL && l->separator() == SASS_HASH)
|
|
444
|
+
)) is_keyword = true;
|
|
436
445
|
else is_arglist = true;
|
|
437
446
|
}
|
|
438
447
|
arg = SASS_MEMORY_NEW(ctx.mem, Argument, pstate, val, "", is_arglist, is_keyword);
|
|
@@ -474,7 +483,9 @@ namespace Sass {
|
|
|
474
483
|
if (lookahead.parsable) ruleset->selector(parse_selector_list(is_root));
|
|
475
484
|
else ruleset->selector(parse_selector_schema(lookahead.found));
|
|
476
485
|
// then parse the inner block
|
|
486
|
+
stack.push_back(Scope::Rules);
|
|
477
487
|
ruleset->block(parse_block());
|
|
488
|
+
stack.pop_back();
|
|
478
489
|
// update for end position
|
|
479
490
|
ruleset->update_pstate(pstate);
|
|
480
491
|
// inherit is_root from parent block
|
|
@@ -501,7 +512,7 @@ namespace Sass {
|
|
|
501
512
|
// process until end
|
|
502
513
|
while (i < end_of_selector) {
|
|
503
514
|
// try to parse mutliple interpolants
|
|
504
|
-
if (const char* p = find_first_in_interval< exactly<hash_lbrace
|
|
515
|
+
if (const char* p = find_first_in_interval< exactly<hash_lbrace>, block_comment >(i, end_of_selector)) {
|
|
505
516
|
// accumulate the preceding segment if the position has advanced
|
|
506
517
|
if (i < p) (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, std::string(i, p));
|
|
507
518
|
// check if the interpolation only contains white-space (error out)
|
|
@@ -514,6 +525,7 @@ namespace Sass {
|
|
|
514
525
|
Expression* interpolant = Parser::from_c_str(p+2, j, ctx, pstate).parse_list();
|
|
515
526
|
// set status on the list expression
|
|
516
527
|
interpolant->is_interpolant(true);
|
|
528
|
+
// schema->has_interpolants(true);
|
|
517
529
|
// add to the string schema
|
|
518
530
|
(*schema) << interpolant;
|
|
519
531
|
// advance position
|
|
@@ -579,7 +591,6 @@ namespace Sass {
|
|
|
579
591
|
bool reloop = true;
|
|
580
592
|
bool had_linefeed = false;
|
|
581
593
|
Complex_Selector* sel = 0;
|
|
582
|
-
To_String to_string(&ctx);
|
|
583
594
|
Selector_List* group = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate);
|
|
584
595
|
group->media_block(last_media_block);
|
|
585
596
|
|
|
@@ -676,14 +687,14 @@ namespace Sass {
|
|
|
676
687
|
sel->tail(parse_complex_selector(true));
|
|
677
688
|
if (sel->tail()) {
|
|
678
689
|
// ToDo: move this logic below into tail setter
|
|
679
|
-
if (sel->tail()->has_reference()) sel->has_reference(true);
|
|
690
|
+
// if (sel->tail()->has_reference()) sel->has_reference(true);
|
|
680
691
|
if (sel->tail()->has_placeholder()) sel->has_placeholder(true);
|
|
681
692
|
}
|
|
682
693
|
}
|
|
683
694
|
|
|
684
695
|
// add a parent selector if we are not in a root
|
|
685
696
|
// also skip adding parent ref if we only have refs
|
|
686
|
-
if (!sel->
|
|
697
|
+
if (!sel->has_parent_ref() && !in_at_root && !in_root) {
|
|
687
698
|
// create the objects to wrap parent selector reference
|
|
688
699
|
Parent_Selector* parent = SASS_MEMORY_NEW(ctx.mem, Parent_Selector, pstate);
|
|
689
700
|
parent->media_block(last_media_block);
|
|
@@ -725,7 +736,7 @@ namespace Sass {
|
|
|
725
736
|
// remove all block comments (don't skip white-space)
|
|
726
737
|
lex< delimited_by< slash_star, star_slash, false > >(false);
|
|
727
738
|
// parse functional
|
|
728
|
-
if (
|
|
739
|
+
if (match < re_pseudo_selector >())
|
|
729
740
|
{
|
|
730
741
|
(*seq) << parse_simple_selector();
|
|
731
742
|
}
|
|
@@ -735,6 +746,18 @@ namespace Sass {
|
|
|
735
746
|
// this produces a linefeed!?
|
|
736
747
|
seq->has_parent_reference(true);
|
|
737
748
|
(*seq) << SASS_MEMORY_NEW(ctx.mem, Parent_Selector, pstate);
|
|
749
|
+
// parent selector only allowed at start
|
|
750
|
+
// upcoming sass may allow also trailing
|
|
751
|
+
if (seq->length() > 1) {
|
|
752
|
+
ParserState state(pstate);
|
|
753
|
+
Simple_Selector* cur = (*seq)[seq->length()-1];
|
|
754
|
+
Simple_Selector* prev = (*seq)[seq->length()-2];
|
|
755
|
+
std::string sel(prev->to_string({ NESTED, 5 }));
|
|
756
|
+
std::string found(cur->to_string({ NESTED, 5 }));
|
|
757
|
+
if (lex < identifier >()) { found += std::string(lexed); }
|
|
758
|
+
error("Invalid CSS after \"" + sel + "\": expected \"{\", was \"" + found + "\"\n\n"
|
|
759
|
+
"\"" + found + "\" may only be used at the beginning of a compound selector.", state);
|
|
760
|
+
}
|
|
738
761
|
}
|
|
739
762
|
// parse type selector
|
|
740
763
|
else if (lex< re_type_selector >(false))
|
|
@@ -901,7 +924,8 @@ namespace Sass {
|
|
|
901
924
|
Block* block = block_stack.back();
|
|
902
925
|
while (lex< block_comment >()) {
|
|
903
926
|
bool is_important = lexed.begin[2] == '!';
|
|
904
|
-
|
|
927
|
+
// flag on second param is to skip loosely over comments
|
|
928
|
+
String* contents = parse_interpolated_chunk(lexed, true);
|
|
905
929
|
(*block) << SASS_MEMORY_NEW(ctx.mem, Comment, pstate, contents, is_important);
|
|
906
930
|
}
|
|
907
931
|
}
|
|
@@ -971,7 +995,7 @@ namespace Sass {
|
|
|
971
995
|
Expression* Parser::parse_map()
|
|
972
996
|
{
|
|
973
997
|
Expression* key = parse_list();
|
|
974
|
-
|
|
998
|
+
List* map = SASS_MEMORY_NEW(ctx.mem, List, pstate, 0, SASS_HASH);
|
|
975
999
|
if (String_Quoted* str = dynamic_cast<String_Quoted*>(key)) {
|
|
976
1000
|
if (!str->quote_mark() && !str->is_delayed()) {
|
|
977
1001
|
if (const Color* col = name_to_color(str->value())) {
|
|
@@ -984,14 +1008,12 @@ namespace Sass {
|
|
|
984
1008
|
}
|
|
985
1009
|
|
|
986
1010
|
// it's not a map so return the lexed value as a list value
|
|
987
|
-
if (!
|
|
1011
|
+
if (!lex_css< exactly<':'> >())
|
|
988
1012
|
{ return key; }
|
|
989
1013
|
|
|
990
|
-
lex< exactly<':'> >();
|
|
991
|
-
|
|
992
1014
|
Expression* value = parse_space_list();
|
|
993
1015
|
|
|
994
|
-
(*map) <<
|
|
1016
|
+
(*map) << key << value;
|
|
995
1017
|
|
|
996
1018
|
while (lex_css< exactly<','> >())
|
|
997
1019
|
{
|
|
@@ -1016,7 +1038,7 @@ namespace Sass {
|
|
|
1016
1038
|
|
|
1017
1039
|
Expression* value = parse_space_list();
|
|
1018
1040
|
|
|
1019
|
-
(*map) <<
|
|
1041
|
+
(*map) << key << value;
|
|
1020
1042
|
}
|
|
1021
1043
|
|
|
1022
1044
|
ParserState ps = map->pstate();
|
|
@@ -1047,6 +1069,7 @@ namespace Sass {
|
|
|
1047
1069
|
exactly<'{'>,
|
|
1048
1070
|
exactly<')'>,
|
|
1049
1071
|
exactly<':'>,
|
|
1072
|
+
end_of_file,
|
|
1050
1073
|
exactly<ellipsis>,
|
|
1051
1074
|
default_flag,
|
|
1052
1075
|
global_flag
|
|
@@ -1072,6 +1095,7 @@ namespace Sass {
|
|
|
1072
1095
|
exactly<'{'>,
|
|
1073
1096
|
exactly<')'>,
|
|
1074
1097
|
exactly<':'>,
|
|
1098
|
+
end_of_file,
|
|
1075
1099
|
exactly<ellipsis>,
|
|
1076
1100
|
default_flag,
|
|
1077
1101
|
global_flag
|
|
@@ -1098,6 +1122,7 @@ namespace Sass {
|
|
|
1098
1122
|
exactly<')'>,
|
|
1099
1123
|
exactly<','>,
|
|
1100
1124
|
exactly<':'>,
|
|
1125
|
+
end_of_file,
|
|
1101
1126
|
exactly<ellipsis>,
|
|
1102
1127
|
default_flag,
|
|
1103
1128
|
global_flag
|
|
@@ -1115,6 +1140,7 @@ namespace Sass {
|
|
|
1115
1140
|
exactly<')'>,
|
|
1116
1141
|
exactly<','>,
|
|
1117
1142
|
exactly<':'>,
|
|
1143
|
+
end_of_file,
|
|
1118
1144
|
exactly<ellipsis>,
|
|
1119
1145
|
default_flag,
|
|
1120
1146
|
global_flag
|
|
@@ -1140,7 +1166,7 @@ namespace Sass {
|
|
|
1140
1166
|
// if it's a singleton, return it directly
|
|
1141
1167
|
if (operands.size() == 0) return conj;
|
|
1142
1168
|
// fold all operands into one binary expression
|
|
1143
|
-
return fold_operands(conj, operands, Sass_OP::OR);
|
|
1169
|
+
return fold_operands(conj, operands, { Sass_OP::OR });
|
|
1144
1170
|
}
|
|
1145
1171
|
// EO parse_disjunction
|
|
1146
1172
|
|
|
@@ -1156,7 +1182,7 @@ namespace Sass {
|
|
|
1156
1182
|
// if it's a singleton, return it directly
|
|
1157
1183
|
if (operands.size() == 0) return rel;
|
|
1158
1184
|
// fold all operands into one binary expression
|
|
1159
|
-
return fold_operands(rel, operands, Sass_OP::AND);
|
|
1185
|
+
return fold_operands(rel, operands, { Sass_OP::AND });
|
|
1160
1186
|
}
|
|
1161
1187
|
// EO parse_conjunction
|
|
1162
1188
|
|
|
@@ -1165,30 +1191,38 @@ namespace Sass {
|
|
|
1165
1191
|
{
|
|
1166
1192
|
// parse the left hand side expression
|
|
1167
1193
|
Expression* lhs = parse_expression();
|
|
1194
|
+
std::vector<Expression*> operands;
|
|
1195
|
+
std::vector<Operand> operators;
|
|
1168
1196
|
// if it's a singleton, return it (don't wrap it)
|
|
1169
|
-
|
|
1197
|
+
while (peek< alternatives <
|
|
1170
1198
|
kwd_eq,
|
|
1171
1199
|
kwd_neq,
|
|
1172
1200
|
kwd_gte,
|
|
1173
1201
|
kwd_gt,
|
|
1174
1202
|
kwd_lte,
|
|
1175
1203
|
kwd_lt
|
|
1176
|
-
> >(position))
|
|
1177
|
-
{
|
|
1204
|
+
> >(position))
|
|
1205
|
+
{
|
|
1206
|
+
// is directly adjancent to expression?
|
|
1207
|
+
bool left_ws = peek < css_comments >() != NULL;
|
|
1208
|
+
// parse the operator
|
|
1209
|
+
enum Sass_OP op
|
|
1210
|
+
= lex<kwd_eq>() ? Sass_OP::EQ
|
|
1211
|
+
: lex<kwd_neq>() ? Sass_OP::NEQ
|
|
1212
|
+
: lex<kwd_gte>() ? Sass_OP::GTE
|
|
1213
|
+
: lex<kwd_lte>() ? Sass_OP::LTE
|
|
1214
|
+
: lex<kwd_gt>() ? Sass_OP::GT
|
|
1215
|
+
: lex<kwd_lt>() ? Sass_OP::LT
|
|
1216
|
+
// we checked the possibilites on top of fn
|
|
1217
|
+
: Sass_OP::EQ;
|
|
1218
|
+
// is directly adjancent to expression?
|
|
1219
|
+
bool right_ws = peek < css_comments >() != NULL;
|
|
1220
|
+
operators.push_back({ op, left_ws, right_ws });
|
|
1221
|
+
operands.push_back(parse_expression());
|
|
1222
|
+
left_ws = peek < css_comments >() != NULL;
|
|
1223
|
+
}
|
|
1178
1224
|
// parse the operator
|
|
1179
|
-
|
|
1180
|
-
= lex<kwd_eq>() ? Sass_OP::EQ
|
|
1181
|
-
: lex<kwd_neq>() ? Sass_OP::NEQ
|
|
1182
|
-
: lex<kwd_gte>() ? Sass_OP::GTE
|
|
1183
|
-
: lex<kwd_lte>() ? Sass_OP::LTE
|
|
1184
|
-
: lex<kwd_gt>() ? Sass_OP::GT
|
|
1185
|
-
: lex<kwd_lt>() ? Sass_OP::LT
|
|
1186
|
-
// we checked the possibilites on top of fn
|
|
1187
|
-
: Sass_OP::EQ;
|
|
1188
|
-
// parse the right hand side expression
|
|
1189
|
-
Expression* rhs = parse_expression();
|
|
1190
|
-
// return binary expression with a left and a right hand side
|
|
1191
|
-
return SASS_MEMORY_NEW(ctx.mem, Binary_Expression, lhs->pstate(), op, lhs, rhs);
|
|
1225
|
+
return fold_operands(lhs, operands, operators);
|
|
1192
1226
|
}
|
|
1193
1227
|
// parse_relation
|
|
1194
1228
|
|
|
@@ -1199,20 +1233,37 @@ namespace Sass {
|
|
|
1199
1233
|
// parse addition and subtraction operations
|
|
1200
1234
|
Expression* Parser::parse_expression()
|
|
1201
1235
|
{
|
|
1236
|
+
// parses multiple add and subtract operations
|
|
1237
|
+
// NOTE: make sure that identifiers starting with
|
|
1238
|
+
// NOTE: dashes do NOT count as subtract operation
|
|
1202
1239
|
Expression* lhs = parse_operators();
|
|
1203
1240
|
// if it's a singleton, return it (don't wrap it)
|
|
1204
|
-
if (
|
|
1241
|
+
// if it's a singleton, return it (don't wrap it)
|
|
1242
|
+
if (!(peek_css< exactly<'+'> >(position) ||
|
|
1205
1243
|
// condition is a bit misterious, but some combinations should not be counted as operations
|
|
1206
1244
|
(peek< no_spaces >(position) && peek< sequence< negate< unsigned_number >, exactly<'-'>, negate< space > > >(position)) ||
|
|
1207
1245
|
(peek< sequence< negate< unsigned_number >, exactly<'-'>, negate< unsigned_number > > >(position))) ||
|
|
1208
|
-
peek< identifier >(position))
|
|
1246
|
+
peek< sequence < zero_plus < exactly <'-' > >, identifier > >(position))
|
|
1209
1247
|
{ return lhs; }
|
|
1210
1248
|
|
|
1211
1249
|
std::vector<Expression*> operands;
|
|
1212
|
-
std::vector<
|
|
1213
|
-
|
|
1214
|
-
|
|
1250
|
+
std::vector<Operand> operators;
|
|
1251
|
+
bool left_ws = peek < css_comments >() != NULL;
|
|
1252
|
+
while (
|
|
1253
|
+
lex_css< exactly<'+'> >() ||
|
|
1254
|
+
|
|
1255
|
+
(
|
|
1256
|
+
! peek_css< sequence < zero_plus < exactly <'-' > >, identifier > >(position)
|
|
1257
|
+
&& lex_css< sequence< negate< digit >, exactly<'-'> > >()
|
|
1258
|
+
)
|
|
1259
|
+
|
|
1260
|
+
) {
|
|
1261
|
+
|
|
1262
|
+
|
|
1263
|
+
bool right_ws = peek < css_comments >() != NULL;
|
|
1264
|
+
operators.push_back({ lexed.to_string() == "+" ? Sass_OP::ADD : Sass_OP::SUB, left_ws, right_ws });
|
|
1215
1265
|
operands.push_back(parse_operators());
|
|
1266
|
+
left_ws = peek < css_comments >() != NULL;
|
|
1216
1267
|
}
|
|
1217
1268
|
|
|
1218
1269
|
if (operands.size() == 0) return lhs;
|
|
@@ -1223,25 +1274,21 @@ namespace Sass {
|
|
|
1223
1274
|
Expression* Parser::parse_operators()
|
|
1224
1275
|
{
|
|
1225
1276
|
Expression* factor = parse_factor();
|
|
1226
|
-
// Special case: Ruby sass never tries to modulo if the lhs contains an interpolant
|
|
1227
|
-
if (peek_css< exactly<'%'> >() && factor->concrete_type() == Expression::STRING) {
|
|
1228
|
-
String_Schema* ss = dynamic_cast<String_Schema*>(factor);
|
|
1229
|
-
if (ss && ss->has_interpolants()) return factor;
|
|
1230
|
-
}
|
|
1231
1277
|
// if it's a singleton, return it (don't wrap it)
|
|
1232
|
-
if (!peek_css< class_char< static_ops > >()) return factor;
|
|
1233
|
-
// parse more factors and operators
|
|
1234
1278
|
std::vector<Expression*> operands; // factors
|
|
1235
|
-
std::vector<
|
|
1279
|
+
std::vector<Operand> operators; // ops
|
|
1236
1280
|
// lex operations to apply to lhs
|
|
1281
|
+
const char* left_ws = peek < css_comments >();
|
|
1237
1282
|
while (lex_css< class_char< static_ops > >()) {
|
|
1283
|
+
const char* right_ws = peek < css_comments >();
|
|
1238
1284
|
switch(*lexed.begin) {
|
|
1239
|
-
case '*': operators.push_back(Sass_OP::MUL); break;
|
|
1240
|
-
case '/': operators.push_back(Sass_OP::DIV); break;
|
|
1241
|
-
case '%': operators.push_back(Sass_OP::MOD); break;
|
|
1285
|
+
case '*': operators.push_back({ Sass_OP::MUL, left_ws != 0, right_ws != 0 }); break;
|
|
1286
|
+
case '/': operators.push_back({ Sass_OP::DIV, left_ws != 0, right_ws != 0 }); break;
|
|
1287
|
+
case '%': operators.push_back({ Sass_OP::MOD, left_ws != 0, right_ws != 0 }); break;
|
|
1242
1288
|
default: throw std::runtime_error("unknown static op parsed"); break;
|
|
1243
1289
|
}
|
|
1244
1290
|
operands.push_back(parse_factor());
|
|
1291
|
+
left_ws = peek < css_comments >();
|
|
1245
1292
|
}
|
|
1246
1293
|
// operands and operators to binary expression
|
|
1247
1294
|
return fold_operands(factor, operands, operators);
|
|
@@ -1260,18 +1307,21 @@ namespace Sass {
|
|
|
1260
1307
|
// lex the expected closing parenthesis
|
|
1261
1308
|
if (!lex_css< exactly<')'> >()) error("unclosed parenthesis", pstate);
|
|
1262
1309
|
// expression can be evaluated
|
|
1263
|
-
|
|
1310
|
+
// make sure wrapped lists and division expressions are non-delayed within parentheses
|
|
1264
1311
|
// make sure wrapped lists and division expressions are non-delayed within parentheses
|
|
1265
1312
|
if (value->concrete_type() == Expression::LIST) {
|
|
1266
|
-
List* l = static_cast<List*>(value);
|
|
1267
|
-
if (!l->empty()) (*l)[0]->is_delayed(false);
|
|
1313
|
+
// List* l = static_cast<List*>(value);
|
|
1314
|
+
// if (!l->empty()) (*l)[0]->is_delayed(false);
|
|
1268
1315
|
} else if (typeid(*value) == typeid(Binary_Expression)) {
|
|
1269
1316
|
Binary_Expression* b = static_cast<Binary_Expression*>(value);
|
|
1270
|
-
|
|
1271
|
-
if (lhs && lhs->type() == Sass_OP::DIV) lhs->is_delayed(false);
|
|
1317
|
+
if (b && b->type() == Sass_OP::DIV) b->set_delayed(false);
|
|
1272
1318
|
}
|
|
1273
1319
|
return value;
|
|
1274
1320
|
}
|
|
1321
|
+
// string may be interpolated
|
|
1322
|
+
// if (lex< quoted_string >()) {
|
|
1323
|
+
// return parse_string();
|
|
1324
|
+
// }
|
|
1275
1325
|
else if (peek< ie_property >()) {
|
|
1276
1326
|
return parse_ie_property();
|
|
1277
1327
|
}
|
|
@@ -1332,6 +1382,17 @@ namespace Sass {
|
|
|
1332
1382
|
if (lex< kwd_important >())
|
|
1333
1383
|
{ return SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, "!important"); }
|
|
1334
1384
|
|
|
1385
|
+
// parse `10%4px` into separated items and not a schema
|
|
1386
|
+
if (lex< sequence < percentage, lookahead < number > > >())
|
|
1387
|
+
{ return SASS_MEMORY_NEW(ctx.mem, Textual, pstate, Textual::PERCENTAGE, lexed); }
|
|
1388
|
+
|
|
1389
|
+
if (lex< sequence < number, lookahead< sequence < op, number > > > >())
|
|
1390
|
+
{ return SASS_MEMORY_NEW(ctx.mem, Textual, pstate, Textual::NUMBER, lexed); }
|
|
1391
|
+
|
|
1392
|
+
// string may be interpolated
|
|
1393
|
+
if (lex< sequence < quoted_string, lookahead < exactly <'-'> > > >())
|
|
1394
|
+
{ return parse_string(); }
|
|
1395
|
+
|
|
1335
1396
|
if (const char* stop = peek< value_schema >())
|
|
1336
1397
|
{ return parse_value_schema(stop); }
|
|
1337
1398
|
|
|
@@ -1363,7 +1424,8 @@ namespace Sass {
|
|
|
1363
1424
|
{ return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, lexed); }
|
|
1364
1425
|
|
|
1365
1426
|
// also handle the 10em- foo special case
|
|
1366
|
-
|
|
1427
|
+
// alternatives < exactly < '.' >, .. > -- `1.5em-.75em` is split into a list, not a binary expression
|
|
1428
|
+
if (lex< sequence< dimension, optional< sequence< exactly<'-'>, lookahead< alternatives < space > > > > > >())
|
|
1367
1429
|
{ return SASS_MEMORY_NEW(ctx.mem, Textual, pstate, Textual::DIMENSION, lexed); }
|
|
1368
1430
|
|
|
1369
1431
|
if (lex< sequence< static_component, one_plus< strict_identifier > > >())
|
|
@@ -1379,7 +1441,7 @@ namespace Sass {
|
|
|
1379
1441
|
if (lex< sequence< exactly<'%'>, optional< percentage > > >())
|
|
1380
1442
|
{ return SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed); }
|
|
1381
1443
|
|
|
1382
|
-
|
|
1444
|
+
css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
|
|
1383
1445
|
|
|
1384
1446
|
// unreachable statement
|
|
1385
1447
|
return 0;
|
|
@@ -1391,7 +1453,9 @@ namespace Sass {
|
|
|
1391
1453
|
{
|
|
1392
1454
|
const char* i = chunk.begin;
|
|
1393
1455
|
// see if there any interpolants
|
|
1394
|
-
const char* p = find_first_in_interval< exactly<hash_lbrace> >(i, chunk.end)
|
|
1456
|
+
const char* p = constant ? find_first_in_interval< exactly<hash_lbrace> >(i, chunk.end) :
|
|
1457
|
+
find_first_in_interval< exactly<hash_lbrace>, block_comment >(i, chunk.end);
|
|
1458
|
+
|
|
1395
1459
|
if (!p) {
|
|
1396
1460
|
String_Quoted* str_quoted = SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, std::string(i, chunk.end));
|
|
1397
1461
|
if (!constant && str_quoted->quote_mark()) str_quoted->quote_mark('*');
|
|
@@ -1400,8 +1464,10 @@ namespace Sass {
|
|
|
1400
1464
|
}
|
|
1401
1465
|
|
|
1402
1466
|
String_Schema* schema = SASS_MEMORY_NEW(ctx.mem, String_Schema, pstate);
|
|
1467
|
+
schema->is_interpolant(true);
|
|
1403
1468
|
while (i < chunk.end) {
|
|
1404
|
-
p = find_first_in_interval< exactly<hash_lbrace> >(i, chunk.end)
|
|
1469
|
+
p = constant ? find_first_in_interval< exactly<hash_lbrace> >(i, chunk.end) :
|
|
1470
|
+
find_first_in_interval< exactly<hash_lbrace>, block_comment >(i, chunk.end);
|
|
1405
1471
|
if (p) {
|
|
1406
1472
|
if (i < p) {
|
|
1407
1473
|
// accumulate the preceding segment if it's nonempty
|
|
@@ -1415,7 +1481,7 @@ namespace Sass {
|
|
|
1415
1481
|
const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p + 2, chunk.end); // find the closing brace
|
|
1416
1482
|
if (j) { --j;
|
|
1417
1483
|
// parse the interpolant and accumulate it
|
|
1418
|
-
Expression* interp_node = Parser::from_token(Token(p+2, j), ctx, pstate).parse_list();
|
|
1484
|
+
Expression* interp_node = Parser::from_token(Token(p+2, j), ctx, pstate, source).parse_list();
|
|
1419
1485
|
interp_node->is_interpolant(true);
|
|
1420
1486
|
(*schema) << interp_node;
|
|
1421
1487
|
i = j;
|
|
@@ -1467,14 +1533,14 @@ namespace Sass {
|
|
|
1467
1533
|
Token str(lexed);
|
|
1468
1534
|
const char* i = str.begin;
|
|
1469
1535
|
// see if there any interpolants
|
|
1470
|
-
const char* p = find_first_in_interval< exactly<hash_lbrace
|
|
1536
|
+
const char* p = find_first_in_interval< exactly<hash_lbrace>, block_comment >(str.begin, str.end);
|
|
1471
1537
|
if (!p) {
|
|
1472
1538
|
return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, std::string(str.begin, str.end));
|
|
1473
1539
|
}
|
|
1474
1540
|
|
|
1475
1541
|
String_Schema* schema = SASS_MEMORY_NEW(ctx.mem, String_Schema, pstate);
|
|
1476
1542
|
while (i < str.end) {
|
|
1477
|
-
p = find_first_in_interval< exactly<hash_lbrace
|
|
1543
|
+
p = find_first_in_interval< exactly<hash_lbrace>, block_comment >(i, str.end);
|
|
1478
1544
|
if (p) {
|
|
1479
1545
|
if (i < p) {
|
|
1480
1546
|
(*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, std::string(i, p)); // accumulate the preceding segment if it's nonempty
|
|
@@ -1485,7 +1551,7 @@ namespace Sass {
|
|
|
1485
1551
|
const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p+2, str.end); // find the closing brace
|
|
1486
1552
|
if (j) {
|
|
1487
1553
|
// parse the interpolant and accumulate it
|
|
1488
|
-
Expression* interp_node = Parser::from_token(Token(p+2, j), ctx, pstate).parse_list();
|
|
1554
|
+
Expression* interp_node = Parser::from_token(Token(p+2, j), ctx, pstate, source).parse_list();
|
|
1489
1555
|
interp_node->is_interpolant(true);
|
|
1490
1556
|
(*schema) << interp_node;
|
|
1491
1557
|
i = j;
|
|
@@ -1533,9 +1599,14 @@ namespace Sass {
|
|
|
1533
1599
|
|
|
1534
1600
|
const char* e = 0;
|
|
1535
1601
|
size_t num_items = 0;
|
|
1602
|
+
bool need_space = false;
|
|
1536
1603
|
while (position < stop) {
|
|
1537
1604
|
// parse space between tokens
|
|
1538
1605
|
if (lex< spaces >() && num_items) {
|
|
1606
|
+
need_space = true;
|
|
1607
|
+
}
|
|
1608
|
+
if (need_space) {
|
|
1609
|
+
need_space = false;
|
|
1539
1610
|
(*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, " ");
|
|
1540
1611
|
}
|
|
1541
1612
|
if ((e = peek< re_functional >()) && e < stop) {
|
|
@@ -1547,27 +1618,35 @@ namespace Sass {
|
|
|
1547
1618
|
if (peek< exactly< rbrace > >()) {
|
|
1548
1619
|
css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
|
|
1549
1620
|
}
|
|
1621
|
+
Expression* ex = 0;
|
|
1550
1622
|
if (lex< re_static_expression >()) {
|
|
1551
|
-
|
|
1623
|
+
ex = SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed);
|
|
1552
1624
|
} else {
|
|
1553
|
-
|
|
1625
|
+
ex = parse_list();
|
|
1554
1626
|
}
|
|
1627
|
+
ex->is_interpolant(true);
|
|
1628
|
+
(*schema) << ex;
|
|
1555
1629
|
// ToDo: no error check here?
|
|
1556
1630
|
lex < exactly < rbrace > >();
|
|
1557
1631
|
}
|
|
1558
|
-
// lex some string constants
|
|
1559
|
-
|
|
1632
|
+
// lex some string constants or other valid token
|
|
1633
|
+
// Note: [-+] chars are left over from ie. `#{3}+3`
|
|
1634
|
+
else if (lex< alternatives < exactly<'%'>, exactly < '-' >, exactly < '+' > > >()) {
|
|
1635
|
+
(*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed);
|
|
1636
|
+
}
|
|
1637
|
+
else if (lex< sequence < identifier > >()) {
|
|
1560
1638
|
(*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed);
|
|
1561
|
-
if (*position == '"' || *position == '\'') {
|
|
1562
|
-
|
|
1639
|
+
if ((*position == '"' || *position == '\'') || peek < alternatives < alpha > >()) {
|
|
1640
|
+
need_space = true;
|
|
1563
1641
|
}
|
|
1564
1642
|
}
|
|
1565
1643
|
// lex a quoted string
|
|
1566
1644
|
else if (lex< quoted_string >()) {
|
|
1567
1645
|
(*schema) << SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, lexed, '"');
|
|
1568
|
-
if (*position == '"' || *position == '\'' || alpha(
|
|
1569
|
-
|
|
1646
|
+
if ((*position == '"' || *position == '\'') || peek < alternatives < alpha > >()) {
|
|
1647
|
+
need_space = true;
|
|
1570
1648
|
}
|
|
1649
|
+
if (peek < exactly < '-' > >()) return schema;
|
|
1571
1650
|
}
|
|
1572
1651
|
// lex (normalized) variable
|
|
1573
1652
|
else if (lex< variable >()) {
|
|
@@ -1612,14 +1691,14 @@ namespace Sass {
|
|
|
1612
1691
|
Token id(lexed);
|
|
1613
1692
|
const char* i = id.begin;
|
|
1614
1693
|
// see if there any interpolants
|
|
1615
|
-
const char* p = find_first_in_interval< exactly<hash_lbrace
|
|
1694
|
+
const char* p = find_first_in_interval< exactly<hash_lbrace>, block_comment >(id.begin, id.end);
|
|
1616
1695
|
if (!p) {
|
|
1617
1696
|
return SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, std::string(id.begin, id.end));
|
|
1618
1697
|
}
|
|
1619
1698
|
|
|
1620
1699
|
String_Schema* schema = SASS_MEMORY_NEW(ctx.mem, String_Schema, pstate);
|
|
1621
1700
|
while (i < id.end) {
|
|
1622
|
-
p = find_first_in_interval< exactly<hash_lbrace
|
|
1701
|
+
p = find_first_in_interval< exactly<hash_lbrace>, block_comment >(i, id.end);
|
|
1623
1702
|
if (p) {
|
|
1624
1703
|
if (i < p) {
|
|
1625
1704
|
// accumulate the preceding segment if it's nonempty
|
|
@@ -1635,10 +1714,10 @@ namespace Sass {
|
|
|
1635
1714
|
const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p+2, id.end); // find the closing brace
|
|
1636
1715
|
if (j) {
|
|
1637
1716
|
// parse the interpolant and accumulate it
|
|
1638
|
-
Expression* interp_node = Parser::from_token(Token(p+2, j), ctx, pstate).parse_list();
|
|
1717
|
+
Expression* interp_node = Parser::from_token(Token(p+2, j), ctx, pstate, source).parse_list();
|
|
1639
1718
|
interp_node->is_interpolant(true);
|
|
1640
1719
|
(*schema) << interp_node;
|
|
1641
|
-
schema->has_interpolants(true);
|
|
1720
|
+
// schema->has_interpolants(true);
|
|
1642
1721
|
i = j;
|
|
1643
1722
|
}
|
|
1644
1723
|
else {
|
|
@@ -1682,13 +1761,38 @@ namespace Sass {
|
|
|
1682
1761
|
|
|
1683
1762
|
String* Parser::parse_url_function_string()
|
|
1684
1763
|
{
|
|
1685
|
-
|
|
1764
|
+
std::string prefix("");
|
|
1765
|
+
if (lex< uri_prefix >()) {
|
|
1766
|
+
prefix = std::string(lexed);
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
String* url_string = parse_url_function_argument();
|
|
1770
|
+
|
|
1771
|
+
std::string suffix("");
|
|
1772
|
+
if (lex< real_uri_suffix >()) {
|
|
1773
|
+
suffix = std::string(lexed);
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
if (String_Schema* schema = dynamic_cast<String_Schema*>(url_string)) {
|
|
1777
|
+
String_Schema* res = SASS_MEMORY_NEW(ctx.mem, String_Schema, pstate);
|
|
1778
|
+
(*res) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, prefix);
|
|
1779
|
+
(*res) += schema;
|
|
1780
|
+
(*res) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, suffix);
|
|
1781
|
+
return res;
|
|
1782
|
+
} else {
|
|
1783
|
+
std::string res = prefix + url_string->to_string({ NESTED, 5 }) + suffix;
|
|
1784
|
+
return SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, res);
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1686
1787
|
|
|
1687
|
-
|
|
1688
|
-
|
|
1788
|
+
String* Parser::parse_url_function_argument()
|
|
1789
|
+
{
|
|
1790
|
+
const char* p = position;
|
|
1689
1791
|
|
|
1690
|
-
|
|
1691
|
-
|
|
1792
|
+
std::string uri("");
|
|
1793
|
+
if (lex< real_uri_value >(false)) {
|
|
1794
|
+
uri = lexed.to_string();
|
|
1795
|
+
}
|
|
1692
1796
|
|
|
1693
1797
|
if (peek< exactly< hash_lbrace > >()) {
|
|
1694
1798
|
const char* pp = position;
|
|
@@ -1696,14 +1800,15 @@ namespace Sass {
|
|
|
1696
1800
|
while (peek< exactly< hash_lbrace > >(pp)) {
|
|
1697
1801
|
pp = sequence< interpolant, real_uri_value >(pp);
|
|
1698
1802
|
}
|
|
1699
|
-
position =
|
|
1803
|
+
position = pp;
|
|
1700
1804
|
return parse_interpolated_chunk(Token(p, position));
|
|
1701
|
-
}
|
|
1702
|
-
|
|
1703
|
-
std::string res =
|
|
1805
|
+
}
|
|
1806
|
+
else if (uri != "") {
|
|
1807
|
+
std::string res = Util::rtrim(uri);
|
|
1704
1808
|
return SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, res);
|
|
1705
1809
|
}
|
|
1706
1810
|
|
|
1811
|
+
return 0;
|
|
1707
1812
|
}
|
|
1708
1813
|
|
|
1709
1814
|
Function_Call* Parser::parse_function_call()
|
|
@@ -1727,7 +1832,14 @@ namespace Sass {
|
|
|
1727
1832
|
|
|
1728
1833
|
Content* Parser::parse_content_directive()
|
|
1729
1834
|
{
|
|
1730
|
-
|
|
1835
|
+
bool missing_mixin_parent = true;
|
|
1836
|
+
for (auto parent : stack) {
|
|
1837
|
+
if (parent == Scope::Mixin) {
|
|
1838
|
+
missing_mixin_parent = false;
|
|
1839
|
+
break;
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
if (missing_mixin_parent) {
|
|
1731
1843
|
error("@content may only be used within a mixin", pstate);
|
|
1732
1844
|
}
|
|
1733
1845
|
return SASS_MEMORY_NEW(ctx.mem, Content, pstate);
|
|
@@ -1735,6 +1847,7 @@ namespace Sass {
|
|
|
1735
1847
|
|
|
1736
1848
|
If* Parser::parse_if_directive(bool else_if)
|
|
1737
1849
|
{
|
|
1850
|
+
stack.push_back(Scope::Control);
|
|
1738
1851
|
ParserState if_source_position = pstate;
|
|
1739
1852
|
Expression* predicate = parse_list();
|
|
1740
1853
|
predicate->is_delayed(false);
|
|
@@ -1750,11 +1863,13 @@ namespace Sass {
|
|
|
1750
1863
|
else if (lex_css< kwd_else_directive >()) {
|
|
1751
1864
|
alternative = parse_block();
|
|
1752
1865
|
}
|
|
1866
|
+
stack.pop_back();
|
|
1753
1867
|
return SASS_MEMORY_NEW(ctx.mem, If, if_source_position, predicate, block, alternative);
|
|
1754
1868
|
}
|
|
1755
1869
|
|
|
1756
1870
|
For* Parser::parse_for_directive()
|
|
1757
1871
|
{
|
|
1872
|
+
stack.push_back(Scope::Control);
|
|
1758
1873
|
ParserState for_source_position = pstate;
|
|
1759
1874
|
lex_variable();
|
|
1760
1875
|
std::string var(Util::normalize_underscores(lexed));
|
|
@@ -1768,6 +1883,7 @@ namespace Sass {
|
|
|
1768
1883
|
Expression* upper_bound = parse_expression();
|
|
1769
1884
|
upper_bound->is_delayed(false);
|
|
1770
1885
|
Block* body = parse_block();
|
|
1886
|
+
stack.pop_back();
|
|
1771
1887
|
return SASS_MEMORY_NEW(ctx.mem, For, for_source_position, var, lower_bound, upper_bound, body, inclusive);
|
|
1772
1888
|
}
|
|
1773
1889
|
|
|
@@ -1799,6 +1915,7 @@ namespace Sass {
|
|
|
1799
1915
|
|
|
1800
1916
|
Each* Parser::parse_each_directive()
|
|
1801
1917
|
{
|
|
1918
|
+
stack.push_back(Scope::Control);
|
|
1802
1919
|
ParserState each_source_position = pstate;
|
|
1803
1920
|
std::vector<std::string> vars;
|
|
1804
1921
|
lex_variable();
|
|
@@ -1817,12 +1934,14 @@ namespace Sass {
|
|
|
1817
1934
|
}
|
|
1818
1935
|
}
|
|
1819
1936
|
Block* body = parse_block();
|
|
1937
|
+
stack.pop_back();
|
|
1820
1938
|
return SASS_MEMORY_NEW(ctx.mem, Each, each_source_position, vars, list, body);
|
|
1821
1939
|
}
|
|
1822
1940
|
|
|
1823
1941
|
// called after parsing `kwd_while_directive`
|
|
1824
1942
|
While* Parser::parse_while_directive()
|
|
1825
1943
|
{
|
|
1944
|
+
stack.push_back(Scope::Control);
|
|
1826
1945
|
// create the initial while call object
|
|
1827
1946
|
While* call = SASS_MEMORY_NEW(ctx.mem, While, pstate, 0, 0);
|
|
1828
1947
|
// parse mandatory predicate
|
|
@@ -1832,12 +1951,15 @@ namespace Sass {
|
|
|
1832
1951
|
// parse mandatory block
|
|
1833
1952
|
call->block(parse_block());
|
|
1834
1953
|
// return ast node
|
|
1954
|
+
stack.pop_back();
|
|
1955
|
+
// return ast node
|
|
1835
1956
|
return call;
|
|
1836
1957
|
}
|
|
1837
1958
|
|
|
1838
1959
|
// EO parse_while_directive
|
|
1839
1960
|
Media_Block* Parser::parse_media_block()
|
|
1840
1961
|
{
|
|
1962
|
+
stack.push_back(Scope::Media);
|
|
1841
1963
|
Media_Block* media_block = SASS_MEMORY_NEW(ctx.mem, Media_Block, pstate, 0, 0);
|
|
1842
1964
|
media_block->media_queries(parse_media_queries());
|
|
1843
1965
|
|
|
@@ -1845,7 +1967,7 @@ namespace Sass {
|
|
|
1845
1967
|
last_media_block = media_block;
|
|
1846
1968
|
media_block->block(parse_css_block());
|
|
1847
1969
|
last_media_block = prev_media_block;
|
|
1848
|
-
|
|
1970
|
+
stack.pop_back();
|
|
1849
1971
|
return media_block;
|
|
1850
1972
|
}
|
|
1851
1973
|
|
|
@@ -1898,10 +2020,10 @@ namespace Sass {
|
|
|
1898
2020
|
}
|
|
1899
2021
|
feature = parse_expression();
|
|
1900
2022
|
Expression* expression = 0;
|
|
1901
|
-
if (
|
|
2023
|
+
if (lex_css< exactly<':'> >()) {
|
|
1902
2024
|
expression = parse_list();
|
|
1903
2025
|
}
|
|
1904
|
-
if (!
|
|
2026
|
+
if (!lex_css< exactly<')'> >()) {
|
|
1905
2027
|
error("unclosed parenthesis in media query expression", pstate);
|
|
1906
2028
|
}
|
|
1907
2029
|
return SASS_MEMORY_NEW(ctx.mem, Media_Query_Expression, feature->pstate(), feature, expression);
|
|
@@ -2010,6 +2132,7 @@ namespace Sass {
|
|
|
2010
2132
|
Block* body = 0;
|
|
2011
2133
|
At_Root_Expression* expr = 0;
|
|
2012
2134
|
Lookahead lookahead_result;
|
|
2135
|
+
// stack.push_back(Scope::Root);
|
|
2013
2136
|
LOCAL_FLAG(in_at_root, true);
|
|
2014
2137
|
if (lex< exactly<'('> >()) {
|
|
2015
2138
|
expr = parse_at_root_expression();
|
|
@@ -2024,6 +2147,7 @@ namespace Sass {
|
|
|
2024
2147
|
}
|
|
2025
2148
|
At_Root_Block* at_root = SASS_MEMORY_NEW(ctx.mem, At_Root_Block, at_source_position, body);
|
|
2026
2149
|
if (expr) at_root->expression(expr);
|
|
2150
|
+
// stack.pop_back();
|
|
2027
2151
|
return at_root;
|
|
2028
2152
|
}
|
|
2029
2153
|
|
|
@@ -2082,16 +2206,37 @@ namespace Sass {
|
|
|
2082
2206
|
|
|
2083
2207
|
Warning* Parser::parse_warning()
|
|
2084
2208
|
{
|
|
2209
|
+
if (stack.back() != Scope::Root &&
|
|
2210
|
+
stack.back() != Scope::Function &&
|
|
2211
|
+
stack.back() != Scope::Mixin &&
|
|
2212
|
+
stack.back() != Scope::Control &&
|
|
2213
|
+
stack.back() != Scope::Rules) {
|
|
2214
|
+
error("Illegal nesting: Only properties may be nested beneath properties.", pstate);
|
|
2215
|
+
}
|
|
2085
2216
|
return SASS_MEMORY_NEW(ctx.mem, Warning, pstate, parse_list());
|
|
2086
2217
|
}
|
|
2087
2218
|
|
|
2088
2219
|
Error* Parser::parse_error()
|
|
2089
2220
|
{
|
|
2221
|
+
if (stack.back() != Scope::Root &&
|
|
2222
|
+
stack.back() != Scope::Function &&
|
|
2223
|
+
stack.back() != Scope::Mixin &&
|
|
2224
|
+
stack.back() != Scope::Control &&
|
|
2225
|
+
stack.back() != Scope::Rules) {
|
|
2226
|
+
error("Illegal nesting: Only properties may be nested beneath properties.", pstate);
|
|
2227
|
+
}
|
|
2090
2228
|
return SASS_MEMORY_NEW(ctx.mem, Error, pstate, parse_list());
|
|
2091
2229
|
}
|
|
2092
2230
|
|
|
2093
2231
|
Debug* Parser::parse_debug()
|
|
2094
2232
|
{
|
|
2233
|
+
if (stack.back() != Scope::Root &&
|
|
2234
|
+
stack.back() != Scope::Function &&
|
|
2235
|
+
stack.back() != Scope::Mixin &&
|
|
2236
|
+
stack.back() != Scope::Control &&
|
|
2237
|
+
stack.back() != Scope::Rules) {
|
|
2238
|
+
error("Illegal nesting: Only properties may be nested beneath properties.", pstate);
|
|
2239
|
+
}
|
|
2095
2240
|
return SASS_MEMORY_NEW(ctx.mem, Debug, pstate, parse_list());
|
|
2096
2241
|
}
|
|
2097
2242
|
|
|
@@ -2113,57 +2258,69 @@ namespace Sass {
|
|
|
2113
2258
|
rv.error = p;
|
|
2114
2259
|
if (const char* q =
|
|
2115
2260
|
peek <
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
schema_reference_combinator,
|
|
2123
|
-
// match selector ops /[*&%,()\[\]]/
|
|
2124
|
-
class_char < selector_lookahead_ops >,
|
|
2125
|
-
// match selector combinators /[>+~]/
|
|
2126
|
-
class_char < selector_combinator_ops >,
|
|
2127
|
-
// match attribute compare operators
|
|
2128
|
-
alternatives <
|
|
2129
|
-
exact_match, class_match, dash_match,
|
|
2130
|
-
prefix_match, suffix_match, substring_match
|
|
2261
|
+
alternatives <
|
|
2262
|
+
// partial bem selector
|
|
2263
|
+
sequence <
|
|
2264
|
+
ampersand,
|
|
2265
|
+
one_plus <
|
|
2266
|
+
exactly < '-' >
|
|
2131
2267
|
>,
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2268
|
+
word_boundary
|
|
2269
|
+
>,
|
|
2270
|
+
// main selector matching
|
|
2271
|
+
one_plus <
|
|
2272
|
+
alternatives <
|
|
2273
|
+
// consume whitespace and comments
|
|
2274
|
+
spaces, block_comment, line_comment,
|
|
2275
|
+
// match `/deep/` selector (pass-trough)
|
|
2276
|
+
// there is no functionality for it yet
|
|
2277
|
+
schema_reference_combinator,
|
|
2278
|
+
// match selector ops /[*&%,()\[\]]/
|
|
2279
|
+
class_char < selector_lookahead_ops >,
|
|
2280
|
+
// match selector combinators /[>+~]/
|
|
2281
|
+
class_char < selector_combinator_ops >,
|
|
2282
|
+
// match attribute compare operators
|
|
2137
2283
|
alternatives <
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
// not for interpolation
|
|
2141
|
-
negate < exactly <'{'> >
|
|
2142
|
-
>,
|
|
2143
|
-
// class match
|
|
2144
|
-
exactly <'.'>,
|
|
2145
|
-
// single or double colon
|
|
2146
|
-
optional < pseudo_prefix >
|
|
2284
|
+
exact_match, class_match, dash_match,
|
|
2285
|
+
prefix_match, suffix_match, substring_match
|
|
2147
2286
|
>,
|
|
2148
|
-
//
|
|
2149
|
-
|
|
2150
|
-
//
|
|
2151
|
-
|
|
2152
|
-
//
|
|
2287
|
+
// main selector match
|
|
2288
|
+
sequence <
|
|
2289
|
+
// allow namespace prefix
|
|
2290
|
+
optional < namespace_schema >,
|
|
2291
|
+
// modifiers prefixes
|
|
2153
2292
|
alternatives <
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2293
|
+
sequence <
|
|
2294
|
+
exactly <'#'>,
|
|
2295
|
+
// not for interpolation
|
|
2296
|
+
negate < exactly <'{'> >
|
|
2297
|
+
>,
|
|
2298
|
+
// class match
|
|
2299
|
+
exactly <'.'>,
|
|
2300
|
+
// single or double colon
|
|
2301
|
+
optional < pseudo_prefix >
|
|
2302
|
+
>,
|
|
2303
|
+
// accept hypens in token
|
|
2304
|
+
one_plus < sequence <
|
|
2305
|
+
// can start with hyphens
|
|
2306
|
+
zero_plus < exactly<'-'> >,
|
|
2307
|
+
// now the main token
|
|
2308
|
+
alternatives <
|
|
2309
|
+
kwd_optional,
|
|
2310
|
+
exactly <'*'>,
|
|
2311
|
+
quoted_string,
|
|
2312
|
+
interpolant,
|
|
2313
|
+
identifier,
|
|
2314
|
+
variable,
|
|
2315
|
+
percentage,
|
|
2316
|
+
binomial,
|
|
2317
|
+
dimension,
|
|
2318
|
+
alnum
|
|
2319
|
+
>
|
|
2320
|
+
> >,
|
|
2321
|
+
// can also end with hyphens
|
|
2322
|
+
zero_plus < exactly<'-'> >
|
|
2323
|
+
>
|
|
2167
2324
|
>
|
|
2168
2325
|
>
|
|
2169
2326
|
>
|
|
@@ -2346,15 +2503,15 @@ namespace Sass {
|
|
|
2346
2503
|
}
|
|
2347
2504
|
|
|
2348
2505
|
|
|
2349
|
-
Expression* Parser::fold_operands(Expression* base, std::vector<Expression*>& operands,
|
|
2506
|
+
Expression* Parser::fold_operands(Expression* base, std::vector<Expression*>& operands, Operand op)
|
|
2350
2507
|
{
|
|
2351
2508
|
for (size_t i = 0, S = operands.size(); i < S; ++i) {
|
|
2352
2509
|
base = SASS_MEMORY_NEW(ctx.mem, Binary_Expression, pstate, op, base, operands[i]);
|
|
2353
2510
|
Binary_Expression* b = static_cast<Binary_Expression*>(base);
|
|
2354
|
-
if (op == Sass_OP::DIV && b->left()->is_delayed() && b->right()->is_delayed()) {
|
|
2511
|
+
if (op.operand == Sass_OP::DIV && b->left()->is_delayed() && b->right()->is_delayed()) {
|
|
2355
2512
|
base->is_delayed(true);
|
|
2356
2513
|
}
|
|
2357
|
-
else {
|
|
2514
|
+
else if (b && b->op().operand != Sass_OP::DIV) {
|
|
2358
2515
|
b->left()->is_delayed(false);
|
|
2359
2516
|
b->right()->is_delayed(false);
|
|
2360
2517
|
}
|
|
@@ -2362,18 +2519,62 @@ namespace Sass {
|
|
|
2362
2519
|
return base;
|
|
2363
2520
|
}
|
|
2364
2521
|
|
|
2365
|
-
Expression* Parser::fold_operands(Expression* base, std::vector<Expression*>& operands, std::vector<
|
|
2366
|
-
{
|
|
2367
|
-
|
|
2368
|
-
|
|
2522
|
+
Expression* Parser::fold_operands(Expression* base, std::vector<Expression*>& operands, std::vector<Operand>& ops, size_t i)
|
|
2523
|
+
{
|
|
2524
|
+
|
|
2525
|
+
if (String_Schema* schema = dynamic_cast<String_Schema*>(base)) {
|
|
2526
|
+
// return schema;
|
|
2527
|
+
if (schema->has_interpolants()) {
|
|
2528
|
+
if (i + 1 < operands.size() && (
|
|
2529
|
+
(ops[0].operand == Sass_OP::EQ)
|
|
2530
|
+
|| (ops[0].operand == Sass_OP::ADD)
|
|
2531
|
+
|| (ops[0].operand == Sass_OP::DIV)
|
|
2532
|
+
|| (ops[0].operand == Sass_OP::MUL)
|
|
2533
|
+
|| (ops[0].operand == Sass_OP::NEQ)
|
|
2534
|
+
|| (ops[0].operand == Sass_OP::LT)
|
|
2535
|
+
|| (ops[0].operand == Sass_OP::GT)
|
|
2536
|
+
|| (ops[0].operand == Sass_OP::LTE)
|
|
2537
|
+
|| (ops[0].operand == Sass_OP::GTE)
|
|
2538
|
+
)) {
|
|
2539
|
+
Expression* rhs = fold_operands(operands[0], operands, ops, 1);
|
|
2540
|
+
rhs = SASS_MEMORY_NEW(ctx.mem, Binary_Expression, base->pstate(), ops[0], schema, rhs);
|
|
2541
|
+
rhs->set_delayed(false);
|
|
2542
|
+
rhs->is_delayed(true);
|
|
2543
|
+
return rhs;
|
|
2544
|
+
}
|
|
2545
|
+
// return schema;
|
|
2546
|
+
}
|
|
2547
|
+
}
|
|
2548
|
+
|
|
2549
|
+
for (size_t S = operands.size(); i < S; ++i) {
|
|
2550
|
+
if (String_Schema* schema = dynamic_cast<String_Schema*>(operands[i])) {
|
|
2551
|
+
if (schema->has_interpolants()) {
|
|
2552
|
+
if (i + 1 < S) {
|
|
2553
|
+
Expression* rhs = fold_operands(operands[i+1], operands, ops, i + 2);
|
|
2554
|
+
rhs = SASS_MEMORY_NEW(ctx.mem, Binary_Expression, base->pstate(), ops[i], schema, rhs);
|
|
2555
|
+
base = SASS_MEMORY_NEW(ctx.mem, Binary_Expression, base->pstate(), ops[i], base, rhs);
|
|
2556
|
+
rhs->is_delayed(true);
|
|
2557
|
+
base->is_delayed(true);
|
|
2558
|
+
return base;
|
|
2559
|
+
}
|
|
2560
|
+
base = SASS_MEMORY_NEW(ctx.mem, Binary_Expression, base->pstate(), ops[i], base, operands[i]);
|
|
2561
|
+
if (ops[i].operand != Sass_OP::DIV) base->is_delayed(true);
|
|
2562
|
+
return base;
|
|
2563
|
+
} else {
|
|
2564
|
+
base = SASS_MEMORY_NEW(ctx.mem, Binary_Expression, base->pstate(), ops[i], base, operands[i]);
|
|
2565
|
+
}
|
|
2566
|
+
} else {
|
|
2567
|
+
base = SASS_MEMORY_NEW(ctx.mem, Binary_Expression, base->pstate(), ops[i], base, operands[i]);
|
|
2568
|
+
}
|
|
2369
2569
|
Binary_Expression* b = static_cast<Binary_Expression*>(base);
|
|
2370
|
-
if (ops[i] == Sass_OP::DIV && b->left()->is_delayed() && b->right()->is_delayed()) {
|
|
2570
|
+
if (b && ops[i].operand == Sass_OP::DIV && b->left()->is_delayed() && b->right()->is_delayed()) {
|
|
2371
2571
|
base->is_delayed(true);
|
|
2372
2572
|
}
|
|
2373
|
-
else {
|
|
2573
|
+
else if (b) {
|
|
2374
2574
|
b->left()->is_delayed(false);
|
|
2375
2575
|
b->right()->is_delayed(false);
|
|
2376
2576
|
}
|
|
2577
|
+
|
|
2377
2578
|
}
|
|
2378
2579
|
return base;
|
|
2379
2580
|
}
|
|
@@ -2387,22 +2588,37 @@ namespace Sass {
|
|
|
2387
2588
|
void Parser::css_error(const std::string& msg, const std::string& prefix, const std::string& middle)
|
|
2388
2589
|
{
|
|
2389
2590
|
int max_len = 18;
|
|
2591
|
+
const char* end = this->end;
|
|
2592
|
+
while (*end != 0) ++ end;
|
|
2390
2593
|
const char* pos = peek < optional_spaces >();
|
|
2391
2594
|
|
|
2392
|
-
const char* last_pos(pos
|
|
2595
|
+
const char* last_pos(pos);
|
|
2596
|
+
if (last_pos > source) {
|
|
2597
|
+
utf8::prior(last_pos, source);
|
|
2598
|
+
}
|
|
2393
2599
|
// backup position to last significant char
|
|
2394
|
-
while (
|
|
2600
|
+
while (last_pos > source && last_pos < end) {
|
|
2601
|
+
if (!Prelexer::is_space(*last_pos)) break;
|
|
2602
|
+
utf8::prior(last_pos, source);
|
|
2603
|
+
}
|
|
2395
2604
|
|
|
2396
2605
|
bool ellipsis_left = false;
|
|
2397
|
-
const char* pos_left(last_pos
|
|
2398
|
-
const char* end_left(last_pos
|
|
2606
|
+
const char* pos_left(last_pos);
|
|
2607
|
+
const char* end_left(last_pos);
|
|
2608
|
+
|
|
2609
|
+
utf8::next(pos_left, end);
|
|
2610
|
+
utf8::next(end_left, end);
|
|
2399
2611
|
while (pos_left > source) {
|
|
2400
|
-
if (end_left
|
|
2401
|
-
|
|
2612
|
+
if (utf8::distance(pos_left, end_left) >= max_len) {
|
|
2613
|
+
utf8::prior(pos_left, source);
|
|
2614
|
+
ellipsis_left = *(pos_left) != '\n' &&
|
|
2615
|
+
*(pos_left) != '\r';
|
|
2616
|
+
utf8::next(pos_left, end);
|
|
2402
2617
|
break;
|
|
2403
2618
|
}
|
|
2404
2619
|
|
|
2405
|
-
const char* prev = pos_left
|
|
2620
|
+
const char* prev = pos_left;
|
|
2621
|
+
utf8::prior(prev, source);
|
|
2406
2622
|
if (*prev == '\r') break;
|
|
2407
2623
|
if (*prev == '\n') break;
|
|
2408
2624
|
pos_left = prev;
|
|
@@ -2414,21 +2630,24 @@ namespace Sass {
|
|
|
2414
2630
|
bool ellipsis_right = false;
|
|
2415
2631
|
const char* end_right(pos);
|
|
2416
2632
|
const char* pos_right(pos);
|
|
2417
|
-
while (end_right
|
|
2418
|
-
if (end_right
|
|
2419
|
-
|
|
2633
|
+
while (end_right < end) {
|
|
2634
|
+
if (utf8::distance(pos_right, end_right) > max_len) {
|
|
2635
|
+
ellipsis_left = *(pos_right) != '\n' &&
|
|
2636
|
+
*(pos_right) != '\r';
|
|
2420
2637
|
break;
|
|
2421
2638
|
}
|
|
2422
2639
|
if (*end_right == '\r') break;
|
|
2423
2640
|
if (*end_right == '\n') break;
|
|
2424
|
-
|
|
2641
|
+
utf8::next(end_right, end);
|
|
2425
2642
|
}
|
|
2426
|
-
if (end_right
|
|
2643
|
+
// if (*end_right == 0) end_right ++;
|
|
2427
2644
|
|
|
2428
2645
|
std::string left(pos_left, end_left);
|
|
2429
2646
|
std::string right(pos_right, end_right);
|
|
2430
|
-
|
|
2431
|
-
|
|
2647
|
+
size_t left_subpos = left.size() > 15 ? left.size() - 15 : 0;
|
|
2648
|
+
size_t right_subpos = right.size() > 15 ? right.size() - 15 : 0;
|
|
2649
|
+
if (left_subpos && ellipsis_left) left = ellipsis + left.substr(left_subpos);
|
|
2650
|
+
if (right_subpos && ellipsis_right) right = right.substr(right_subpos) + ellipsis;
|
|
2432
2651
|
// now pass new message to the more generic error function
|
|
2433
2652
|
error(msg + prefix + quote(left) + middle + quote(right), pstate);
|
|
2434
2653
|
}
|