sassc 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.gitmodules +3 -0
- data/.travis.yml +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +24 -0
- data/Rakefile +21 -0
- data/ext/libsass/.editorconfig +15 -0
- data/ext/libsass/.gitattributes +2 -0
- data/ext/libsass/.gitignore +61 -0
- data/ext/libsass/.travis.yml +38 -0
- data/ext/libsass/COPYING +25 -0
- data/ext/libsass/INSTALL +1 -0
- data/ext/libsass/LICENSE +25 -0
- data/ext/libsass/Makefile +223 -0
- data/ext/libsass/Makefile.am +145 -0
- data/ext/libsass/Readme.md +93 -0
- data/ext/libsass/appveyor.yml +76 -0
- data/ext/libsass/ast.cpp +581 -0
- data/ext/libsass/ast.hpp +1949 -0
- data/ext/libsass/ast_def_macros.hpp +16 -0
- data/ext/libsass/ast_factory.hpp +87 -0
- data/ext/libsass/ast_fwd_decl.hpp +72 -0
- data/ext/libsass/b64/cencode.h +32 -0
- data/ext/libsass/b64/encode.h +77 -0
- data/ext/libsass/backtrace.hpp +81 -0
- data/ext/libsass/base64vlq.cpp +43 -0
- data/ext/libsass/base64vlq.hpp +28 -0
- data/ext/libsass/bind.cpp +187 -0
- data/ext/libsass/bind.hpp +18 -0
- data/ext/libsass/cencode.c +102 -0
- data/ext/libsass/color_names.hpp +324 -0
- data/ext/libsass/configure.ac +130 -0
- data/ext/libsass/constants.cpp +144 -0
- data/ext/libsass/constants.hpp +145 -0
- data/ext/libsass/context.cpp +507 -0
- data/ext/libsass/context.hpp +150 -0
- data/ext/libsass/contextualize.cpp +157 -0
- data/ext/libsass/contextualize.hpp +65 -0
- data/ext/libsass/copy_c_str.cpp +13 -0
- data/ext/libsass/copy_c_str.hpp +5 -0
- data/ext/libsass/debug.hpp +39 -0
- data/ext/libsass/environment.hpp +75 -0
- data/ext/libsass/error_handling.cpp +28 -0
- data/ext/libsass/error_handling.hpp +28 -0
- data/ext/libsass/eval.cpp +1149 -0
- data/ext/libsass/eval.hpp +80 -0
- data/ext/libsass/expand.cpp +430 -0
- data/ext/libsass/expand.hpp +77 -0
- data/ext/libsass/extconf.rb +6 -0
- data/ext/libsass/extend.cpp +1962 -0
- data/ext/libsass/extend.hpp +50 -0
- data/ext/libsass/file.cpp +291 -0
- data/ext/libsass/file.hpp +18 -0
- data/ext/libsass/functions.cpp +1565 -0
- data/ext/libsass/functions.hpp +187 -0
- data/ext/libsass/inspect.cpp +727 -0
- data/ext/libsass/inspect.hpp +108 -0
- data/ext/libsass/json.cpp +1411 -0
- data/ext/libsass/json.hpp +117 -0
- data/ext/libsass/kwd_arg_macros.hpp +23 -0
- data/ext/libsass/m4/.gitkeep +0 -0
- data/ext/libsass/mapping.hpp +17 -0
- data/ext/libsass/memory_manager.hpp +54 -0
- data/ext/libsass/node.cpp +251 -0
- data/ext/libsass/node.hpp +122 -0
- data/ext/libsass/operation.hpp +153 -0
- data/ext/libsass/output_compressed.cpp +401 -0
- data/ext/libsass/output_compressed.hpp +95 -0
- data/ext/libsass/output_nested.cpp +364 -0
- data/ext/libsass/output_nested.hpp +108 -0
- data/ext/libsass/parser.cpp +2016 -0
- data/ext/libsass/parser.hpp +264 -0
- data/ext/libsass/paths.hpp +69 -0
- data/ext/libsass/position.hpp +22 -0
- data/ext/libsass/posix/getopt.c +562 -0
- data/ext/libsass/posix/getopt.h +95 -0
- data/ext/libsass/prelexer.cpp +688 -0
- data/ext/libsass/prelexer.hpp +513 -0
- data/ext/libsass/remove_placeholders.cpp +59 -0
- data/ext/libsass/remove_placeholders.hpp +43 -0
- data/ext/libsass/res/resource.rc +35 -0
- data/ext/libsass/sass.cpp +33 -0
- data/ext/libsass/sass.h +60 -0
- data/ext/libsass/sass2scss.cpp +834 -0
- data/ext/libsass/sass2scss.h +110 -0
- data/ext/libsass/sass_context.cpp +709 -0
- data/ext/libsass/sass_context.h +120 -0
- data/ext/libsass/sass_functions.cpp +137 -0
- data/ext/libsass/sass_functions.h +90 -0
- data/ext/libsass/sass_interface.cpp +277 -0
- data/ext/libsass/sass_interface.h +97 -0
- data/ext/libsass/sass_util.cpp +136 -0
- data/ext/libsass/sass_util.hpp +259 -0
- data/ext/libsass/sass_values.cpp +337 -0
- data/ext/libsass/sass_values.h +124 -0
- data/ext/libsass/script/bootstrap +10 -0
- data/ext/libsass/script/branding +10 -0
- data/ext/libsass/script/ci-build-libsass +72 -0
- data/ext/libsass/script/ci-install-compiler +4 -0
- data/ext/libsass/script/ci-install-deps +19 -0
- data/ext/libsass/script/ci-report-coverage +25 -0
- data/ext/libsass/script/coveralls-debug +32 -0
- data/ext/libsass/script/spec +5 -0
- data/ext/libsass/script/tap-driver +652 -0
- data/ext/libsass/script/tap-runner +1 -0
- data/ext/libsass/source_map.cpp +133 -0
- data/ext/libsass/source_map.hpp +46 -0
- data/ext/libsass/subset_map.hpp +145 -0
- data/ext/libsass/support/libsass.pc.in +11 -0
- data/ext/libsass/test-driver +127 -0
- data/ext/libsass/test/test_node.cpp +98 -0
- data/ext/libsass/test/test_paths.cpp +29 -0
- data/ext/libsass/test/test_selector_difference.cpp +28 -0
- data/ext/libsass/test/test_specificity.cpp +28 -0
- data/ext/libsass/test/test_subset_map.cpp +472 -0
- data/ext/libsass/test/test_superselector.cpp +71 -0
- data/ext/libsass/test/test_unification.cpp +33 -0
- data/ext/libsass/to_c.cpp +61 -0
- data/ext/libsass/to_c.hpp +44 -0
- data/ext/libsass/to_string.cpp +29 -0
- data/ext/libsass/to_string.hpp +32 -0
- data/ext/libsass/token.hpp +32 -0
- data/ext/libsass/units.cpp +54 -0
- data/ext/libsass/units.hpp +10 -0
- data/ext/libsass/utf8.h +34 -0
- data/ext/libsass/utf8/checked.h +327 -0
- data/ext/libsass/utf8/core.h +329 -0
- data/ext/libsass/utf8/unchecked.h +228 -0
- data/ext/libsass/utf8_string.cpp +102 -0
- data/ext/libsass/utf8_string.hpp +36 -0
- data/ext/libsass/util.cpp +189 -0
- data/ext/libsass/util.hpp +26 -0
- data/ext/libsass/win/libsass.filters +291 -0
- data/ext/libsass/win/libsass.sln +28 -0
- data/ext/libsass/win/libsass.vcxproj +255 -0
- data/lib/sassc.rb +6 -0
- data/lib/sassc/engine.rb +13 -0
- data/lib/sassc/native.rb +44 -0
- data/lib/sassc/native/native_context_api.rb +140 -0
- data/lib/sassc/native/native_functions_api.rb +41 -0
- data/lib/sassc/native/sass_input_style.rb +11 -0
- data/lib/sassc/native/sass_output_style.rb +10 -0
- data/lib/sassc/native/sass_value.rb +95 -0
- data/lib/sassc/native/string_list.rb +8 -0
- data/lib/sassc/version.rb +3 -0
- data/sassc.gemspec +43 -0
- data/test/smoke_test.rb +171 -0
- data/test/test_helper.rb +4 -0
- metadata +281 -0
@@ -0,0 +1,80 @@
|
|
1
|
+
#define SASS_EVAL
|
2
|
+
|
3
|
+
#include <iostream>
|
4
|
+
|
5
|
+
#ifndef SASS_OPERATION
|
6
|
+
#include "operation.hpp"
|
7
|
+
#endif
|
8
|
+
|
9
|
+
#ifndef SASS_ENVIRONMENT
|
10
|
+
#include "environment.hpp"
|
11
|
+
#endif
|
12
|
+
|
13
|
+
#ifndef SASS_POSITION
|
14
|
+
#include "position.hpp"
|
15
|
+
#endif
|
16
|
+
|
17
|
+
#include "sass_values.h"
|
18
|
+
|
19
|
+
namespace Sass {
|
20
|
+
using namespace std;
|
21
|
+
|
22
|
+
struct Context;
|
23
|
+
typedef Environment<AST_Node*> Env;
|
24
|
+
struct Backtrace;
|
25
|
+
|
26
|
+
class Eval : public Operation_CRTP<Expression*, Eval> {
|
27
|
+
|
28
|
+
Context& ctx;
|
29
|
+
|
30
|
+
Expression* fallback_impl(AST_Node* n);
|
31
|
+
|
32
|
+
public:
|
33
|
+
Env* env;
|
34
|
+
Backtrace* backtrace;
|
35
|
+
Eval(Context&, Env*, Backtrace*);
|
36
|
+
virtual ~Eval();
|
37
|
+
Eval* with(Env* e, Backtrace* bt); // for setting the env before eval'ing an expression
|
38
|
+
using Operation<Expression*>::operator();
|
39
|
+
|
40
|
+
// for evaluating function bodies
|
41
|
+
Expression* operator()(Block*);
|
42
|
+
Expression* operator()(Assignment*);
|
43
|
+
Expression* operator()(If*);
|
44
|
+
Expression* operator()(For*);
|
45
|
+
Expression* operator()(Each*);
|
46
|
+
Expression* operator()(While*);
|
47
|
+
Expression* operator()(Return*);
|
48
|
+
Expression* operator()(Warning*);
|
49
|
+
Expression* operator()(Error*);
|
50
|
+
Expression* operator()(Debug*);
|
51
|
+
|
52
|
+
Expression* operator()(List*);
|
53
|
+
Expression* operator()(Map*);
|
54
|
+
Expression* operator()(Binary_Expression*);
|
55
|
+
Expression* operator()(Unary_Expression*);
|
56
|
+
Expression* operator()(Function_Call*);
|
57
|
+
Expression* operator()(Function_Call_Schema*);
|
58
|
+
Expression* operator()(Variable*);
|
59
|
+
Expression* operator()(Textual*);
|
60
|
+
Expression* operator()(Number*);
|
61
|
+
Expression* operator()(Boolean*);
|
62
|
+
Expression* operator()(String_Schema*);
|
63
|
+
Expression* operator()(String_Constant*);
|
64
|
+
Expression* operator()(Media_Query*);
|
65
|
+
Expression* operator()(Media_Query_Expression*);
|
66
|
+
Expression* operator()(Feature_Query*);
|
67
|
+
Expression* operator()(Feature_Query_Condition*);
|
68
|
+
Expression* operator()(Null*);
|
69
|
+
Expression* operator()(Argument*);
|
70
|
+
Expression* operator()(Arguments*);
|
71
|
+
|
72
|
+
template <typename U>
|
73
|
+
Expression* fallback(U x) { return fallback_impl(x); }
|
74
|
+
};
|
75
|
+
|
76
|
+
Expression* cval_to_astnode(Sass_Value* v, Context& ctx, Backtrace* backtrace, string path = "", Position position = Position());
|
77
|
+
|
78
|
+
bool eq(Expression*, Expression*, Context&);
|
79
|
+
bool lt(Expression*, Expression*, Context&);
|
80
|
+
}
|
@@ -0,0 +1,430 @@
|
|
1
|
+
#include "expand.hpp"
|
2
|
+
#include "bind.hpp"
|
3
|
+
#include "eval.hpp"
|
4
|
+
#include "contextualize.hpp"
|
5
|
+
#include "to_string.hpp"
|
6
|
+
#include "backtrace.hpp"
|
7
|
+
|
8
|
+
#include <iostream>
|
9
|
+
#include <typeinfo>
|
10
|
+
|
11
|
+
#ifndef SASS_CONTEXT
|
12
|
+
#include "context.hpp"
|
13
|
+
#endif
|
14
|
+
|
15
|
+
#include "parser.hpp"
|
16
|
+
|
17
|
+
namespace Sass {
|
18
|
+
|
19
|
+
Expand::Expand(Context& ctx, Eval* eval, Contextualize* contextualize, Env* env, Backtrace* bt)
|
20
|
+
: ctx(ctx),
|
21
|
+
eval(eval),
|
22
|
+
contextualize(contextualize),
|
23
|
+
env(env),
|
24
|
+
block_stack(vector<Block*>()),
|
25
|
+
property_stack(vector<String*>()),
|
26
|
+
selector_stack(vector<Selector*>()),
|
27
|
+
backtrace(bt)
|
28
|
+
{ selector_stack.push_back(0); }
|
29
|
+
|
30
|
+
Statement* Expand::operator()(Block* b)
|
31
|
+
{
|
32
|
+
Env new_env;
|
33
|
+
new_env.link(*env);
|
34
|
+
env = &new_env;
|
35
|
+
Block* bb = new (ctx.mem) Block(b->path(), b->position(), b->length(), b->is_root());
|
36
|
+
block_stack.push_back(bb);
|
37
|
+
append_block(b);
|
38
|
+
block_stack.pop_back();
|
39
|
+
env = env->parent();
|
40
|
+
return bb;
|
41
|
+
}
|
42
|
+
|
43
|
+
Statement* Expand::operator()(Ruleset* r)
|
44
|
+
{
|
45
|
+
To_String to_string;
|
46
|
+
// if (selector_stack.back()) cerr << "expanding " << selector_stack.back()->perform(&to_string) << " and " << r->selector()->perform(&to_string) << endl;
|
47
|
+
Selector* sel_ctx = r->selector()->perform(contextualize->with(selector_stack.back(), env, backtrace));
|
48
|
+
// re-parse in order to restructure parent nodes correctly
|
49
|
+
sel_ctx = Parser::from_c_str((sel_ctx->perform(&to_string) + ";").c_str(), ctx, r->selector()->path(), r->selector()->position()).parse_selector_group();
|
50
|
+
selector_stack.push_back(sel_ctx);
|
51
|
+
Ruleset* rr = new (ctx.mem) Ruleset(r->path(),
|
52
|
+
r->position(),
|
53
|
+
sel_ctx,
|
54
|
+
r->block()->perform(this)->block());
|
55
|
+
selector_stack.pop_back();
|
56
|
+
return rr;
|
57
|
+
}
|
58
|
+
|
59
|
+
Statement* Expand::operator()(Propset* p)
|
60
|
+
{
|
61
|
+
property_stack.push_back(p->property_fragment());
|
62
|
+
Block* expanded_block = p->block()->perform(this)->block();
|
63
|
+
|
64
|
+
Block* current_block = block_stack.back();
|
65
|
+
for (size_t i = 0, L = expanded_block->length(); i < L; ++i) {
|
66
|
+
Statement* stm = (*expanded_block)[i];
|
67
|
+
if (typeid(*stm) == typeid(Declaration)) {
|
68
|
+
Declaration* dec = static_cast<Declaration*>(stm);
|
69
|
+
String_Schema* combined_prop = new (ctx.mem) String_Schema(p->path(), p->position());
|
70
|
+
if (!property_stack.empty()) {
|
71
|
+
*combined_prop << property_stack.back()
|
72
|
+
<< new (ctx.mem) String_Constant(p->path(), p->position(), "-")
|
73
|
+
<< dec->property(); // TODO: eval the prop into a string constant
|
74
|
+
}
|
75
|
+
else {
|
76
|
+
*combined_prop << dec->property();
|
77
|
+
}
|
78
|
+
dec->property(combined_prop);
|
79
|
+
*current_block << dec;
|
80
|
+
}
|
81
|
+
else {
|
82
|
+
error("contents of namespaced properties must result in style declarations only", stm->path(), stm->position(), backtrace);
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
property_stack.pop_back();
|
87
|
+
|
88
|
+
return 0;
|
89
|
+
}
|
90
|
+
|
91
|
+
Statement* Expand::operator()(Feature_Block* f)
|
92
|
+
{
|
93
|
+
Expression* feature_queries = f->feature_queries()->perform(eval->with(env, backtrace));
|
94
|
+
Feature_Block* ff = new (ctx.mem) Feature_Block(f->path(),
|
95
|
+
f->position(),
|
96
|
+
static_cast<Feature_Query*>(feature_queries),
|
97
|
+
f->block()->perform(this)->block());
|
98
|
+
ff->selector(selector_stack.back());
|
99
|
+
return ff;
|
100
|
+
}
|
101
|
+
|
102
|
+
Statement* Expand::operator()(Media_Block* m)
|
103
|
+
{
|
104
|
+
Expression* media_queries = m->media_queries()->perform(eval->with(env, backtrace));
|
105
|
+
Media_Block* mm = new (ctx.mem) Media_Block(m->path(),
|
106
|
+
m->position(),
|
107
|
+
static_cast<List*>(media_queries),
|
108
|
+
m->block()->perform(this)->block());
|
109
|
+
mm->selector(selector_stack.back());
|
110
|
+
return mm;
|
111
|
+
}
|
112
|
+
|
113
|
+
Statement* Expand::operator()(At_Rule* a)
|
114
|
+
{
|
115
|
+
Block* ab = a->block();
|
116
|
+
selector_stack.push_back(0);
|
117
|
+
Selector* as = a->selector();
|
118
|
+
Expression* av = a->value();
|
119
|
+
if (as) as = as->perform(contextualize->with(0, env, backtrace));
|
120
|
+
else if (av) av = av->perform(eval->with(env, backtrace));
|
121
|
+
Block* bb = ab ? ab->perform(this)->block() : 0;
|
122
|
+
At_Rule* aa = new (ctx.mem) At_Rule(a->path(),
|
123
|
+
a->position(),
|
124
|
+
a->keyword(),
|
125
|
+
as,
|
126
|
+
bb);
|
127
|
+
if (av) aa->value(av);
|
128
|
+
selector_stack.pop_back();
|
129
|
+
return aa;
|
130
|
+
}
|
131
|
+
|
132
|
+
Statement* Expand::operator()(Declaration* d)
|
133
|
+
{
|
134
|
+
String* old_p = d->property();
|
135
|
+
String* new_p = static_cast<String*>(old_p->perform(eval->with(env, backtrace)));
|
136
|
+
Expression* value = d->value()->perform(eval->with(env, backtrace));
|
137
|
+
|
138
|
+
if (value->is_invisible() && !d->is_important()) return 0;
|
139
|
+
|
140
|
+
return new (ctx.mem) Declaration(d->path(),
|
141
|
+
d->position(),
|
142
|
+
new_p,
|
143
|
+
value,
|
144
|
+
d->is_important());
|
145
|
+
}
|
146
|
+
|
147
|
+
Statement* Expand::operator()(Assignment* a)
|
148
|
+
{
|
149
|
+
string var(a->variable());
|
150
|
+
if (env->has(var)) {
|
151
|
+
Expression* v = static_cast<Expression*>((*env)[var]);
|
152
|
+
if (!a->is_guarded() || v->concrete_type() == Expression::NULL_VAL) (*env)[var] = a->value()->perform(eval->with(env, backtrace));
|
153
|
+
}
|
154
|
+
else {
|
155
|
+
env->current_frame()[var] = a->value()->perform(eval->with(env, backtrace));
|
156
|
+
}
|
157
|
+
return 0;
|
158
|
+
}
|
159
|
+
|
160
|
+
Statement* Expand::operator()(Import* imp)
|
161
|
+
{
|
162
|
+
Import* result = new (ctx.mem) Import(imp->path(), imp->position());
|
163
|
+
for ( size_t i = 0, S = imp->urls().size(); i < S; ++i) {
|
164
|
+
result->urls().push_back(imp->urls()[i]->perform(eval->with(env, backtrace)));
|
165
|
+
}
|
166
|
+
return result;
|
167
|
+
}
|
168
|
+
|
169
|
+
Statement* Expand::operator()(Import_Stub* i)
|
170
|
+
{
|
171
|
+
append_block(ctx.style_sheets[i->file_name()]);
|
172
|
+
return 0;
|
173
|
+
}
|
174
|
+
|
175
|
+
Statement* Expand::operator()(Warning* w)
|
176
|
+
{
|
177
|
+
// eval handles this too, because warnings may occur in functions
|
178
|
+
w->perform(eval->with(env, backtrace));
|
179
|
+
return 0;
|
180
|
+
}
|
181
|
+
|
182
|
+
Statement* Expand::operator()(Error* e)
|
183
|
+
{
|
184
|
+
// eval handles this too, because errors may occur in functions
|
185
|
+
e->perform(eval->with(env, backtrace));
|
186
|
+
return 0;
|
187
|
+
}
|
188
|
+
|
189
|
+
Statement* Expand::operator()(Debug* d)
|
190
|
+
{
|
191
|
+
// eval handles this too, because warnings may occur in functions
|
192
|
+
d->perform(eval->with(env, backtrace));
|
193
|
+
return 0;
|
194
|
+
}
|
195
|
+
|
196
|
+
Statement* Expand::operator()(Comment* c)
|
197
|
+
{
|
198
|
+
// TODO: eval the text, once we're parsing/storing it as a String_Schema
|
199
|
+
return new (ctx.mem) Comment(c->path(), c->position(), static_cast<String*>(c->text()->perform(eval->with(env, backtrace))));
|
200
|
+
}
|
201
|
+
|
202
|
+
Statement* Expand::operator()(If* i)
|
203
|
+
{
|
204
|
+
if (*i->predicate()->perform(eval->with(env, backtrace))) {
|
205
|
+
append_block(i->consequent());
|
206
|
+
}
|
207
|
+
else {
|
208
|
+
Block* alt = i->alternative();
|
209
|
+
if (alt) append_block(alt);
|
210
|
+
}
|
211
|
+
return 0;
|
212
|
+
}
|
213
|
+
|
214
|
+
Statement* Expand::operator()(For* f)
|
215
|
+
{
|
216
|
+
string variable(f->variable());
|
217
|
+
Expression* low = f->lower_bound()->perform(eval->with(env, backtrace));
|
218
|
+
if (low->concrete_type() != Expression::NUMBER) {
|
219
|
+
error("lower bound of `@for` directive must be numeric", low->path(), low->position(), backtrace);
|
220
|
+
}
|
221
|
+
Expression* high = f->upper_bound()->perform(eval->with(env, backtrace));
|
222
|
+
if (high->concrete_type() != Expression::NUMBER) {
|
223
|
+
error("upper bound of `@for` directive must be numeric", high->path(), high->position(), backtrace);
|
224
|
+
}
|
225
|
+
double start = static_cast<Number*>(low)->value();
|
226
|
+
double end = static_cast<Number*>(high)->value();
|
227
|
+
Env new_env;
|
228
|
+
new_env[variable] = new (ctx.mem) Number(low->path(), low->position(), start);
|
229
|
+
new_env.link(env);
|
230
|
+
env = &new_env;
|
231
|
+
Block* body = f->block();
|
232
|
+
if (start < end) {
|
233
|
+
if (f->is_inclusive()) ++end;
|
234
|
+
for (double i = start;
|
235
|
+
i < end;
|
236
|
+
(*env)[variable] = new (ctx.mem) Number(low->path(), low->position(), ++i)) {
|
237
|
+
append_block(body);
|
238
|
+
}
|
239
|
+
} else {
|
240
|
+
if (f->is_inclusive()) --end;
|
241
|
+
for (double i = start;
|
242
|
+
i > end;
|
243
|
+
(*env)[variable] = new (ctx.mem) Number(low->path(), low->position(), --i)) {
|
244
|
+
append_block(body);
|
245
|
+
}
|
246
|
+
}
|
247
|
+
env = new_env.parent();
|
248
|
+
return 0;
|
249
|
+
}
|
250
|
+
|
251
|
+
Statement* Expand::operator()(Each* e)
|
252
|
+
{
|
253
|
+
vector<string> variables(e->variables());
|
254
|
+
Expression* expr = e->list()->perform(eval->with(env, backtrace));
|
255
|
+
List* list = 0;
|
256
|
+
Map* map = 0;
|
257
|
+
if (expr->concrete_type() == Expression::MAP) {
|
258
|
+
map = static_cast<Map*>(expr);
|
259
|
+
}
|
260
|
+
else if (expr->concrete_type() != Expression::LIST) {
|
261
|
+
list = new (ctx.mem) List(expr->path(), expr->position(), 1, List::COMMA);
|
262
|
+
*list << expr;
|
263
|
+
}
|
264
|
+
else {
|
265
|
+
list = static_cast<List*>(expr);
|
266
|
+
}
|
267
|
+
Env new_env;
|
268
|
+
for (size_t i = 0, L = variables.size(); i < L; ++i) new_env[variables[i]] = 0;
|
269
|
+
new_env.link(env);
|
270
|
+
env = &new_env;
|
271
|
+
Block* body = e->block();
|
272
|
+
|
273
|
+
if (map) {
|
274
|
+
for (auto key : map->keys()) {
|
275
|
+
Expression* k = key->perform(eval->with(env, backtrace));
|
276
|
+
Expression* v = map->at(key)->perform(eval->with(env, backtrace));
|
277
|
+
|
278
|
+
if (variables.size() == 1) {
|
279
|
+
List* variable = new (ctx.mem) List(map->path(), map->position(), 2, List::SPACE);
|
280
|
+
*variable << k;
|
281
|
+
*variable << v;
|
282
|
+
(*env)[variables[0]] = variable;
|
283
|
+
} else {
|
284
|
+
(*env)[variables[0]] = k;
|
285
|
+
(*env)[variables[1]] = v;
|
286
|
+
}
|
287
|
+
append_block(body);
|
288
|
+
}
|
289
|
+
}
|
290
|
+
else {
|
291
|
+
for (size_t i = 0, L = list->length(); i < L; ++i) {
|
292
|
+
List* variable = 0;
|
293
|
+
if ((*list)[i]->concrete_type() != Expression::LIST || variables.size() == 1) {
|
294
|
+
variable = new (ctx.mem) List((*list)[i]->path(), (*list)[i]->position(), 1, List::COMMA);
|
295
|
+
*variable << (*list)[i];
|
296
|
+
}
|
297
|
+
else {
|
298
|
+
variable = static_cast<List*>((*list)[i]);
|
299
|
+
}
|
300
|
+
for (size_t j = 0, K = variables.size(); j < K; ++j) {
|
301
|
+
if (j < variable->length()) {
|
302
|
+
(*env)[variables[j]] = (*variable)[j]->perform(eval->with(env, backtrace));
|
303
|
+
}
|
304
|
+
else {
|
305
|
+
(*env)[variables[j]] = new (ctx.mem) Null(expr->path(), expr->position());
|
306
|
+
}
|
307
|
+
}
|
308
|
+
append_block(body);
|
309
|
+
}
|
310
|
+
}
|
311
|
+
env = new_env.parent();
|
312
|
+
return 0;
|
313
|
+
}
|
314
|
+
|
315
|
+
Statement* Expand::operator()(While* w)
|
316
|
+
{
|
317
|
+
Expression* pred = w->predicate();
|
318
|
+
Block* body = w->block();
|
319
|
+
while (*pred->perform(eval->with(env, backtrace))) {
|
320
|
+
append_block(body);
|
321
|
+
}
|
322
|
+
return 0;
|
323
|
+
}
|
324
|
+
|
325
|
+
Statement* Expand::operator()(Return* r)
|
326
|
+
{
|
327
|
+
error("@return may only be used within a function", r->path(), r->position(), backtrace);
|
328
|
+
return 0;
|
329
|
+
}
|
330
|
+
|
331
|
+
Statement* Expand::operator()(Extension* e)
|
332
|
+
{
|
333
|
+
To_String to_string;
|
334
|
+
Selector_List* extender = static_cast<Selector_List*>(selector_stack.back());
|
335
|
+
if (!extender) return 0;
|
336
|
+
Selector_List* extendee = static_cast<Selector_List*>(e->selector()->perform(contextualize->with(0, env, backtrace)));
|
337
|
+
if (extendee->length() != 1) {
|
338
|
+
error("selector groups may not be extended", extendee->path(), extendee->position(), backtrace);
|
339
|
+
}
|
340
|
+
Complex_Selector* c = (*extendee)[0];
|
341
|
+
if (!c->head() || c->tail()) {
|
342
|
+
error("nested selectors may not be extended", c->path(), c->position(), backtrace);
|
343
|
+
}
|
344
|
+
Compound_Selector* s = c->head();
|
345
|
+
|
346
|
+
// // need to convert the compound selector into a by-value data structure
|
347
|
+
// vector<string> target_vec;
|
348
|
+
// for (size_t i = 0, L = s->length(); i < L; ++i)
|
349
|
+
// { target_vec.push_back((*s)[i]->perform(&to_string)); }
|
350
|
+
|
351
|
+
for (size_t i = 0, L = extender->length(); i < L; ++i) {
|
352
|
+
// let's test this out
|
353
|
+
// cerr << "REGISTERING EXTENSION REQUEST: " << (*extender)[i]->perform(&to_string) << " <- " << s->perform(&to_string) << endl;
|
354
|
+
ctx.subset_map.put(s->to_str_vec(), make_pair((*extender)[i], s));
|
355
|
+
}
|
356
|
+
return 0;
|
357
|
+
}
|
358
|
+
|
359
|
+
Statement* Expand::operator()(Definition* d)
|
360
|
+
{
|
361
|
+
Definition* dd = new (ctx.mem) Definition(*d);
|
362
|
+
env->current_frame()[d->name() +
|
363
|
+
(d->type() == Definition::MIXIN ? "[m]" : "[f]")] = dd;
|
364
|
+
// set the static link so we can have lexical scoping
|
365
|
+
dd->environment(env);
|
366
|
+
return 0;
|
367
|
+
}
|
368
|
+
|
369
|
+
Statement* Expand::operator()(Mixin_Call* c)
|
370
|
+
{
|
371
|
+
string full_name(c->name() + "[m]");
|
372
|
+
if (!env->has(full_name)) {
|
373
|
+
error("no mixin named " + c->name(), c->path(), c->position(), backtrace);
|
374
|
+
}
|
375
|
+
Definition* def = static_cast<Definition*>((*env)[full_name]);
|
376
|
+
Block* body = def->block();
|
377
|
+
Parameters* params = def->parameters();
|
378
|
+
Arguments* args = static_cast<Arguments*>(c->arguments()
|
379
|
+
->perform(eval->with(env, backtrace)));
|
380
|
+
Backtrace here(backtrace, c->path(), c->position(), ", in mixin `" + c->name() + "`");
|
381
|
+
backtrace = &here;
|
382
|
+
Env new_env;
|
383
|
+
new_env.link(def->environment());
|
384
|
+
if (c->block()) {
|
385
|
+
// represent mixin content blocks as thunks/closures
|
386
|
+
Definition* thunk = new (ctx.mem) Definition(c->path(),
|
387
|
+
c->position(),
|
388
|
+
"@content",
|
389
|
+
new (ctx.mem) Parameters(c->path(), c->position()),
|
390
|
+
c->block(),
|
391
|
+
Definition::MIXIN);
|
392
|
+
thunk->environment(env);
|
393
|
+
new_env.current_frame()["@content[m]"] = thunk;
|
394
|
+
}
|
395
|
+
bind("mixin " + c->name(), params, args, ctx, &new_env, eval);
|
396
|
+
Env* old_env = env;
|
397
|
+
env = &new_env;
|
398
|
+
append_block(body);
|
399
|
+
env = old_env;
|
400
|
+
backtrace = here.parent;
|
401
|
+
return 0;
|
402
|
+
}
|
403
|
+
|
404
|
+
Statement* Expand::operator()(Content* c)
|
405
|
+
{
|
406
|
+
// convert @content directives into mixin calls to the underlying thunk
|
407
|
+
if (!env->has("@content[m]")) return 0;
|
408
|
+
Mixin_Call* call = new (ctx.mem) Mixin_Call(c->path(),
|
409
|
+
c->position(),
|
410
|
+
"@content",
|
411
|
+
new (ctx.mem) Arguments(c->path(), c->position()));
|
412
|
+
return call->perform(this);
|
413
|
+
}
|
414
|
+
|
415
|
+
inline Statement* Expand::fallback_impl(AST_Node* n)
|
416
|
+
{
|
417
|
+
error("unknown internal error; please contact the LibSass maintainers", n->path(), n->position(), backtrace);
|
418
|
+
String_Constant* msg = new (ctx.mem) String_Constant("", Position(), string("`Expand` doesn't handle ") + typeid(*n).name());
|
419
|
+
return new (ctx.mem) Warning("", Position(), msg);
|
420
|
+
}
|
421
|
+
|
422
|
+
inline void Expand::append_block(Block* b)
|
423
|
+
{
|
424
|
+
Block* current_block = block_stack.back();
|
425
|
+
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
426
|
+
Statement* ith = (*b)[i]->perform(this);
|
427
|
+
if (ith) *current_block << ith;
|
428
|
+
}
|
429
|
+
}
|
430
|
+
}
|