|
Packit Service |
7770af |
#include "sass.hpp"
|
|
Packit Service |
7770af |
#include <iostream>
|
|
Packit Service |
7770af |
#include <typeinfo>
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
#include "ast.hpp"
|
|
Packit Service |
7770af |
#include "expand.hpp"
|
|
Packit Service |
7770af |
#include "bind.hpp"
|
|
Packit Service |
7770af |
#include "eval.hpp"
|
|
Packit Service |
7770af |
#include "backtrace.hpp"
|
|
Packit Service |
7770af |
#include "context.hpp"
|
|
Packit Service |
7770af |
#include "parser.hpp"
|
|
Packit Service |
7770af |
#include "sass_functions.hpp"
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
namespace Sass {
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// simple endless recursion protection
|
|
Packit Service |
7770af |
const size_t maxRecursion = 500;
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Expand::Expand(Context& ctx, Env* env, Backtrace* bt, std::vector<Selector_List_Obj>* stack)
|
|
Packit Service |
7770af |
: ctx(ctx),
|
|
Packit Service |
7770af |
eval(Eval(*this)),
|
|
Packit Service |
7770af |
recursions(0),
|
|
Packit Service |
7770af |
in_keyframes(false),
|
|
Packit Service |
7770af |
at_root_without_rule(false),
|
|
Packit Service |
7770af |
old_at_root_without_rule(false),
|
|
Packit Service |
7770af |
env_stack(std::vector<Env*>()),
|
|
Packit Service |
7770af |
block_stack(std::vector<Block_Ptr>()),
|
|
Packit Service |
7770af |
call_stack(std::vector<AST_Node_Obj>()),
|
|
Packit Service |
7770af |
selector_stack(std::vector<Selector_List_Obj>()),
|
|
Packit Service |
7770af |
media_block_stack(std::vector<Media_Block_Ptr>()),
|
|
Packit Service |
7770af |
backtrace_stack(std::vector<Backtrace*>())
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
env_stack.push_back(0);
|
|
Packit Service |
7770af |
env_stack.push_back(env);
|
|
Packit Service |
7770af |
block_stack.push_back(0);
|
|
Packit Service |
7770af |
call_stack.push_back(0);
|
|
Packit Service |
7770af |
if (stack == NULL) { selector_stack.push_back(0); }
|
|
Packit Service |
7770af |
else { selector_stack.insert(selector_stack.end(), stack->begin(), stack->end()); }
|
|
Packit Service |
7770af |
media_block_stack.push_back(0);
|
|
Packit Service |
7770af |
backtrace_stack.push_back(0);
|
|
Packit Service |
7770af |
backtrace_stack.push_back(bt);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Env* Expand::environment()
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
if (env_stack.size() > 0)
|
|
Packit Service |
7770af |
return env_stack.back();
|
|
Packit Service |
7770af |
return 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Selector_List_Obj Expand::selector()
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
if (selector_stack.size() > 0)
|
|
Packit Service |
7770af |
return selector_stack.back();
|
|
Packit Service |
7770af |
return 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Backtrace* Expand::backtrace()
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
if (backtrace_stack.size() > 0)
|
|
Packit Service |
7770af |
return backtrace_stack.back();
|
|
Packit Service |
7770af |
return 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// blocks create new variable scopes
|
|
Packit Service |
7770af |
Block_Ptr Expand::operator()(Block_Ptr b)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
// create new local environment
|
|
Packit Service |
7770af |
// set the current env as parent
|
|
Packit Service |
7770af |
Env env(environment());
|
|
Packit Service |
7770af |
// copy the block object (add items later)
|
|
Packit Service |
7770af |
Block_Obj bb = SASS_MEMORY_NEW(Block,
|
|
Packit Service |
7770af |
b->pstate(),
|
|
Packit Service |
7770af |
b->length(),
|
|
Packit Service |
7770af |
b->is_root());
|
|
Packit Service |
7770af |
// setup block and env stack
|
|
Packit Service |
7770af |
this->block_stack.push_back(bb);
|
|
Packit Service |
7770af |
this->env_stack.push_back(&env;;
|
|
Packit Service |
7770af |
// operate on block
|
|
Packit Service |
7770af |
// this may throw up!
|
|
Packit Service |
7770af |
this->append_block(b);
|
|
Packit Service |
7770af |
// revert block and env stack
|
|
Packit Service |
7770af |
this->block_stack.pop_back();
|
|
Packit Service |
7770af |
this->env_stack.pop_back();
|
|
Packit Service |
7770af |
// return copy
|
|
Packit Service |
7770af |
return bb.detach();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Statement_Ptr Expand::operator()(Ruleset_Ptr r)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
LOCAL_FLAG(old_at_root_without_rule, at_root_without_rule);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
if (in_keyframes) {
|
|
Packit Service |
7770af |
Block_Ptr bb = operator()(r->block());
|
|
Packit Service |
7770af |
Keyframe_Rule_Obj k = SASS_MEMORY_NEW(Keyframe_Rule, r->pstate(), bb);
|
|
Packit Service |
7770af |
if (r->selector()) {
|
|
Packit Service |
7770af |
if (Selector_List_Ptr s = r->selector()) {
|
|
Packit Service |
7770af |
selector_stack.push_back(0);
|
|
Packit Service |
7770af |
k->name(s->eval(eval));
|
|
Packit Service |
7770af |
selector_stack.pop_back();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
return k.detach();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// reset when leaving scope
|
|
Packit Service |
7770af |
LOCAL_FLAG(at_root_without_rule, false);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// `&` is allowed in `@at-root`!
|
|
Packit Service |
7770af |
bool has_parent_selector = false;
|
|
Packit Service |
7770af |
for (size_t i = 0, L = selector_stack.size(); i < L && !has_parent_selector; i++) {
|
|
Packit Service |
7770af |
Selector_List_Obj ll = selector_stack.at(i);
|
|
Packit Service |
7770af |
has_parent_selector = ll != 0 && ll->length() > 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Selector_List_Obj sel = r->selector();
|
|
Packit Service |
7770af |
if (sel) sel = sel->eval(eval);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// check for parent selectors in base level rules
|
|
Packit Service |
7770af |
if (r->is_root()) {
|
|
Packit Service |
7770af |
if (Selector_List_Ptr selector_list = Cast<Selector_List>(r->selector())) {
|
|
Packit Service |
7770af |
for (Complex_Selector_Obj complex_selector : selector_list->elements()) {
|
|
Packit Service |
7770af |
Complex_Selector_Ptr tail = complex_selector;
|
|
Packit Service |
7770af |
while (tail) {
|
|
Packit Service |
7770af |
if (tail->head()) for (Simple_Selector_Obj header : tail->head()->elements()) {
|
|
Packit Service |
7770af |
Parent_Selector_Ptr ptr = Cast<Parent_Selector>(header);
|
|
Packit Service |
7770af |
if (ptr == NULL || (!ptr->real() || has_parent_selector)) continue;
|
|
Packit Service |
7770af |
std::string sel_str(complex_selector->to_string(ctx.c_options));
|
|
Packit Service |
7770af |
error("Base-level rules cannot contain the parent-selector-referencing character '&'.", header->pstate(), backtrace());
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
tail = tail->tail();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
else {
|
|
Packit Service |
7770af |
if (sel->length() == 0 || sel->has_parent_ref()) {
|
|
Packit Service |
7770af |
if (sel->has_real_parent_ref() && !has_parent_selector) {
|
|
Packit Service |
7770af |
error("Base-level rules cannot contain the parent-selector-referencing character '&'.", sel->pstate(), backtrace());
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
selector_stack.push_back(sel);
|
|
Packit Service |
7770af |
Env env(environment());
|
|
Packit Service |
7770af |
if (block_stack.back()->is_root()) {
|
|
Packit Service |
7770af |
env_stack.push_back(&env;;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
sel->set_media_block(media_block_stack.back());
|
|
Packit Service |
7770af |
Block_Obj blk = 0;
|
|
Packit Service |
7770af |
if (r->block()) blk = operator()(r->block());
|
|
Packit Service |
7770af |
Ruleset_Ptr rr = SASS_MEMORY_NEW(Ruleset,
|
|
Packit Service |
7770af |
r->pstate(),
|
|
Packit Service |
7770af |
sel,
|
|
Packit Service |
7770af |
blk);
|
|
Packit Service |
7770af |
selector_stack.pop_back();
|
|
Packit Service |
7770af |
if (block_stack.back()->is_root()) {
|
|
Packit Service |
7770af |
env_stack.pop_back();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
rr->is_root(r->is_root());
|
|
Packit Service |
7770af |
rr->tabs(r->tabs());
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
return rr;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Statement_Ptr Expand::operator()(Supports_Block_Ptr f)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
Expression_Obj condition = f->condition()->perform(&eval);
|
|
Packit Service |
7770af |
Supports_Block_Obj ff = SASS_MEMORY_NEW(Supports_Block,
|
|
Packit Service |
7770af |
f->pstate(),
|
|
Packit Service |
7770af |
Cast<Supports_Condition>(condition),
|
|
Packit Service |
7770af |
operator()(f->block()));
|
|
Packit Service |
7770af |
return ff.detach();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Statement_Ptr Expand::operator()(Media_Block_Ptr m)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
Media_Block_Obj cpy = SASS_MEMORY_COPY(m);
|
|
Packit Service |
7770af |
// Media_Blocks are prone to have circular references
|
|
Packit Service |
7770af |
// Copy could leak memory if it does not get picked up
|
|
Packit Service |
7770af |
// Looks like we are able to reset block reference for copy
|
|
Packit Service |
7770af |
// Good as it will ensure a low memory overhead for this fix
|
|
Packit Service |
7770af |
// So this is a cheap solution with a minimal price
|
|
Packit Service |
7770af |
ctx.ast_gc.push_back(cpy); cpy->block(0);
|
|
Packit Service |
7770af |
Expression_Obj mq = eval(m->media_queries());
|
|
Packit Service |
7770af |
std::string str_mq(mq->to_string(ctx.c_options));
|
|
Packit Service |
7770af |
char* str = sass_copy_c_string(str_mq.c_str());
|
|
Packit Service |
7770af |
ctx.strings.push_back(str);
|
|
Packit Service |
7770af |
Parser p(Parser::from_c_str(str, ctx, mq->pstate()));
|
|
Packit Service |
7770af |
mq = p.parse_media_queries(); // re-assign now
|
|
Packit Service |
7770af |
cpy->media_queries(mq);
|
|
Packit Service |
7770af |
media_block_stack.push_back(cpy);
|
|
Packit Service |
7770af |
Block_Obj blk = operator()(m->block());
|
|
Packit Service |
7770af |
Media_Block_Ptr mm = SASS_MEMORY_NEW(Media_Block,
|
|
Packit Service |
7770af |
m->pstate(),
|
|
Packit Service |
7770af |
mq,
|
|
Packit Service |
7770af |
blk);
|
|
Packit Service |
7770af |
media_block_stack.pop_back();
|
|
Packit Service |
7770af |
mm->tabs(m->tabs());
|
|
Packit Service |
7770af |
return mm;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Statement_Ptr Expand::operator()(At_Root_Block_Ptr a)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
Block_Obj ab = a->block();
|
|
Packit Service |
7770af |
Expression_Obj ae = a->expression();
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
if (ae) ae = ae->perform(&eval);
|
|
Packit Service |
7770af |
else ae = SASS_MEMORY_NEW(At_Root_Query, a->pstate());
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
LOCAL_FLAG(at_root_without_rule, true);
|
|
Packit Service |
7770af |
LOCAL_FLAG(in_keyframes, false);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
;
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Block_Obj bb = ab ? operator()(ab) : NULL;
|
|
Packit Service |
7770af |
At_Root_Block_Obj aa = SASS_MEMORY_NEW(At_Root_Block,
|
|
Packit Service |
7770af |
a->pstate(),
|
|
Packit Service |
7770af |
bb,
|
|
Packit Service |
7770af |
Cast<At_Root_Query>(ae));
|
|
Packit Service |
7770af |
return aa.detach();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Statement_Ptr Expand::operator()(Directive_Ptr a)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
LOCAL_FLAG(in_keyframes, a->is_keyframes());
|
|
Packit Service |
7770af |
Block_Ptr ab = a->block();
|
|
Packit Service |
7770af |
Selector_List_Ptr as = a->selector();
|
|
Packit Service |
7770af |
Expression_Ptr av = a->value();
|
|
Packit Service |
7770af |
selector_stack.push_back(0);
|
|
Packit Service |
7770af |
if (av) av = av->perform(&eval);
|
|
Packit Service |
7770af |
if (as) as = eval(as);
|
|
Packit Service |
7770af |
selector_stack.pop_back();
|
|
Packit Service |
7770af |
Block_Ptr bb = ab ? operator()(ab) : NULL;
|
|
Packit Service |
7770af |
Directive_Ptr aa = SASS_MEMORY_NEW(Directive,
|
|
Packit Service |
7770af |
a->pstate(),
|
|
Packit Service |
7770af |
a->keyword(),
|
|
Packit Service |
7770af |
as,
|
|
Packit Service |
7770af |
bb,
|
|
Packit Service |
7770af |
av);
|
|
Packit Service |
7770af |
return aa;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Statement_Ptr Expand::operator()(Declaration_Ptr d)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
Block_Obj ab = d->block();
|
|
Packit Service |
7770af |
String_Obj old_p = d->property();
|
|
Packit Service |
7770af |
Expression_Obj prop = old_p->perform(&eval);
|
|
Packit Service |
7770af |
String_Obj new_p = Cast<String>(prop);
|
|
Packit Service |
7770af |
// we might get a color back
|
|
Packit Service |
7770af |
if (!new_p) {
|
|
Packit Service |
7770af |
std::string str(prop->to_string(ctx.c_options));
|
|
Packit Service |
7770af |
new_p = SASS_MEMORY_NEW(String_Constant, old_p->pstate(), str);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
Expression_Obj value = d->value()->perform(&eval);
|
|
Packit Service |
7770af |
Block_Obj bb = ab ? operator()(ab) : NULL;
|
|
Packit Service |
7770af |
if (!bb) {
|
|
Packit Service |
7770af |
if (!value || (value->is_invisible() && !d->is_important())) return 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
Declaration_Ptr decl = SASS_MEMORY_NEW(Declaration,
|
|
Packit Service |
7770af |
d->pstate(),
|
|
Packit Service |
7770af |
new_p,
|
|
Packit Service |
7770af |
value,
|
|
Packit Service |
7770af |
d->is_important(),
|
|
Packit Service |
7770af |
bb);
|
|
Packit Service |
7770af |
decl->tabs(d->tabs());
|
|
Packit Service |
7770af |
return decl;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Statement_Ptr Expand::operator()(Assignment_Ptr a)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
Env* env = environment();
|
|
Packit Service |
7770af |
const std::string& var(a->variable());
|
|
Packit Service |
7770af |
if (a->is_global()) {
|
|
Packit Service |
7770af |
if (a->is_default()) {
|
|
Packit Service |
7770af |
if (env->has_global(var)) {
|
|
Packit Service |
7770af |
Expression_Obj e = Cast<Expression>(env->get_global(var));
|
|
Packit Service |
7770af |
if (!e || e->concrete_type() == Expression::NULL_VAL) {
|
|
Packit Service |
7770af |
env->set_global(var, a->value()->perform(&eval));
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
else {
|
|
Packit Service |
7770af |
env->set_global(var, a->value()->perform(&eval));
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
else {
|
|
Packit Service |
7770af |
env->set_global(var, a->value()->perform(&eval));
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
else if (a->is_default()) {
|
|
Packit Service |
7770af |
if (env->has_lexical(var)) {
|
|
Packit Service |
7770af |
auto cur = env;
|
|
Packit Service |
7770af |
while (cur && cur->is_lexical()) {
|
|
Packit Service |
7770af |
if (cur->has_local(var)) {
|
|
Packit Service |
7770af |
if (AST_Node_Obj node = cur->get_local(var)) {
|
|
Packit Service |
7770af |
Expression_Obj e = Cast<Expression>(node);
|
|
Packit Service |
7770af |
if (!e || e->concrete_type() == Expression::NULL_VAL) {
|
|
Packit Service |
7770af |
cur->set_local(var, a->value()->perform(&eval));
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
else {
|
|
Packit Service |
7770af |
throw std::runtime_error("Env not in sync");
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
return 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
cur = cur->parent();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
throw std::runtime_error("Env not in sync");
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
else if (env->has_global(var)) {
|
|
Packit Service |
7770af |
if (AST_Node_Obj node = env->get_global(var)) {
|
|
Packit Service |
7770af |
Expression_Obj e = Cast<Expression>(node);
|
|
Packit Service |
7770af |
if (!e || e->concrete_type() == Expression::NULL_VAL) {
|
|
Packit Service |
7770af |
env->set_global(var, a->value()->perform(&eval));
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
else if (env->is_lexical()) {
|
|
Packit Service |
7770af |
env->set_local(var, a->value()->perform(&eval));
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
else {
|
|
Packit Service |
7770af |
env->set_local(var, a->value()->perform(&eval));
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
else {
|
|
Packit Service |
7770af |
env->set_lexical(var, a->value()->perform(&eval));
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
return 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Statement_Ptr Expand::operator()(Import_Ptr imp)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
Import_Obj result = SASS_MEMORY_NEW(Import, imp->pstate());
|
|
Packit Service |
7770af |
if (imp->import_queries() && imp->import_queries()->size()) {
|
|
Packit Service |
7770af |
Expression_Obj ex = imp->import_queries()->perform(&eval);
|
|
Packit Service |
7770af |
result->import_queries(Cast<List>(ex));
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
for ( size_t i = 0, S = imp->urls().size(); i < S; ++i) {
|
|
Packit Service |
7770af |
result->urls().push_back(imp->urls()[i]->perform(&eval));
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
// all resources have been dropped for Input_Stubs
|
|
Packit Service |
7770af |
// for ( size_t i = 0, S = imp->incs().size(); i < S; ++i) {}
|
|
Packit Service |
7770af |
return result.detach();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Statement_Ptr Expand::operator()(Import_Stub_Ptr i)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
// get parent node from call stack
|
|
Packit Service |
7770af |
AST_Node_Obj parent = call_stack.back();
|
|
Packit Service |
7770af |
if (Cast<Block>(parent) == NULL) {
|
|
Packit Service |
7770af |
error("Import directives may not be used within control directives or mixins.", i->pstate());
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
// we don't seem to need that actually afterall
|
|
Packit Service |
7770af |
Sass_Import_Entry import = sass_make_import(
|
|
Packit Service |
7770af |
i->imp_path().c_str(),
|
|
Packit Service |
7770af |
i->abs_path().c_str(),
|
|
Packit Service |
7770af |
0, 0
|
|
Packit Service |
7770af |
);
|
|
Packit Service |
7770af |
ctx.import_stack.push_back(import);
|
|
Packit Service |
7770af |
const std::string& abs_path(i->resource().abs_path);
|
|
Packit Service |
7770af |
append_block(ctx.sheets.at(abs_path).root);
|
|
Packit Service |
7770af |
sass_delete_import(ctx.import_stack.back());
|
|
Packit Service |
7770af |
ctx.import_stack.pop_back();
|
|
Packit Service |
7770af |
return 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Statement_Ptr Expand::operator()(Warning_Ptr w)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
// eval handles this too, because warnings may occur in functions
|
|
Packit Service |
7770af |
w->perform(&eval);
|
|
Packit Service |
7770af |
return 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Statement_Ptr Expand::operator()(Error_Ptr e)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
// eval handles this too, because errors may occur in functions
|
|
Packit Service |
7770af |
e->perform(&eval);
|
|
Packit Service |
7770af |
return 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Statement_Ptr Expand::operator()(Debug_Ptr d)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
// eval handles this too, because warnings may occur in functions
|
|
Packit Service |
7770af |
d->perform(&eval);
|
|
Packit Service |
7770af |
return 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Statement_Ptr Expand::operator()(Comment_Ptr c)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
if (ctx.output_style() == COMPRESSED) {
|
|
Packit Service |
7770af |
// comments should not be evaluated in compact
|
|
Packit Service |
7770af |
// https://github.com/sass/libsass/issues/2359
|
|
Packit Service |
7770af |
if (!c->is_important()) return NULL;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
eval.is_in_comment = true;
|
|
Packit Service |
7770af |
Comment_Ptr rv = SASS_MEMORY_NEW(Comment, c->pstate(), Cast<String>(c->text()->perform(&eval)), c->is_important());
|
|
Packit Service |
7770af |
eval.is_in_comment = false;
|
|
Packit Service |
7770af |
// TODO: eval the text, once we're parsing/storing it as a String_Schema
|
|
Packit Service |
7770af |
return rv;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Statement_Ptr Expand::operator()(If_Ptr i)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
Env env(environment(), true);
|
|
Packit Service |
7770af |
env_stack.push_back(&env;;
|
|
Packit Service |
7770af |
call_stack.push_back(i);
|
|
Packit Service |
7770af |
Expression_Obj rv = i->predicate()->perform(&eval);
|
|
Packit Service |
7770af |
if (*rv) {
|
|
Packit Service |
7770af |
append_block(i->block());
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
else {
|
|
Packit Service |
7770af |
Block_Ptr alt = i->alternative();
|
|
Packit Service |
7770af |
if (alt) append_block(alt);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
call_stack.pop_back();
|
|
Packit Service |
7770af |
env_stack.pop_back();
|
|
Packit Service |
7770af |
return 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// For does not create a new env scope
|
|
Packit Service |
7770af |
// But iteration vars are reset afterwards
|
|
Packit Service |
7770af |
Statement_Ptr Expand::operator()(For_Ptr f)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
std::string variable(f->variable());
|
|
Packit Service |
7770af |
Expression_Obj low = f->lower_bound()->perform(&eval);
|
|
Packit Service |
7770af |
if (low->concrete_type() != Expression::NUMBER) {
|
|
Packit Service |
7770af |
throw Exception::TypeMismatch(*low, "integer");
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
Expression_Obj high = f->upper_bound()->perform(&eval);
|
|
Packit Service |
7770af |
if (high->concrete_type() != Expression::NUMBER) {
|
|
Packit Service |
7770af |
throw Exception::TypeMismatch(*high, "integer");
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
Number_Obj sass_start = Cast<Number>(low);
|
|
Packit Service |
7770af |
Number_Obj sass_end = Cast<Number>(high);
|
|
Packit Service |
7770af |
// check if units are valid for sequence
|
|
Packit Service |
7770af |
if (sass_start->unit() != sass_end->unit()) {
|
|
Packit Service |
7770af |
std::stringstream msg; msg << "Incompatible units: '"
|
|
Packit Service |
7770af |
<< sass_start->unit() << "' and '"
|
|
Packit Service |
7770af |
<< sass_end->unit() << "'.";
|
|
Packit Service |
7770af |
error(msg.str(), low->pstate(), backtrace());
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
double start = sass_start->value();
|
|
Packit Service |
7770af |
double end = sass_end->value();
|
|
Packit Service |
7770af |
// only create iterator once in this environment
|
|
Packit Service |
7770af |
Env env(environment(), true);
|
|
Packit Service |
7770af |
env_stack.push_back(&env;;
|
|
Packit Service |
7770af |
call_stack.push_back(f);
|
|
Packit Service |
7770af |
Block_Ptr body = f->block();
|
|
Packit Service |
7770af |
if (start < end) {
|
|
Packit Service |
7770af |
if (f->is_inclusive()) ++end;
|
|
Packit Service |
7770af |
for (double i = start;
|
|
Packit Service |
7770af |
i < end;
|
|
Packit Service |
7770af |
++i) {
|
|
Packit Service |
7770af |
Number_Obj it = SASS_MEMORY_NEW(Number, low->pstate(), i, sass_end->unit());
|
|
Packit Service |
7770af |
env.set_local(variable, it);
|
|
Packit Service |
7770af |
append_block(body);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
} else {
|
|
Packit Service |
7770af |
if (f->is_inclusive()) --end;
|
|
Packit Service |
7770af |
for (double i = start;
|
|
Packit Service |
7770af |
i > end;
|
|
Packit Service |
7770af |
--i) {
|
|
Packit Service |
7770af |
Number_Obj it = SASS_MEMORY_NEW(Number, low->pstate(), i, sass_end->unit());
|
|
Packit Service |
7770af |
env.set_local(variable, it);
|
|
Packit Service |
7770af |
append_block(body);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
call_stack.pop_back();
|
|
Packit Service |
7770af |
env_stack.pop_back();
|
|
Packit Service |
7770af |
return 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Eval does not create a new env scope
|
|
Packit Service |
7770af |
// But iteration vars are reset afterwards
|
|
Packit Service |
7770af |
Statement_Ptr Expand::operator()(Each_Ptr e)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
std::vector<std::string> variables(e->variables());
|
|
Packit Service |
7770af |
Expression_Obj expr = e->list()->perform(&eval);
|
|
Packit Service |
7770af |
List_Obj list = 0;
|
|
Packit Service |
7770af |
Map_Obj map;
|
|
Packit Service |
7770af |
if (expr->concrete_type() == Expression::MAP) {
|
|
Packit Service |
7770af |
map = Cast<Map>(expr);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
else if (Selector_List_Ptr ls = Cast<Selector_List>(expr)) {
|
|
Packit Service |
7770af |
Listize listize;
|
|
Packit Service |
7770af |
Expression_Obj rv = ls->perform(&listize);
|
|
Packit Service |
7770af |
list = Cast<List>(rv);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
else if (expr->concrete_type() != Expression::LIST) {
|
|
Packit Service |
7770af |
list = SASS_MEMORY_NEW(List, expr->pstate(), 1, SASS_COMMA);
|
|
Packit Service |
7770af |
list->append(expr);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
else {
|
|
Packit Service |
7770af |
list = Cast<List>(expr);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
// remember variables and then reset them
|
|
Packit Service |
7770af |
Env env(environment(), true);
|
|
Packit Service |
7770af |
env_stack.push_back(&env;;
|
|
Packit Service |
7770af |
call_stack.push_back(e);
|
|
Packit Service |
7770af |
Block_Ptr body = e->block();
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
if (map) {
|
|
Packit Service |
7770af |
for (auto key : map->keys()) {
|
|
Packit Service |
7770af |
Expression_Obj k = key->perform(&eval);
|
|
Packit Service |
7770af |
Expression_Obj v = map->at(key)->perform(&eval);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
if (variables.size() == 1) {
|
|
Packit Service |
7770af |
List_Obj variable = SASS_MEMORY_NEW(List, map->pstate(), 2, SASS_SPACE);
|
|
Packit Service |
7770af |
variable->append(k);
|
|
Packit Service |
7770af |
variable->append(v);
|
|
Packit Service |
7770af |
env.set_local(variables[0], variable);
|
|
Packit Service |
7770af |
} else {
|
|
Packit Service |
7770af |
env.set_local(variables[0], k);
|
|
Packit Service |
7770af |
env.set_local(variables[1], v);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
append_block(body);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
else {
|
|
Packit Service |
7770af |
// bool arglist = list->is_arglist();
|
|
Packit Service |
7770af |
if (list->length() == 1 && Cast<Selector_List>(list)) {
|
|
Packit Service |
7770af |
list = Cast<List>(list);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
for (size_t i = 0, L = list->length(); i < L; ++i) {
|
|
Packit Service |
7770af |
Expression_Obj item = list->at(i);
|
|
Packit Service |
7770af |
// unwrap value if the expression is an argument
|
|
Packit Service |
7770af |
if (Argument_Obj arg = Cast<Argument>(item)) item = arg->value();
|
|
Packit Service |
7770af |
// check if we got passed a list of args (investigate)
|
|
Packit Service |
7770af |
if (List_Obj scalars = Cast<List>(item)) {
|
|
Packit Service |
7770af |
if (variables.size() == 1) {
|
|
Packit Service |
7770af |
List_Obj var = scalars;
|
|
Packit Service |
7770af |
// if (arglist) var = (*scalars)[0];
|
|
Packit Service |
7770af |
env.set_local(variables[0], var);
|
|
Packit Service |
7770af |
} else {
|
|
Packit Service |
7770af |
for (size_t j = 0, K = variables.size(); j < K; ++j) {
|
|
Packit Service |
7770af |
Expression_Obj res = j >= scalars->length()
|
|
Packit Service |
7770af |
? SASS_MEMORY_NEW(Null, expr->pstate())
|
|
Packit Service |
7770af |
: (*scalars)[j]->perform(&eval);
|
|
Packit Service |
7770af |
env.set_local(variables[j], res);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
} else {
|
|
Packit Service |
7770af |
if (variables.size() > 0) {
|
|
Packit Service |
7770af |
env.set_local(variables.at(0), item);
|
|
Packit Service |
7770af |
for (size_t j = 1, K = variables.size(); j < K; ++j) {
|
|
Packit Service |
7770af |
Expression_Obj res = SASS_MEMORY_NEW(Null, expr->pstate());
|
|
Packit Service |
7770af |
env.set_local(variables[j], res);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
append_block(body);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
call_stack.pop_back();
|
|
Packit Service |
7770af |
env_stack.pop_back();
|
|
Packit Service |
7770af |
return 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Statement_Ptr Expand::operator()(While_Ptr w)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
Expression_Obj pred = w->predicate();
|
|
Packit Service |
7770af |
Block_Ptr body = w->block();
|
|
Packit Service |
7770af |
Env env(environment(), true);
|
|
Packit Service |
7770af |
env_stack.push_back(&env;;
|
|
Packit Service |
7770af |
call_stack.push_back(w);
|
|
Packit Service |
7770af |
Expression_Obj cond = pred->perform(&eval);
|
|
Packit Service |
7770af |
while (!cond->is_false()) {
|
|
Packit Service |
7770af |
append_block(body);
|
|
Packit Service |
7770af |
cond = pred->perform(&eval);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
call_stack.pop_back();
|
|
Packit Service |
7770af |
env_stack.pop_back();
|
|
Packit Service |
7770af |
return 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Statement_Ptr Expand::operator()(Return_Ptr r)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
error("@return may only be used within a function", r->pstate(), backtrace());
|
|
Packit Service |
7770af |
return 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
void Expand::expand_selector_list(Selector_Obj s, Selector_List_Obj extender) {
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
if (Selector_List_Obj sl = Cast<Selector_List>(s)) {
|
|
Packit Service |
7770af |
for (Complex_Selector_Obj complex_selector : sl->elements()) {
|
|
Packit Service |
7770af |
Complex_Selector_Obj tail = complex_selector;
|
|
Packit Service |
7770af |
while (tail) {
|
|
Packit Service |
7770af |
if (tail->head()) for (Simple_Selector_Obj header : tail->head()->elements()) {
|
|
Packit Service |
7770af |
if (Cast<Parent_Selector>(header) == NULL) continue; // skip all others
|
|
Packit Service |
7770af |
std::string sel_str(complex_selector->to_string(ctx.c_options));
|
|
Packit Service |
7770af |
error("Can't extend " + sel_str + ": can't extend parent selectors", header->pstate(), backtrace());
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
tail = tail->tail();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Selector_List_Obj contextualized = Cast<Selector_List>(s->perform(&eval));
|
|
Packit Service |
7770af |
if (contextualized == false) return;
|
|
Packit Service |
7770af |
for (auto complex_sel : contextualized->elements()) {
|
|
Packit Service |
7770af |
Complex_Selector_Obj c = complex_sel;
|
|
Packit Service |
7770af |
if (!c->head() || c->tail()) {
|
|
Packit Service |
7770af |
std::string sel_str(contextualized->to_string(ctx.c_options));
|
|
Packit Service |
7770af |
error("Can't extend " + sel_str + ": can't extend nested selectors", c->pstate(), backtrace());
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
Compound_Selector_Obj target = c->head();
|
|
Packit Service |
7770af |
if (contextualized->is_optional()) target->is_optional(true);
|
|
Packit Service |
7770af |
for (size_t i = 0, L = extender->length(); i < L; ++i) {
|
|
Packit Service |
7770af |
Complex_Selector_Obj sel = (*extender)[i];
|
|
Packit Service |
7770af |
if (!(sel->head() && sel->head()->length() > 0 &&
|
|
Packit Service |
7770af |
Cast<Parent_Selector>((*sel->head())[0])))
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
Compound_Selector_Obj hh = SASS_MEMORY_NEW(Compound_Selector, (*extender)[i]->pstate());
|
|
Packit Service |
7770af |
hh->media_block((*extender)[i]->media_block());
|
|
Packit Service |
7770af |
Complex_Selector_Obj ssel = SASS_MEMORY_NEW(Complex_Selector, (*extender)[i]->pstate());
|
|
Packit Service |
7770af |
ssel->media_block((*extender)[i]->media_block());
|
|
Packit Service |
7770af |
if (sel->has_line_feed()) ssel->has_line_feed(true);
|
|
Packit Service |
7770af |
Parent_Selector_Obj ps = SASS_MEMORY_NEW(Parent_Selector, (*extender)[i]->pstate());
|
|
Packit Service |
7770af |
ps->media_block((*extender)[i]->media_block());
|
|
Packit Service |
7770af |
hh->append(ps);
|
|
Packit Service |
7770af |
ssel->tail(sel);
|
|
Packit Service |
7770af |
ssel->head(hh);
|
|
Packit Service |
7770af |
sel = ssel;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
// if (c->has_line_feed()) sel->has_line_feed(true);
|
|
Packit Service |
7770af |
ctx.subset_map.put(target, std::make_pair(sel, target));
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Statement* Expand::operator()(Extension_Ptr e)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
if (Selector_List_Ptr extender = selector()) {
|
|
Packit Service |
7770af |
Selector_List_Ptr sl = e->selector();
|
|
Packit Service |
7770af |
// abort on invalid selector
|
|
Packit Service |
7770af |
if (sl == NULL) return NULL;
|
|
Packit Service |
7770af |
if (Selector_Schema_Ptr schema = sl->schema()) {
|
|
Packit Service |
7770af |
if (schema->has_real_parent_ref()) {
|
|
Packit Service |
7770af |
// put root block on stack again (ignore parents)
|
|
Packit Service |
7770af |
// selector schema must not connect in eval!
|
|
Packit Service |
7770af |
block_stack.push_back(block_stack.at(1));
|
|
Packit Service |
7770af |
sl = eval(sl->schema());
|
|
Packit Service |
7770af |
block_stack.pop_back();
|
|
Packit Service |
7770af |
} else {
|
|
Packit Service |
7770af |
selector_stack.push_back(0);
|
|
Packit Service |
7770af |
sl = eval(sl->schema());
|
|
Packit Service |
7770af |
selector_stack.pop_back();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
for (Complex_Selector_Obj cs : sl->elements()) {
|
|
Packit Service |
7770af |
if (!cs.isNull() && !cs->head().isNull()) {
|
|
Packit Service |
7770af |
cs->head()->media_block(media_block_stack.back());
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
selector_stack.push_back(0);
|
|
Packit Service |
7770af |
expand_selector_list(sl, extender);
|
|
Packit Service |
7770af |
selector_stack.pop_back();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
return 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Statement_Ptr Expand::operator()(Definition_Ptr d)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
Env* env = environment();
|
|
Packit Service |
7770af |
Definition_Obj dd = SASS_MEMORY_COPY(d);
|
|
Packit Service |
7770af |
env->local_frame()[d->name() +
|
|
Packit Service |
7770af |
(d->type() == Definition::MIXIN ? "[m]" : "[f]")] = dd;
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
if (d->type() == Definition::FUNCTION && (
|
|
Packit Service |
7770af |
Prelexer::calc_fn_call(d->name().c_str()) ||
|
|
Packit Service |
7770af |
d->name() == "element" ||
|
|
Packit Service |
7770af |
d->name() == "expression" ||
|
|
Packit Service |
7770af |
d->name() == "url"
|
|
Packit Service |
7770af |
)) {
|
|
Packit Service |
7770af |
deprecated(
|
|
Packit Service |
7770af |
"Naming a function \"" + d->name() + "\" is disallowed",
|
|
Packit Service |
7770af |
"This name conflicts with an existing CSS function with special parse rules.",
|
|
Packit Service |
7770af |
d->pstate()
|
|
Packit Service |
7770af |
);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// set the static link so we can have lexical scoping
|
|
Packit Service |
7770af |
dd->environment(env);
|
|
Packit Service |
7770af |
return 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Statement_Ptr Expand::operator()(Mixin_Call_Ptr c)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
if (recursions > maxRecursion) {
|
|
Packit Service |
7770af |
throw Exception::StackError(*c);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
recursions ++;
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Env* env = environment();
|
|
Packit Service |
7770af |
std::string full_name(c->name() + "[m]");
|
|
Packit Service |
7770af |
if (!env->has(full_name)) {
|
|
Packit Service |
7770af |
error("no mixin named " + c->name(), c->pstate(), backtrace());
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
Definition_Obj def = Cast<Definition>((*env)[full_name]);
|
|
Packit Service |
7770af |
Block_Obj body = def->block();
|
|
Packit Service |
7770af |
Parameters_Obj params = def->parameters();
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
if (c->block() && c->name() != "@content" && !body->has_content()) {
|
|
Packit Service |
7770af |
error("Mixin \"" + c->name() + "\" does not accept a content block.", c->pstate(), backtrace());
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
Expression_Obj rv = c->arguments()->perform(&eval);
|
|
Packit Service |
7770af |
Arguments_Obj args = Cast<Arguments>(rv);
|
|
Packit Service |
7770af |
Backtrace new_bt(backtrace(), c->pstate(), ", in mixin `" + c->name() + "`");
|
|
Packit Service |
7770af |
backtrace_stack.push_back(&new_bt);
|
|
Packit Service |
7770af |
ctx.callee_stack.push_back({
|
|
Packit Service |
7770af |
c->name().c_str(),
|
|
Packit Service |
7770af |
c->pstate().path,
|
|
Packit Service |
7770af |
c->pstate().line + 1,
|
|
Packit Service |
7770af |
c->pstate().column + 1,
|
|
Packit Service |
7770af |
SASS_CALLEE_MIXIN,
|
|
Packit Service |
7770af |
{ env }
|
|
Packit Service |
7770af |
});
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Env new_env(def->environment());
|
|
Packit Service |
7770af |
env_stack.push_back(&new_env);
|
|
Packit Service |
7770af |
if (c->block()) {
|
|
Packit Service |
7770af |
// represent mixin content blocks as thunks/closures
|
|
Packit Service |
7770af |
Definition_Obj thunk = SASS_MEMORY_NEW(Definition,
|
|
Packit Service |
7770af |
c->pstate(),
|
|
Packit Service |
7770af |
"@content",
|
|
Packit Service |
7770af |
SASS_MEMORY_NEW(Parameters, c->pstate()),
|
|
Packit Service |
7770af |
c->block(),
|
|
Packit Service |
7770af |
Definition::MIXIN);
|
|
Packit Service |
7770af |
thunk->environment(env);
|
|
Packit Service |
7770af |
new_env.local_frame()["@content[m]"] = thunk;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
bind(std::string("Mixin"), c->name(), params, args, &ctx, &new_env, &eval);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Block_Obj trace_block = SASS_MEMORY_NEW(Block, c->pstate());
|
|
Packit Service |
7770af |
Trace_Obj trace = SASS_MEMORY_NEW(Trace, c->pstate(), c->name(), trace_block);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
block_stack.push_back(trace_block);
|
|
Packit Service |
7770af |
for (auto bb : body->elements()) {
|
|
Packit Service |
7770af |
Statement_Obj ith = bb->perform(this);
|
|
Packit Service |
7770af |
if (ith) trace->block()->append(ith);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
block_stack.pop_back();
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
env_stack.pop_back();
|
|
Packit Service |
7770af |
backtrace_stack.pop_back();
|
|
Packit Service |
7770af |
ctx.callee_stack.pop_back();
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
recursions --;
|
|
Packit Service |
7770af |
return trace.detach();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Statement_Ptr Expand::operator()(Content_Ptr c)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
Env* env = environment();
|
|
Packit Service |
7770af |
// convert @content directives into mixin calls to the underlying thunk
|
|
Packit Service |
7770af |
if (!env->has("@content[m]")) return 0;
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
if (block_stack.back()->is_root()) {
|
|
Packit Service |
7770af |
selector_stack.push_back(0);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Mixin_Call_Obj call = SASS_MEMORY_NEW(Mixin_Call,
|
|
Packit Service |
7770af |
c->pstate(),
|
|
Packit Service |
7770af |
"@content",
|
|
Packit Service |
7770af |
SASS_MEMORY_NEW(Arguments, c->pstate()));
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Trace_Obj trace = Cast<Trace>(call->perform(this));
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
if (block_stack.back()->is_root()) {
|
|
Packit Service |
7770af |
selector_stack.pop_back();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
return trace.detach();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// produce an error if something is not implemented
|
|
Packit Service |
7770af |
inline Statement_Ptr Expand::fallback_impl(AST_Node_Ptr n)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
std::string err =std:: string("`Expand` doesn't handle ") + typeid(*n).name();
|
|
Packit Service |
7770af |
String_Quoted_Obj msg = SASS_MEMORY_NEW(String_Quoted, ParserState("[WARN]"), err);
|
|
Packit Service |
7770af |
error("unknown internal error; please contact the LibSass maintainers", n->pstate(), backtrace());
|
|
Packit Service |
7770af |
return SASS_MEMORY_NEW(Warning, ParserState("[WARN]"), msg);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// process and add to last block on stack
|
|
Packit Service |
7770af |
inline void Expand::append_block(Block_Ptr b)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
if (b->is_root()) call_stack.push_back(b);
|
|
Packit Service |
7770af |
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
Packit Service |
7770af |
Statement_Ptr stm = b->at(i);
|
|
Packit Service |
7770af |
Statement_Obj ith = stm->perform(this);
|
|
Packit Service |
7770af |
if (ith) block_stack.back()->append(ith);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
if (b->is_root()) call_stack.pop_back();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
}
|