Skip to content

Commit

Permalink
Error when declarations are printed without ruleset
Browse files Browse the repository at this point in the history
This is introduces a vastly reduced `CheckNesting` visitor from Ruby
Sass as discussed in sass#2061. Doing this properly will require some
small changes to the parser, and probably eval, which currently try
to do some nesting checking of their own.

This is just first step to properly introducing the proper nesting
checking.

Closes sass#2061
Fixes sass#1732
  • Loading branch information
xzyfer committed May 2, 2016
1 parent c95478c commit 2e7810d
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 0 deletions.
1 change: 1 addition & 0 deletions Makefile.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ SOURCES = \
ast.cpp \
base64vlq.cpp \
bind.cpp \
check_nesting.cpp \
color_maps.cpp \
constants.cpp \
context.cpp \
Expand Down
66 changes: 66 additions & 0 deletions src/check_nesting.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include "sass.hpp"
#include <vector>

#include "check_nesting.hpp"
#include "context.hpp"
// #include "debugger.hpp"

namespace Sass {

CheckNesting::CheckNesting(Context& ctx)
: ctx(ctx),
parent_stack(std::vector<AST_Node*>())
{ }

AST_Node* CheckNesting::parent()
{
if (parent_stack.size() > 0)
return parent_stack.back();
return 0;
}

Statement* CheckNesting::operator()(Block* b)
{
parent_stack.push_back(b);
append_block(b);
parent_stack.pop_back();
return b;
}

Statement* CheckNesting::operator()(Declaration* d)
{
if (!is_valid_prop_parent(parent())) {
throw Exception::InvalidSass(d->pstate(), "Properties are only allowed "
"within rules, directives, mixin includes, or other properties.");
}
return static_cast<Statement*>(d);
}

Statement* CheckNesting::fallback_impl(AST_Node* n)
{
return static_cast<Statement*>(n);
}

bool CheckNesting::is_valid_prop_parent(AST_Node* p)
{
if (Definition* def = dynamic_cast<Definition*>(p)) {
return def->type() == Definition::MIXIN;
}

return dynamic_cast<Ruleset*>(p) ||
dynamic_cast<Keyframe_Rule*>(p) ||
dynamic_cast<Propset*>(p) ||
dynamic_cast<Directive*>(p) ||
dynamic_cast<Mixin_Call*>(p);
}

void CheckNesting::append_block(Block* b)
{
for (size_t i = 0, L = b->length(); i < L; ++i) {
Statement* ith = (*b)[i]->perform(this);
if (ith) {
(*b)[i] = ith;
}
}
}
}
38 changes: 38 additions & 0 deletions src/check_nesting.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#ifndef SASS_CHECK_NESTING_H
#define SASS_CHECK_NESTING_H

#include "ast.hpp"
#include "context.hpp"
#include "operation.hpp"

namespace Sass {

typedef Environment<AST_Node*> Env;

class CheckNesting : public Operation_CRTP<Statement*, CheckNesting> {

Context& ctx;
std::vector<Block*> block_stack;
std::vector<AST_Node*> parent_stack;

AST_Node* parent();

Statement* fallback_impl(AST_Node* n);

public:
CheckNesting(Context&);
~CheckNesting() { }

Statement* operator()(Block*);
Statement* operator()(Declaration*);

template <typename U>
Statement* fallback(U x) { return fallback_impl(x); }

bool is_valid_prop_parent(AST_Node*);
void append_block(Block*);
};

}

#endif
6 changes: 6 additions & 0 deletions src/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "output.hpp"
#include "expand.hpp"
#include "eval.hpp"
#include "check_nesting.hpp"
#include "cssize.hpp"
#include "listize.hpp"
#include "extend.hpp"
Expand Down Expand Up @@ -648,8 +649,13 @@ namespace Sass {
// create crtp visitor objects
Expand expand(*this, &global, &backtrace);
Cssize cssize(*this, &backtrace);
CheckNesting check_nesting(*this);
// check nesting
root = root->perform(&check_nesting)->block();
// expand and eval the tree
root = root->perform(&expand)->block();
// check nesting
root = root->perform(&check_nesting)->block();
// merge and bubble certain rules
root = root->perform(&cssize)->block();
// should we extend something?
Expand Down
2 changes: 2 additions & 0 deletions win/libsass.targets
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<ClInclude Include="$(LIBSASS_HEADERS_DIR)\base64vlq.hpp" />
<ClInclude Include="$(LIBSASS_HEADERS_DIR)\bind.hpp" />
<ClInclude Include="$(LIBSASS_HEADERS_DIR)\b64\cencode.h" />
<ClInclude Include="$(LIBSASS_HEADERS_DIR)\check_nesting.hpp" />
<ClInclude Include="$(LIBSASS_HEADERS_DIR)\color_maps.hpp" />
<ClInclude Include="$(LIBSASS_HEADERS_DIR)\constants.hpp" />
<ClInclude Include="$(LIBSASS_HEADERS_DIR)\context.hpp" />
Expand Down Expand Up @@ -71,6 +72,7 @@
<ClCompile Include="$(LIBSASS_SRC_DIR)\bind.cpp" />
<ClCompile Condition="$(VisualStudioVersion) &lt; 14.0" Include="$(LIBSASS_SRC_DIR)\c99func.c" />
<ClCompile Include="$(LIBSASS_SRC_DIR)\cencode.c" />
<ClCompile Include="$(LIBSASS_SRC_DIR)\check_nesting.cpp" />
<ClCompile Include="$(LIBSASS_SRC_DIR)\color_maps.cpp" />
<ClCompile Include="$(LIBSASS_SRC_DIR)\constants.cpp" />
<ClCompile Include="$(LIBSASS_SRC_DIR)\context.cpp" />
Expand Down
6 changes: 6 additions & 0 deletions win/libsass.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@
<ClInclude Include="$(LIBSASS_HEADERS_DIR)\bind.hpp">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="$(LIBSASS_HEADERS_DIR)\check_nesting.hpp">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="$(LIBSASS_HEADERS_DIR)\color_maps.hpp">
<Filter>Headers</Filter>
</ClInclude>
Expand Down Expand Up @@ -224,6 +227,9 @@
<ClCompile Include="$(LIBSASS_SRC_DIR)\cencode.c">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="$(LIBSASS_SRC_DIR)\check_nesting.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="$(LIBSASS_SRC_DIR)\color_maps.cpp">
<Filter>Sources</Filter>
</ClCompile>
Expand Down

0 comments on commit 2e7810d

Please sign in to comment.