Skip to content

Commit

Permalink
Fix ParserState for SourceMaps
Browse files Browse the repository at this point in the history
- Fixes parent selector mappings
- Fixes media block/query mappings
- Fixes range over binary expressions
- Don't include semicolon for statics
  • Loading branch information
mgreter committed Oct 21, 2016
1 parent 894963f commit e7a3b7e
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 12 deletions.
40 changes: 39 additions & 1 deletion src/ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ namespace Sass {
pstate_.offset += pstate - pstate_ + pstate.offset;
}

void AST_Node::set_pstate_offset(const Offset& offset)
{
pstate_.offset = offset;
}

inline bool is_ns_eq(const std::string& l, const std::string& r)
{
if (l.empty() && r.empty()) return true;
Expand Down Expand Up @@ -1056,22 +1061,30 @@ namespace Sass {
if (Class_Selector* sq = dynamic_cast<Class_Selector*>(rh->last())) {
Class_Selector* sqs = SASS_MEMORY_NEW(ctx.mem, Class_Selector, *sq);
sqs->name(sqs->name() + (*h)[0]->name());
sqs->pstate((*h)[0]->pstate());
(*rh)[rh->length()-1] = sqs;
rh->pstate(h->pstate());
for (i = 1; i < L; ++i) *rh << (*h)[i];
} else if (Id_Selector* sq = dynamic_cast<Id_Selector*>(rh->last())) {
Id_Selector* sqs = SASS_MEMORY_NEW(ctx.mem, Id_Selector, *sq);
sqs->name(sqs->name() + (*h)[0]->name());
sqs->pstate((*h)[0]->pstate());
(*rh)[rh->length()-1] = sqs;
rh->pstate(h->pstate());
for (i = 1; i < L; ++i) *rh << (*h)[i];
} else if (Element_Selector* ts = dynamic_cast<Element_Selector*>(rh->last())) {
Element_Selector* tss = SASS_MEMORY_NEW(ctx.mem, Element_Selector, *ts);
tss->name(tss->name() + (*h)[0]->name());
tss->pstate((*h)[0]->pstate());
(*rh)[rh->length()-1] = tss;
rh->pstate(h->pstate());
for (i = 1; i < L; ++i) *rh << (*h)[i];
} else if (Placeholder_Selector* ps = dynamic_cast<Placeholder_Selector*>(rh->last())) {
Placeholder_Selector* pss = SASS_MEMORY_NEW(ctx.mem, Placeholder_Selector, *ps);
pss->name(pss->name() + (*h)[0]->name());
pss->pstate((*h)[0]->pstate());
(*rh)[rh->length()-1] = pss;
rh->pstate(h->pstate());
for (i = 1; i < L; ++i) *rh << (*h)[i];
} else {
*last()->head_ += h;
Expand Down Expand Up @@ -1150,9 +1163,18 @@ namespace Sass {
Sequence_Selector* ss = this->clone(ctx);
ss->tail(t ? t->clone(ctx) : 0);
SimpleSequence_Selector* h = head_->clone(ctx);
// remove parent selector from sequence
if (h->length()) h->erase(h->begin());
ss->head(h->length() ? h : 0);
s->append(ctx, ss);
// adjust for parent selector (1 char)
ParserState nstate = (*h)[0]->pstate();
nstate.offset.column += 1;
nstate.column -= 1;
(*h)[0]->pstate(nstate);
// keep old parser state
s->pstate(pstate());
// append new tail
s->append(ctx, ss);
*retval << s;
}
}
Expand All @@ -1171,10 +1193,19 @@ namespace Sass {
}
ss->tail(tail ? tail->clone(ctx) : 0);
SimpleSequence_Selector* h = head_->clone(ctx);
// remove parent selector from sequence
if (h->length()) h->erase(h->begin());
ss->head(h->length() ? h : 0);
// \/ IMO ruby sass bug \/
ss->has_line_feed(false);
// adjust for parent selector (1 char)
ParserState nstate = (*h)[0]->pstate();
nstate.offset.column += 1;
nstate.column -= 1;
(*h)[0]->pstate(nstate);
// keep old parser state
s->pstate(pstate());
// append new tail
s->append(ctx, ss);
*retval << s;
}
Expand Down Expand Up @@ -1557,6 +1588,13 @@ namespace Sass {
return result;
}

SimpleSequence_Selector& SimpleSequence_Selector::operator<<(Simple_Selector* element)
{
Vectorized<Simple_Selector*>::operator<<(element);
pstate_.offset += element->pstate().offset;
return *this;
}

SimpleSequence_Selector* SimpleSequence_Selector::minus(SimpleSequence_Selector* rhs, Context& ctx)
{
SimpleSequence_Selector* result = SASS_MEMORY_NEW(ctx.mem, SimpleSequence_Selector, pstate());
Expand Down
5 changes: 4 additions & 1 deletion src/ast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ namespace Sass {
// virtual Block* block() { return 0; }
public:
void update_pstate(const ParserState& pstate);
void set_pstate_offset(const Offset& offset);
public:
Offset off() { return pstate(); }
Position pos() { return pstate(); }
Expand Down Expand Up @@ -235,7 +236,7 @@ namespace Sass {
T& operator[](size_t i) { return elements_[i]; }
virtual const T& at(size_t i) const { return elements_.at(i); }
const T& operator[](size_t i) const { return elements_[i]; }
Vectorized& operator<<(T element)
virtual Vectorized& operator<<(T element)
{
if (!element) return *this;
reset_hash();
Expand Down Expand Up @@ -2287,6 +2288,8 @@ namespace Sass {
return false;
};

SimpleSequence_Selector& operator<<(Simple_Selector* element);

bool is_universal() const
{
return length() == 1 && (*this)[0]->is_universal();
Expand Down
45 changes: 35 additions & 10 deletions src/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ namespace Sass {

Parser Parser::from_c_str(const char* beg, Context& ctx, ParserState pstate, const char* source)
{
pstate.offset.column = 0;
pstate.offset.line = 0;
Parser p(ctx, pstate);
p.source = source ? source : beg;
p.position = beg ? beg : p.source;
Expand All @@ -45,6 +47,8 @@ namespace Sass {

Parser Parser::from_c_str(const char* beg, const char* end, Context& ctx, ParserState pstate, const char* source)
{
pstate.offset.column = 0;
pstate.offset.line = 0;
Parser p(ctx, pstate);
p.source = source ? source : beg;
p.position = beg ? beg : p.source;
Expand All @@ -55,6 +59,14 @@ namespace Sass {
return p;
}

void Parser::advanceToNextToken() {
lex < css_comments >(false);
// advance to position
pstate += pstate.offset;
pstate.offset.column = 0;
pstate.offset.line = 0;
}

CommaSequence_Selector* Parser::parse_selector(const char* beg, Context& ctx, ParserState pstate, const char* source)
{
Parser p = Parser::from_c_str(beg, ctx, pstate, source);
Expand Down Expand Up @@ -655,6 +667,9 @@ namespace Sass {

String* reference = 0;
lex < block_comment >();

Sequence_Selector* sel = SASS_MEMORY_NEW(ctx.mem, Sequence_Selector, pstate);

// parse the left hand side
SimpleSequence_Selector* lhs = 0;
// special case if it starts with combinator ([+~>])
Expand Down Expand Up @@ -683,9 +698,8 @@ namespace Sass {
if (!lhs && combinator == Sequence_Selector::ANCESTOR_OF) return 0;

// lex < block_comment >();
// source position of a complex selector points to the combinator
// ToDo: make sure we update pstate for ancestor of (lex < zero >());
Sequence_Selector* sel = SASS_MEMORY_NEW(ctx.mem, Sequence_Selector, pstate, combinator, lhs);
sel->head(lhs);
sel->combinator(combinator);
sel->media_block(last_media_block);

if (combinator == Sequence_Selector::REFERENCE) sel->reference(reference);
Expand All @@ -703,9 +717,9 @@ namespace Sass {
// also skip adding parent ref if we only have refs
if (!sel->has_parent_ref() && !in_at_root && !in_root) {
// create the objects to wrap parent selector reference
SimpleSequence_Selector* head = SASS_MEMORY_NEW(ctx.mem, SimpleSequence_Selector, pstate);
Parent_Selector* parent = SASS_MEMORY_NEW(ctx.mem, Parent_Selector, pstate, false);
parent->media_block(last_media_block);
SimpleSequence_Selector* head = SASS_MEMORY_NEW(ctx.mem, SimpleSequence_Selector, pstate);
head->media_block(last_media_block);
// add simple selector
(*head) << parent;
Expand All @@ -720,6 +734,8 @@ namespace Sass {
// if (peek_newline()) head->has_line_break(true);
}

sel->update_pstate(pstate);

// complex selector
return sel;
}
Expand Down Expand Up @@ -1182,6 +1198,7 @@ namespace Sass {
// if it's a singleton, return it directly
if (operands.size() == 0) return conj;
// fold all operands into one binary expression
conj->set_pstate_offset(pstate - conj->pstate());
return fold_operands(conj, operands, { Sass_OP::OR });
}
// EO parse_disjunction
Expand All @@ -1198,6 +1215,7 @@ namespace Sass {
// if it's a singleton, return it directly
if (operands.size() == 0) return rel;
// fold all operands into one binary expression
rel->set_pstate_offset(pstate - rel->pstate());
return fold_operands(rel, operands, { Sass_OP::AND });
}
// EO parse_conjunction
Expand Down Expand Up @@ -1242,6 +1260,7 @@ namespace Sass {
// correctly set to zero. After folding we also unwrap
// single nested items. So we cannot set delay on the
// returned result here, as we have lost nestings ...
lhs->set_pstate_offset(pstate - lhs->pstate());
return fold_operands(lhs, operands, operators);
}
// parse_relation
Expand Down Expand Up @@ -1527,6 +1546,9 @@ namespace Sass {
{
lex< static_value >();
Token str(lexed);
// static valuse always have trailing white-
// space and end delimiter (\s*[;]$) included
-- pstate.offset.column;
--str.end;
--position;

Expand Down Expand Up @@ -1984,22 +2006,22 @@ namespace Sass {

List* Parser::parse_media_queries()
{
advanceToNextToken();
List* media_queries = SASS_MEMORY_NEW(ctx.mem, List, pstate, 0, SASS_COMMA);
if (!peek_css < exactly <'{'> >()) (*media_queries) << parse_media_query();
while (lex_css < exactly <','> >()) (*media_queries) << parse_media_query();
media_queries->update_pstate(pstate);
return media_queries;
}

// Expression* Parser::parse_media_query()
Media_Query* Parser::parse_media_query()
{
advanceToNextToken();
Media_Query* media_query = SASS_MEMORY_NEW(ctx.mem, Media_Query, pstate);
if (lex < kwd_not >()) { media_query->is_negated(true); lex < css_comments >(false); }
else if (lex < kwd_only >()) { media_query->is_restricted(true); lex < css_comments >(false); }

lex < css_comments >(false);
if (lex < kwd_not >()) media_query->is_negated(true);
else if (lex < kwd_only >()) media_query->is_restricted(true);

lex < css_comments >(false);
if (lex < identifier_schema >()) media_query->media_type(parse_identifier_schema());
else if (lex < identifier >()) media_query->media_type(parse_interpolated_chunk(lexed));
else (*media_query) << parse_media_expression();
Expand All @@ -2013,6 +2035,9 @@ namespace Sass {
media_query->media_type(schema);
}
while (lex_css < kwd_and >()) (*media_query) << parse_media_expression();

media_query->update_pstate(pstate);

return media_query;
}

Expand Down Expand Up @@ -2620,7 +2645,7 @@ namespace Sass {
Expression* Parser::fold_operands(Expression* base, std::vector<Expression*>& operands, Operand op)
{
for (size_t i = 0, S = operands.size(); i < S; ++i) {
base = SASS_MEMORY_NEW(ctx.mem, Binary_Expression, pstate, op, base, operands[i]);
base = SASS_MEMORY_NEW(ctx.mem, Binary_Expression, base->pstate(), op, base, operands[i]);
}
return base;
}
Expand Down
4 changes: 4 additions & 0 deletions src/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ namespace Sass {
#endif


// skip current token and next whitespace
// moves ParserState right before next token
void advanceToNextToken();

bool peek_newline(const char* start = 0);

// skip over spaces, tabs and line comments
Expand Down

0 comments on commit e7a3b7e

Please sign in to comment.