sassc 0.0.1
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 +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,28 @@
|
|
|
1
|
+
#ifndef SASS_ERROR_HANDLING
|
|
2
|
+
#include "error_handling.hpp"
|
|
3
|
+
#endif
|
|
4
|
+
|
|
5
|
+
#include "backtrace.hpp"
|
|
6
|
+
#include "prelexer.hpp"
|
|
7
|
+
|
|
8
|
+
namespace Sass {
|
|
9
|
+
|
|
10
|
+
Sass_Error::Sass_Error(Type type, string path, Position position, string message)
|
|
11
|
+
: type(type), path(path), position(position), message(message)
|
|
12
|
+
{ }
|
|
13
|
+
|
|
14
|
+
void error(string msg, string path, Position position)
|
|
15
|
+
{ throw Sass_Error(Sass_Error::syntax, path, position, msg); }
|
|
16
|
+
|
|
17
|
+
void error(string msg, string path, Position position, Backtrace* bt)
|
|
18
|
+
{
|
|
19
|
+
if (!path.empty() && Prelexer::string_constant(path.c_str()))
|
|
20
|
+
path = path.substr(1, path.size() - 1);
|
|
21
|
+
|
|
22
|
+
Backtrace top(bt, path, position, "");
|
|
23
|
+
msg += top.to_string();
|
|
24
|
+
|
|
25
|
+
throw Sass_Error(Sass_Error::syntax, path, position, msg);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#define SASS_ERROR_HANDLING
|
|
2
|
+
#include <string>
|
|
3
|
+
|
|
4
|
+
#ifndef SASS_POSITION
|
|
5
|
+
#include "position.hpp"
|
|
6
|
+
#endif
|
|
7
|
+
|
|
8
|
+
namespace Sass {
|
|
9
|
+
using namespace std;
|
|
10
|
+
|
|
11
|
+
struct Backtrace;
|
|
12
|
+
|
|
13
|
+
struct Sass_Error {
|
|
14
|
+
enum Type { read, write, syntax, evaluation };
|
|
15
|
+
|
|
16
|
+
Type type;
|
|
17
|
+
string path;
|
|
18
|
+
Position position;
|
|
19
|
+
string message;
|
|
20
|
+
|
|
21
|
+
Sass_Error(Type type, string path, Position position, string message);
|
|
22
|
+
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
void error(string msg, string path, Position position);
|
|
26
|
+
void error(string msg, string path, Position position, Backtrace* bt);
|
|
27
|
+
|
|
28
|
+
}
|
|
@@ -0,0 +1,1149 @@
|
|
|
1
|
+
#include "file.hpp"
|
|
2
|
+
#include "eval.hpp"
|
|
3
|
+
#include "ast.hpp"
|
|
4
|
+
#include "bind.hpp"
|
|
5
|
+
#include "util.hpp"
|
|
6
|
+
#include "to_string.hpp"
|
|
7
|
+
#include "inspect.hpp"
|
|
8
|
+
#include "to_c.hpp"
|
|
9
|
+
#include "context.hpp"
|
|
10
|
+
#include "backtrace.hpp"
|
|
11
|
+
#include "prelexer.hpp"
|
|
12
|
+
|
|
13
|
+
#include <cstdlib>
|
|
14
|
+
#include <cmath>
|
|
15
|
+
#include <iostream>
|
|
16
|
+
#include <iomanip>
|
|
17
|
+
#include <typeinfo>
|
|
18
|
+
|
|
19
|
+
namespace Sass {
|
|
20
|
+
using namespace std;
|
|
21
|
+
|
|
22
|
+
inline double add(double x, double y) { return x + y; }
|
|
23
|
+
inline double sub(double x, double y) { return x - y; }
|
|
24
|
+
inline double mul(double x, double y) { return x * y; }
|
|
25
|
+
inline double div(double x, double y) { return x / y; } // x/0 checked by caller
|
|
26
|
+
typedef double (*bop)(double, double);
|
|
27
|
+
bop ops[Binary_Expression::NUM_OPS] = {
|
|
28
|
+
0, 0, // and, or
|
|
29
|
+
0, 0, 0, 0, 0, 0, // eq, neq, gt, gte, lt, lte
|
|
30
|
+
add, sub, mul, div, fmod
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
Eval::Eval(Context& ctx, Env* env, Backtrace* bt)
|
|
34
|
+
: ctx(ctx), env(env), backtrace(bt) { }
|
|
35
|
+
Eval::~Eval() { }
|
|
36
|
+
|
|
37
|
+
Eval* Eval::with(Env* e, Backtrace* bt) // for setting the env before eval'ing an expression
|
|
38
|
+
{
|
|
39
|
+
env = e;
|
|
40
|
+
backtrace = bt;
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
Expression* Eval::operator()(Block* b)
|
|
45
|
+
{
|
|
46
|
+
Expression* val = 0;
|
|
47
|
+
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
48
|
+
val = (*b)[i]->perform(this);
|
|
49
|
+
if (val) return val;
|
|
50
|
+
}
|
|
51
|
+
return val;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
Expression* Eval::operator()(Assignment* a)
|
|
55
|
+
{
|
|
56
|
+
string var(a->variable());
|
|
57
|
+
if (env->has(var)) {
|
|
58
|
+
Expression* v = static_cast<Expression*>((*env)[var]);
|
|
59
|
+
if (!a->is_guarded() || v->concrete_type() == Expression::NULL_VAL) (*env)[var] = a->value()->perform(this);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
env->current_frame()[var] = a->value()->perform(this);
|
|
63
|
+
}
|
|
64
|
+
return 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
Expression* Eval::operator()(If* i)
|
|
68
|
+
{
|
|
69
|
+
if (*i->predicate()->perform(this)) {
|
|
70
|
+
return i->consequent()->perform(this);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
Block* alt = i->alternative();
|
|
74
|
+
if (alt) return alt->perform(this);
|
|
75
|
+
}
|
|
76
|
+
return 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
Expression* Eval::operator()(For* f)
|
|
80
|
+
{
|
|
81
|
+
string variable(f->variable());
|
|
82
|
+
Expression* low = f->lower_bound()->perform(this);
|
|
83
|
+
if (low->concrete_type() != Expression::NUMBER) {
|
|
84
|
+
error("lower bound of `@for` directive must be numeric", low->path(), low->position());
|
|
85
|
+
}
|
|
86
|
+
Expression* high = f->upper_bound()->perform(this);
|
|
87
|
+
if (high->concrete_type() != Expression::NUMBER) {
|
|
88
|
+
error("upper bound of `@for` directive must be numeric", high->path(), high->position());
|
|
89
|
+
}
|
|
90
|
+
double start = static_cast<Number*>(low)->value();
|
|
91
|
+
double end = static_cast<Number*>(high)->value();
|
|
92
|
+
Env new_env;
|
|
93
|
+
new_env[variable] = new (ctx.mem) Number(low->path(), low->position(), start);
|
|
94
|
+
new_env.link(env);
|
|
95
|
+
env = &new_env;
|
|
96
|
+
Block* body = f->block();
|
|
97
|
+
Expression* val = 0;
|
|
98
|
+
if (start < end) {
|
|
99
|
+
if (f->is_inclusive()) ++end;
|
|
100
|
+
for (double i = start;
|
|
101
|
+
i < end;
|
|
102
|
+
(*env)[variable] = new (ctx.mem) Number(low->path(), low->position(), ++i)) {
|
|
103
|
+
val = body->perform(this);
|
|
104
|
+
if (val) break;
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
if (f->is_inclusive()) --end;
|
|
108
|
+
for (double i = start;
|
|
109
|
+
i > end;
|
|
110
|
+
(*env)[variable] = new (ctx.mem) Number(low->path(), low->position(), --i)) {
|
|
111
|
+
val = body->perform(this);
|
|
112
|
+
if (val) break;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
env = new_env.parent();
|
|
116
|
+
return val;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
Expression* Eval::operator()(Each* e)
|
|
120
|
+
{
|
|
121
|
+
vector<string> variables(e->variables());
|
|
122
|
+
Expression* expr = e->list()->perform(this);
|
|
123
|
+
List* list = 0;
|
|
124
|
+
Map* map = 0;
|
|
125
|
+
if (expr->concrete_type() == Expression::MAP) {
|
|
126
|
+
map = static_cast<Map*>(expr);
|
|
127
|
+
}
|
|
128
|
+
else if (expr->concrete_type() != Expression::LIST) {
|
|
129
|
+
list = new (ctx.mem) List(expr->path(), expr->position(), 1, List::COMMA);
|
|
130
|
+
*list << expr;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
list = static_cast<List*>(expr);
|
|
134
|
+
}
|
|
135
|
+
Env new_env;
|
|
136
|
+
for (size_t i = 0, L = variables.size(); i < L; ++i) new_env[variables[i]] = 0;
|
|
137
|
+
new_env.link(env);
|
|
138
|
+
env = &new_env;
|
|
139
|
+
Block* body = e->block();
|
|
140
|
+
Expression* val = 0;
|
|
141
|
+
|
|
142
|
+
if (map) {
|
|
143
|
+
for (auto key : map->keys()) {
|
|
144
|
+
Expression* value = map->at(key);
|
|
145
|
+
|
|
146
|
+
if (variables.size() == 1) {
|
|
147
|
+
List* variable = new (ctx.mem) List(map->path(), map->position(), 2, List::SPACE);
|
|
148
|
+
*variable << key;
|
|
149
|
+
*variable << value;
|
|
150
|
+
(*env)[variables[0]] = variable;
|
|
151
|
+
} else {
|
|
152
|
+
(*env)[variables[0]] = key;
|
|
153
|
+
(*env)[variables[1]] = value;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
val = body->perform(this);
|
|
157
|
+
if (val) break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
for (size_t i = 0, L = list->length(); i < L; ++i) {
|
|
162
|
+
List* variable = 0;
|
|
163
|
+
if ((*list)[i]->concrete_type() != Expression::LIST || variables.size() == 1) {
|
|
164
|
+
variable = new (ctx.mem) List((*list)[i]->path(), (*list)[i]->position(), 1, List::COMMA);
|
|
165
|
+
*variable << (*list)[i];
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
variable = static_cast<List*>((*list)[i]);
|
|
169
|
+
}
|
|
170
|
+
for (size_t j = 0, K = variables.size(); j < K; ++j) {
|
|
171
|
+
if (j < variable->length()) {
|
|
172
|
+
(*env)[variables[j]] = (*variable)[j];
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
(*env)[variables[j]] = new (ctx.mem) Null(expr->path(), expr->position());
|
|
176
|
+
}
|
|
177
|
+
val = body->perform(this);
|
|
178
|
+
if (val) break;
|
|
179
|
+
}
|
|
180
|
+
if (val) break;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
env = new_env.parent();
|
|
184
|
+
return val;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
Expression* Eval::operator()(While* w)
|
|
188
|
+
{
|
|
189
|
+
Expression* pred = w->predicate();
|
|
190
|
+
Block* body = w->block();
|
|
191
|
+
while (*pred->perform(this)) {
|
|
192
|
+
Expression* val = body->perform(this);
|
|
193
|
+
if (val) return val;
|
|
194
|
+
}
|
|
195
|
+
return 0;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
Expression* Eval::operator()(Return* r)
|
|
199
|
+
{
|
|
200
|
+
return r->value()->perform(this);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
Expression* Eval::operator()(Warning* w)
|
|
204
|
+
{
|
|
205
|
+
Expression* message = w->message()->perform(this);
|
|
206
|
+
To_String to_string;
|
|
207
|
+
|
|
208
|
+
// try to use generic function
|
|
209
|
+
if (env->has("@warn[f]")) {
|
|
210
|
+
|
|
211
|
+
Definition* def = static_cast<Definition*>((*env)["@warn[f]"]);
|
|
212
|
+
// Block* body = def->block();
|
|
213
|
+
// Native_Function func = def->native_function();
|
|
214
|
+
Sass_C_Function c_func = def->c_function();
|
|
215
|
+
|
|
216
|
+
To_C to_c;
|
|
217
|
+
union Sass_Value* c_args = sass_make_list(1, SASS_COMMA);
|
|
218
|
+
sass_list_set_value(c_args, 0, message->perform(&to_c));
|
|
219
|
+
Sass_Value* c_val = c_func(c_args, def->cookie());
|
|
220
|
+
sass_delete_value(c_args);
|
|
221
|
+
sass_delete_value(c_val);
|
|
222
|
+
return 0;
|
|
223
|
+
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
string result(unquote(message->perform(&to_string)));
|
|
227
|
+
Backtrace top(backtrace, w->path(), w->position(), "");
|
|
228
|
+
cerr << "WARNING: " << result;
|
|
229
|
+
cerr << top.to_string(true);
|
|
230
|
+
cerr << endl << endl;
|
|
231
|
+
return 0;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
Expression* Eval::operator()(Error* e)
|
|
235
|
+
{
|
|
236
|
+
Expression* message = e->message()->perform(this);
|
|
237
|
+
To_String to_string;
|
|
238
|
+
|
|
239
|
+
// try to use generic function
|
|
240
|
+
if (env->has("@error[f]")) {
|
|
241
|
+
|
|
242
|
+
Definition* def = static_cast<Definition*>((*env)["@error[f]"]);
|
|
243
|
+
// Block* body = def->block();
|
|
244
|
+
// Native_Function func = def->native_function();
|
|
245
|
+
Sass_C_Function c_func = def->c_function();
|
|
246
|
+
|
|
247
|
+
To_C to_c;
|
|
248
|
+
union Sass_Value* c_args = sass_make_list(1, SASS_COMMA);
|
|
249
|
+
sass_list_set_value(c_args, 0, message->perform(&to_c));
|
|
250
|
+
Sass_Value* c_val = c_func(c_args, def->cookie());
|
|
251
|
+
sass_delete_value(c_args);
|
|
252
|
+
sass_delete_value(c_val);
|
|
253
|
+
return 0;
|
|
254
|
+
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
string result(unquote(message->perform(&to_string)));
|
|
258
|
+
Backtrace top(backtrace, e->path(), e->position(), "");
|
|
259
|
+
cerr << "Error: " << result;
|
|
260
|
+
cerr << top.to_string(true);
|
|
261
|
+
cerr << endl << endl;
|
|
262
|
+
return 0;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
Expression* Eval::operator()(Debug* d)
|
|
266
|
+
{
|
|
267
|
+
Expression* message = d->value()->perform(this);
|
|
268
|
+
To_String to_string;
|
|
269
|
+
|
|
270
|
+
// try to use generic function
|
|
271
|
+
if (env->has("@debug[f]")) {
|
|
272
|
+
|
|
273
|
+
Definition* def = static_cast<Definition*>((*env)["@debug[f]"]);
|
|
274
|
+
// Block* body = def->block();
|
|
275
|
+
// Native_Function func = def->native_function();
|
|
276
|
+
Sass_C_Function c_func = def->c_function();
|
|
277
|
+
|
|
278
|
+
To_C to_c;
|
|
279
|
+
union Sass_Value* c_args = sass_make_list(1, SASS_COMMA);
|
|
280
|
+
sass_list_set_value(c_args, 0, message->perform(&to_c));
|
|
281
|
+
Sass_Value* c_val = c_func(c_args, def->cookie());
|
|
282
|
+
sass_delete_value(c_args);
|
|
283
|
+
sass_delete_value(c_val);
|
|
284
|
+
return 0;
|
|
285
|
+
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
string cwd(ctx.get_cwd());
|
|
289
|
+
string result(unquote(message->perform(&to_string)));
|
|
290
|
+
string rel_path(Sass::File::resolve_relative_path(d->path(), cwd, cwd));
|
|
291
|
+
cerr << rel_path << ":" << d->position().line << ":" << " DEBUG: " << result;
|
|
292
|
+
cerr << endl;
|
|
293
|
+
return 0;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
Expression* Eval::operator()(List* l)
|
|
297
|
+
{
|
|
298
|
+
if (l->is_expanded()) return l;
|
|
299
|
+
List* ll = new (ctx.mem) List(l->path(),
|
|
300
|
+
l->position(),
|
|
301
|
+
l->length(),
|
|
302
|
+
l->separator(),
|
|
303
|
+
l->is_arglist());
|
|
304
|
+
for (size_t i = 0, L = l->length(); i < L; ++i) {
|
|
305
|
+
*ll << (*l)[i]->perform(this);
|
|
306
|
+
}
|
|
307
|
+
ll->is_expanded(true);
|
|
308
|
+
return ll;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
Expression* Eval::operator()(Map* m)
|
|
312
|
+
{
|
|
313
|
+
if (m->is_expanded()) return m;
|
|
314
|
+
Map* mm = new (ctx.mem) Map(m->path(),
|
|
315
|
+
m->position(),
|
|
316
|
+
m->length());
|
|
317
|
+
for (auto key : m->keys()) {
|
|
318
|
+
*mm << std::make_pair(key->perform(this), m->at(key)->perform(this));
|
|
319
|
+
}
|
|
320
|
+
mm->is_expanded(true);
|
|
321
|
+
return mm;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// -- only need to define two comparisons, and the rest can be implemented in terms of them
|
|
325
|
+
bool eq(Expression*, Expression*, Context&, Eval*);
|
|
326
|
+
bool lt(Expression*, Expression*, Context&);
|
|
327
|
+
// -- arithmetic on the combinations that matter
|
|
328
|
+
Expression* op_numbers(Context&, Binary_Expression*, Expression*, Expression*);
|
|
329
|
+
Expression* op_number_color(Context&, Binary_Expression::Type, Expression*, Expression*);
|
|
330
|
+
Expression* op_color_number(Context&, Binary_Expression::Type, Expression*, Expression*);
|
|
331
|
+
Expression* op_colors(Context&, Binary_Expression::Type, Expression*, Expression*);
|
|
332
|
+
Expression* op_strings(Context&, Binary_Expression::Type, Expression*, Expression*);
|
|
333
|
+
|
|
334
|
+
Expression* Eval::operator()(Binary_Expression* b)
|
|
335
|
+
{
|
|
336
|
+
Binary_Expression::Type op_type = b->type();
|
|
337
|
+
// don't eval delayed expressions (the '/' when used as a separator)
|
|
338
|
+
if (op_type == Binary_Expression::DIV && b->is_delayed()) return b;
|
|
339
|
+
// if one of the operands is a '/' then make sure it's evaluated
|
|
340
|
+
if (typeid(*b->left()) == typeid(Binary_Expression)) b->left()->is_delayed(false);
|
|
341
|
+
// the logical connectives need to short-circuit
|
|
342
|
+
Expression* lhs = b->left()->perform(this);
|
|
343
|
+
switch (op_type) {
|
|
344
|
+
case Binary_Expression::AND:
|
|
345
|
+
return *lhs ? b->right()->perform(this) : lhs;
|
|
346
|
+
break;
|
|
347
|
+
|
|
348
|
+
case Binary_Expression::OR:
|
|
349
|
+
return *lhs ? lhs : b->right()->perform(this);
|
|
350
|
+
break;
|
|
351
|
+
|
|
352
|
+
default:
|
|
353
|
+
break;
|
|
354
|
+
}
|
|
355
|
+
// not a logical connective, so go ahead and eval the rhs
|
|
356
|
+
Expression* rhs = b->right()->perform(this);
|
|
357
|
+
|
|
358
|
+
// see if it's a relational expression
|
|
359
|
+
switch(op_type) {
|
|
360
|
+
case Binary_Expression::EQ: return new (ctx.mem) Boolean(b->path(), b->position(), eq(lhs, rhs, ctx));
|
|
361
|
+
case Binary_Expression::NEQ: return new (ctx.mem) Boolean(b->path(), b->position(), !eq(lhs, rhs, ctx));
|
|
362
|
+
case Binary_Expression::GT: return new (ctx.mem) Boolean(b->path(), b->position(), !lt(lhs, rhs, ctx) && !eq(lhs, rhs, ctx));
|
|
363
|
+
case Binary_Expression::GTE: return new (ctx.mem) Boolean(b->path(), b->position(), !lt(lhs, rhs, ctx));
|
|
364
|
+
case Binary_Expression::LT: return new (ctx.mem) Boolean(b->path(), b->position(), lt(lhs, rhs, ctx));
|
|
365
|
+
case Binary_Expression::LTE: return new (ctx.mem) Boolean(b->path(), b->position(), lt(lhs, rhs, ctx) || eq(lhs, rhs, ctx));
|
|
366
|
+
|
|
367
|
+
default: break;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
Expression::Concrete_Type l_type = lhs->concrete_type();
|
|
371
|
+
Expression::Concrete_Type r_type = rhs->concrete_type();
|
|
372
|
+
|
|
373
|
+
if (l_type == Expression::NUMBER && r_type == Expression::NUMBER) {
|
|
374
|
+
return op_numbers(ctx, b, lhs, rhs);
|
|
375
|
+
}
|
|
376
|
+
if (l_type == Expression::NUMBER && r_type == Expression::COLOR) {
|
|
377
|
+
return op_number_color(ctx, op_type, lhs, rhs);
|
|
378
|
+
}
|
|
379
|
+
if (l_type == Expression::COLOR && r_type == Expression::NUMBER) {
|
|
380
|
+
return op_color_number(ctx, op_type, lhs, rhs);
|
|
381
|
+
}
|
|
382
|
+
if (l_type == Expression::COLOR && r_type == Expression::COLOR) {
|
|
383
|
+
return op_colors(ctx, op_type, lhs, rhs);
|
|
384
|
+
}
|
|
385
|
+
return op_strings(ctx, op_type, lhs, rhs);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
Expression* Eval::operator()(Unary_Expression* u)
|
|
389
|
+
{
|
|
390
|
+
Expression* operand = u->operand()->perform(this);
|
|
391
|
+
if (u->type() == Unary_Expression::NOT) {
|
|
392
|
+
Boolean* result = new (ctx.mem) Boolean(u->path(), u->position(), (bool)*operand);
|
|
393
|
+
result->value(!result->value());
|
|
394
|
+
return result;
|
|
395
|
+
}
|
|
396
|
+
else if (operand->concrete_type() == Expression::NUMBER) {
|
|
397
|
+
Number* result = new (ctx.mem) Number(*static_cast<Number*>(operand));
|
|
398
|
+
result->value(u->type() == Unary_Expression::MINUS
|
|
399
|
+
? -result->value()
|
|
400
|
+
: result->value());
|
|
401
|
+
return result;
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
To_String to_string;
|
|
405
|
+
// Special cases: +/- variables which evaluate to null ouput just +/-,
|
|
406
|
+
// but +/- null itself outputs the string
|
|
407
|
+
if (operand->concrete_type() == Expression::NULL_VAL && typeid(*(u->operand())) == typeid(Variable)) {
|
|
408
|
+
u->operand(new (ctx.mem) String_Constant(u->path(), u->position(), ""));
|
|
409
|
+
}
|
|
410
|
+
else u->operand(operand);
|
|
411
|
+
String_Constant* result = new (ctx.mem) String_Constant(u->path(),
|
|
412
|
+
u->position(),
|
|
413
|
+
u->perform(&to_string));
|
|
414
|
+
return result;
|
|
415
|
+
}
|
|
416
|
+
// unreachable
|
|
417
|
+
return u;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
Expression* Eval::operator()(Function_Call* c)
|
|
421
|
+
{
|
|
422
|
+
string full_name(c->name() + "[f]");
|
|
423
|
+
Arguments* args = c->arguments();
|
|
424
|
+
if (full_name != "if[f]") {
|
|
425
|
+
args = static_cast<Arguments*>(args->perform(this));
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// try to use generic function
|
|
429
|
+
if (!env->has(full_name)) {
|
|
430
|
+
if (env->has("*[f]")) {
|
|
431
|
+
full_name = "*[f]";
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// if it doesn't exist, just pass it through as a literal
|
|
436
|
+
if (!env->has(full_name)) {
|
|
437
|
+
Function_Call* lit = new (ctx.mem) Function_Call(c->path(),
|
|
438
|
+
c->position(),
|
|
439
|
+
c->name(),
|
|
440
|
+
args);
|
|
441
|
+
To_String to_string;
|
|
442
|
+
return new (ctx.mem) String_Constant(c->path(),
|
|
443
|
+
c->position(),
|
|
444
|
+
lit->perform(&to_string));
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
Expression* result = c;
|
|
448
|
+
Definition* def = static_cast<Definition*>((*env)[full_name]);
|
|
449
|
+
Block* body = def->block();
|
|
450
|
+
Native_Function func = def->native_function();
|
|
451
|
+
Sass_C_Function c_func = def->c_function();
|
|
452
|
+
|
|
453
|
+
if (full_name != "if[f]") {
|
|
454
|
+
for (size_t i = 0, L = args->length(); i < L; ++i) {
|
|
455
|
+
(*args)[i]->value((*args)[i]->value()->perform(this));
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
Parameters* params = def->parameters();
|
|
460
|
+
Env new_env;
|
|
461
|
+
new_env.link(def->environment());
|
|
462
|
+
// bind("function " + c->name(), params, args, ctx, &new_env, this);
|
|
463
|
+
// Env* old_env = env;
|
|
464
|
+
// env = &new_env;
|
|
465
|
+
|
|
466
|
+
// Backtrace here(backtrace, c->path(), c->line(), ", in function `" + c->name() + "`");
|
|
467
|
+
// backtrace = &here;
|
|
468
|
+
|
|
469
|
+
// if it's user-defined, eval the body
|
|
470
|
+
if (body) {
|
|
471
|
+
|
|
472
|
+
bind("function " + c->name(), params, args, ctx, &new_env, this);
|
|
473
|
+
Env* old_env = env;
|
|
474
|
+
env = &new_env;
|
|
475
|
+
|
|
476
|
+
Backtrace here(backtrace, c->path(), c->position(), ", in function `" + c->name() + "`");
|
|
477
|
+
backtrace = &here;
|
|
478
|
+
|
|
479
|
+
result = body->perform(this);
|
|
480
|
+
if (!result) {
|
|
481
|
+
error(string("function ") + c->name() + " did not return a value", c->path(), c->position());
|
|
482
|
+
}
|
|
483
|
+
backtrace = here.parent;
|
|
484
|
+
env = old_env;
|
|
485
|
+
}
|
|
486
|
+
// if it's native, invoke the underlying CPP function
|
|
487
|
+
else if (func) {
|
|
488
|
+
|
|
489
|
+
bind("function " + c->name(), params, args, ctx, &new_env, this);
|
|
490
|
+
Env* old_env = env;
|
|
491
|
+
env = &new_env;
|
|
492
|
+
|
|
493
|
+
Backtrace here(backtrace, c->path(), c->position(), ", in function `" + c->name() + "`");
|
|
494
|
+
backtrace = &here;
|
|
495
|
+
|
|
496
|
+
result = func(*env, *old_env, ctx, def->signature(), c->path(), c->position(), backtrace);
|
|
497
|
+
|
|
498
|
+
backtrace = here.parent;
|
|
499
|
+
env = old_env;
|
|
500
|
+
}
|
|
501
|
+
// else if it's a user-defined c function
|
|
502
|
+
else if (c_func) {
|
|
503
|
+
|
|
504
|
+
if (full_name == "*[f]") {
|
|
505
|
+
String_Constant *str = new (ctx.mem) String_Constant(c->path(), c->position(), c->name());
|
|
506
|
+
Arguments* new_args = new (ctx.mem) Arguments(c->path(), c->position());
|
|
507
|
+
*new_args << new (ctx.mem) Argument(c->path(), c->position(), str);
|
|
508
|
+
*new_args += args;
|
|
509
|
+
args = new_args;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// populates env with default values for params
|
|
513
|
+
bind("function " + c->name(), params, args, ctx, &new_env, this);
|
|
514
|
+
Env* old_env = env;
|
|
515
|
+
env = &new_env;
|
|
516
|
+
|
|
517
|
+
Backtrace here(backtrace, c->path(), c->position(), ", in function `" + c->name() + "`");
|
|
518
|
+
backtrace = &here;
|
|
519
|
+
|
|
520
|
+
To_C to_c;
|
|
521
|
+
union Sass_Value* c_args = sass_make_list(env->current_frame().size(), SASS_COMMA);
|
|
522
|
+
for(size_t i = 0; i < params[0].length(); i++) {
|
|
523
|
+
string key = params[0][i]->name();
|
|
524
|
+
AST_Node* node = env->current_frame().at(key);
|
|
525
|
+
Expression* arg = static_cast<Expression*>(node);
|
|
526
|
+
sass_list_set_value(c_args, i, arg->perform(&to_c));
|
|
527
|
+
}
|
|
528
|
+
Sass_Value* c_val = c_func(c_args, def->cookie());
|
|
529
|
+
if (sass_value_get_tag(c_val) == SASS_ERROR) {
|
|
530
|
+
error("error in C function " + c->name() + ": " + sass_error_get_message(c_val), c->path(), c->position(), backtrace);
|
|
531
|
+
} else if (sass_value_get_tag(c_val) == SASS_WARNING) {
|
|
532
|
+
error("warning in C function " + c->name() + ": " + sass_warning_get_message(c_val), c->path(), c->position(), backtrace);
|
|
533
|
+
}
|
|
534
|
+
result = cval_to_astnode(c_val, ctx, backtrace, c->path(), c->position());
|
|
535
|
+
|
|
536
|
+
backtrace = here.parent;
|
|
537
|
+
sass_delete_value(c_args);
|
|
538
|
+
if (c_val != c_args)
|
|
539
|
+
sass_delete_value(c_val);
|
|
540
|
+
env = old_env;
|
|
541
|
+
}
|
|
542
|
+
// else it's an overloaded native function; resolve it
|
|
543
|
+
else if (def->is_overload_stub()) {
|
|
544
|
+
size_t arity = args->length();
|
|
545
|
+
stringstream ss;
|
|
546
|
+
ss << full_name << arity;
|
|
547
|
+
string resolved_name(ss.str());
|
|
548
|
+
if (!env->has(resolved_name)) error("overloaded function `" + string(c->name()) + "` given wrong number of arguments", c->path(), c->position());
|
|
549
|
+
Definition* resolved_def = static_cast<Definition*>((*env)[resolved_name]);
|
|
550
|
+
params = resolved_def->parameters();
|
|
551
|
+
Env newer_env;
|
|
552
|
+
newer_env.link(resolved_def->environment());
|
|
553
|
+
bind("function " + c->name(), params, args, ctx, &newer_env, this);
|
|
554
|
+
Env* old_env = env;
|
|
555
|
+
env = &newer_env;
|
|
556
|
+
|
|
557
|
+
Backtrace here(backtrace, c->path(), c->position(), ", in function `" + c->name() + "`");
|
|
558
|
+
backtrace = &here;
|
|
559
|
+
|
|
560
|
+
result = resolved_def->native_function()(*env, *old_env, ctx, resolved_def->signature(), c->path(), c->position(), backtrace);
|
|
561
|
+
|
|
562
|
+
backtrace = here.parent;
|
|
563
|
+
env = old_env;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// backtrace = here.parent;
|
|
567
|
+
// env = old_env;
|
|
568
|
+
result->position(c->position());
|
|
569
|
+
return result;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
Expression* Eval::operator()(Function_Call_Schema* s)
|
|
573
|
+
{
|
|
574
|
+
Expression* evaluated_name = s->name()->perform(this);
|
|
575
|
+
Expression* evaluated_args = s->arguments()->perform(this);
|
|
576
|
+
String_Schema* ss = new (ctx.mem) String_Schema(s->path(), s->position(), 2);
|
|
577
|
+
(*ss) << evaluated_name << evaluated_args;
|
|
578
|
+
return ss->perform(this);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
Expression* Eval::operator()(Variable* v)
|
|
582
|
+
{
|
|
583
|
+
To_String to_string;
|
|
584
|
+
string name(v->name());
|
|
585
|
+
Expression* value = 0;
|
|
586
|
+
if (env->has(name)) value = static_cast<Expression*>((*env)[name]);
|
|
587
|
+
else error("unbound variable " + v->name(), v->path(), v->position());
|
|
588
|
+
// cerr << "name: " << v->name() << "; type: " << typeid(*value).name() << "; value: " << value->perform(&to_string) << endl;
|
|
589
|
+
if (typeid(*value) == typeid(Argument)) value = static_cast<Argument*>(value)->value();
|
|
590
|
+
|
|
591
|
+
// behave according to as ruby sass (add leading zero)
|
|
592
|
+
if (value->concrete_type() == Expression::NUMBER) {
|
|
593
|
+
Number* n = static_cast<Number*>(value);
|
|
594
|
+
value = new (ctx.mem) Number(n->path(),
|
|
595
|
+
n->position(),
|
|
596
|
+
n->value(),
|
|
597
|
+
n->unit(),
|
|
598
|
+
true);
|
|
599
|
+
}
|
|
600
|
+
else if (value->concrete_type() == Expression::STRING) {
|
|
601
|
+
String_Constant* s = static_cast<String_Constant*>(value);
|
|
602
|
+
value = new (ctx.mem) String_Constant(s->path(),
|
|
603
|
+
s->position(),
|
|
604
|
+
s->value());
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// cerr << "\ttype is now: " << typeid(*value).name() << endl << endl;
|
|
608
|
+
return value;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
Expression* Eval::operator()(Textual* t)
|
|
612
|
+
{
|
|
613
|
+
using Prelexer::number;
|
|
614
|
+
Expression* result = 0;
|
|
615
|
+
bool zero = !( t->value().substr(0, 1) == "." ||
|
|
616
|
+
t->value().substr(0, 2) == "-." );
|
|
617
|
+
|
|
618
|
+
const string& text = t->value();
|
|
619
|
+
size_t num_pos = text.find_first_not_of(" \n\r\t");
|
|
620
|
+
if (num_pos == string::npos) num_pos = text.length();
|
|
621
|
+
size_t unit_pos = text.find_first_not_of("-+0123456789.", num_pos);
|
|
622
|
+
if (unit_pos == string::npos) unit_pos = text.length();
|
|
623
|
+
const string& num = text.substr(num_pos, unit_pos - num_pos);
|
|
624
|
+
|
|
625
|
+
switch (t->type())
|
|
626
|
+
{
|
|
627
|
+
case Textual::NUMBER:
|
|
628
|
+
result = new (ctx.mem) Number(t->path(),
|
|
629
|
+
t->position(),
|
|
630
|
+
atof(num.c_str()),
|
|
631
|
+
"",
|
|
632
|
+
zero);
|
|
633
|
+
break;
|
|
634
|
+
case Textual::PERCENTAGE:
|
|
635
|
+
result = new (ctx.mem) Number(t->path(),
|
|
636
|
+
t->position(),
|
|
637
|
+
atof(num.c_str()),
|
|
638
|
+
"%",
|
|
639
|
+
zero);
|
|
640
|
+
break;
|
|
641
|
+
case Textual::DIMENSION:
|
|
642
|
+
result = new (ctx.mem) Number(t->path(),
|
|
643
|
+
t->position(),
|
|
644
|
+
atof(num.c_str()),
|
|
645
|
+
Token(number(text.c_str())),
|
|
646
|
+
zero);
|
|
647
|
+
break;
|
|
648
|
+
case Textual::HEX: {
|
|
649
|
+
string hext(t->value().substr(1)); // chop off the '#'
|
|
650
|
+
if (hext.length() == 6) {
|
|
651
|
+
string r(hext.substr(0,2));
|
|
652
|
+
string g(hext.substr(2,2));
|
|
653
|
+
string b(hext.substr(4,2));
|
|
654
|
+
result = new (ctx.mem) Color(t->path(),
|
|
655
|
+
t->position(),
|
|
656
|
+
static_cast<double>(strtol(r.c_str(), NULL, 16)),
|
|
657
|
+
static_cast<double>(strtol(g.c_str(), NULL, 16)),
|
|
658
|
+
static_cast<double>(strtol(b.c_str(), NULL, 16)),
|
|
659
|
+
1, true,
|
|
660
|
+
t->value());
|
|
661
|
+
}
|
|
662
|
+
else {
|
|
663
|
+
result = new (ctx.mem) Color(t->path(),
|
|
664
|
+
t->position(),
|
|
665
|
+
static_cast<double>(strtol(string(2,hext[0]).c_str(), NULL, 16)),
|
|
666
|
+
static_cast<double>(strtol(string(2,hext[1]).c_str(), NULL, 16)),
|
|
667
|
+
static_cast<double>(strtol(string(2,hext[2]).c_str(), NULL, 16)),
|
|
668
|
+
1, false,
|
|
669
|
+
t->value());
|
|
670
|
+
}
|
|
671
|
+
} break;
|
|
672
|
+
}
|
|
673
|
+
return result;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
Expression* Eval::operator()(Number* n)
|
|
677
|
+
{
|
|
678
|
+
// behave according to as ruby sass (add leading zero)
|
|
679
|
+
return new (ctx.mem) Number(n->path(),
|
|
680
|
+
n->position(),
|
|
681
|
+
n->value(),
|
|
682
|
+
n->unit(),
|
|
683
|
+
true);
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
Expression* Eval::operator()(Boolean* b)
|
|
687
|
+
{
|
|
688
|
+
return b;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
char is_quoted(string str)
|
|
692
|
+
{
|
|
693
|
+
size_t len = str.length();
|
|
694
|
+
if (len < 2) return 0;
|
|
695
|
+
if ((str[0] == '"' && str[len-1] == '"') || (str[0] == '\'' && str[len-1] == '\'')) {
|
|
696
|
+
return str[0];
|
|
697
|
+
}
|
|
698
|
+
else {
|
|
699
|
+
return 0;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
Expression* Eval::operator()(String_Schema* s)
|
|
704
|
+
{
|
|
705
|
+
string acc;
|
|
706
|
+
ctx._skip_source_map_update = true;
|
|
707
|
+
To_String to_string(&ctx);
|
|
708
|
+
ctx._skip_source_map_update = false;
|
|
709
|
+
for (size_t i = 0, L = s->length(); i < L; ++i) {
|
|
710
|
+
string chunk((*s)[i]->perform(this)->perform(&to_string));
|
|
711
|
+
if (((s->quote_mark() && is_quoted(chunk)) || !s->quote_mark()) && (*s)[i]->is_interpolant()) { // some redundancy in that test
|
|
712
|
+
acc += unquote(chunk);
|
|
713
|
+
}
|
|
714
|
+
else {
|
|
715
|
+
acc += chunk;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
return new (ctx.mem) String_Constant(s->path(),
|
|
719
|
+
s->position(),
|
|
720
|
+
acc);
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
Expression* Eval::operator()(String_Constant* s)
|
|
724
|
+
{
|
|
725
|
+
if (!s->is_delayed() && ctx.names_to_colors.count(s->value())) {
|
|
726
|
+
Color* c = new (ctx.mem) Color(*ctx.names_to_colors[s->value()]);
|
|
727
|
+
c->path(s->path());
|
|
728
|
+
c->position(s->position());
|
|
729
|
+
c->disp(s->value());
|
|
730
|
+
return c;
|
|
731
|
+
}
|
|
732
|
+
return s;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
Expression* Eval::operator()(Feature_Query* q)
|
|
736
|
+
{
|
|
737
|
+
Feature_Query* qq = new (ctx.mem) Feature_Query(q->path(),
|
|
738
|
+
q->position(),
|
|
739
|
+
q->length());
|
|
740
|
+
for (size_t i = 0, L = q->length(); i < L; ++i) {
|
|
741
|
+
*qq << static_cast<Feature_Query_Condition*>((*q)[i]->perform(this));
|
|
742
|
+
}
|
|
743
|
+
return qq;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
Expression* Eval::operator()(Feature_Query_Condition* c)
|
|
747
|
+
{
|
|
748
|
+
String* feature = c->feature();
|
|
749
|
+
Expression* value = c->value();
|
|
750
|
+
value = (value ? value->perform(this) : 0);
|
|
751
|
+
Feature_Query_Condition* cc = new (ctx.mem) Feature_Query_Condition(c->path(),
|
|
752
|
+
c->position(),
|
|
753
|
+
c->length(),
|
|
754
|
+
feature,
|
|
755
|
+
value,
|
|
756
|
+
c->operand(),
|
|
757
|
+
c->is_root());
|
|
758
|
+
for (size_t i = 0, L = c->length(); i < L; ++i) {
|
|
759
|
+
*cc << static_cast<Feature_Query_Condition*>((*c)[i]->perform(this));
|
|
760
|
+
}
|
|
761
|
+
return cc;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
Expression* Eval::operator()(Media_Query* q)
|
|
765
|
+
{
|
|
766
|
+
String* t = q->media_type();
|
|
767
|
+
t = static_cast<String*>(t ? t->perform(this) : 0);
|
|
768
|
+
Media_Query* qq = new (ctx.mem) Media_Query(q->path(),
|
|
769
|
+
q->position(),
|
|
770
|
+
t,
|
|
771
|
+
q->length(),
|
|
772
|
+
q->is_negated(),
|
|
773
|
+
q->is_restricted());
|
|
774
|
+
for (size_t i = 0, L = q->length(); i < L; ++i) {
|
|
775
|
+
*qq << static_cast<Media_Query_Expression*>((*q)[i]->perform(this));
|
|
776
|
+
}
|
|
777
|
+
return qq;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
Expression* Eval::operator()(Media_Query_Expression* e)
|
|
781
|
+
{
|
|
782
|
+
Expression* feature = e->feature();
|
|
783
|
+
feature = (feature ? feature->perform(this) : 0);
|
|
784
|
+
Expression* value = e->value();
|
|
785
|
+
value = (value ? value->perform(this) : 0);
|
|
786
|
+
return new (ctx.mem) Media_Query_Expression(e->path(),
|
|
787
|
+
e->position(),
|
|
788
|
+
feature,
|
|
789
|
+
value,
|
|
790
|
+
e->is_interpolated());
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
Expression* Eval::operator()(Null* n)
|
|
794
|
+
{
|
|
795
|
+
return n;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
Expression* Eval::operator()(Argument* a)
|
|
799
|
+
{
|
|
800
|
+
Expression* val = a->value();
|
|
801
|
+
val->is_delayed(false);
|
|
802
|
+
val = val->perform(this);
|
|
803
|
+
val->is_delayed(false);
|
|
804
|
+
|
|
805
|
+
bool is_rest_argument = a->is_rest_argument();
|
|
806
|
+
bool is_keyword_argument = a->is_keyword_argument();
|
|
807
|
+
|
|
808
|
+
if (a->is_rest_argument()) {
|
|
809
|
+
if (val->concrete_type() == Expression::MAP) {
|
|
810
|
+
is_rest_argument = false;
|
|
811
|
+
is_keyword_argument = true;
|
|
812
|
+
}
|
|
813
|
+
else
|
|
814
|
+
if(val->concrete_type() != Expression::LIST) {
|
|
815
|
+
List* wrapper = new (ctx.mem) List(val->path(),
|
|
816
|
+
val->position(),
|
|
817
|
+
0,
|
|
818
|
+
List::COMMA,
|
|
819
|
+
true);
|
|
820
|
+
*wrapper << val;
|
|
821
|
+
val = wrapper;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
return new (ctx.mem) Argument(a->path(),
|
|
825
|
+
a->position(),
|
|
826
|
+
val,
|
|
827
|
+
a->name(),
|
|
828
|
+
is_rest_argument,
|
|
829
|
+
is_keyword_argument);
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
Expression* Eval::operator()(Arguments* a)
|
|
833
|
+
{
|
|
834
|
+
Arguments* aa = new (ctx.mem) Arguments(a->path(), a->position());
|
|
835
|
+
for (size_t i = 0, L = a->length(); i < L; ++i) {
|
|
836
|
+
*aa << static_cast<Argument*>((*a)[i]->perform(this));
|
|
837
|
+
}
|
|
838
|
+
return aa;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
inline Expression* Eval::fallback_impl(AST_Node* n)
|
|
842
|
+
{
|
|
843
|
+
return static_cast<Expression*>(n);
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
// All the binary helpers.
|
|
847
|
+
|
|
848
|
+
bool eq(Expression* lhs, Expression* rhs, Context& ctx)
|
|
849
|
+
{
|
|
850
|
+
Expression::Concrete_Type ltype = lhs->concrete_type();
|
|
851
|
+
Expression::Concrete_Type rtype = rhs->concrete_type();
|
|
852
|
+
if (ltype != rtype) return false;
|
|
853
|
+
switch (ltype) {
|
|
854
|
+
|
|
855
|
+
case Expression::BOOLEAN: {
|
|
856
|
+
return static_cast<Boolean*>(lhs)->value() ==
|
|
857
|
+
static_cast<Boolean*>(rhs)->value();
|
|
858
|
+
} break;
|
|
859
|
+
|
|
860
|
+
case Expression::NUMBER: {
|
|
861
|
+
Number* l = static_cast<Number*>(lhs);
|
|
862
|
+
Number* r = static_cast<Number*>(rhs);
|
|
863
|
+
Number tmp_r(*r);
|
|
864
|
+
tmp_r.normalize(l->find_convertible_unit());
|
|
865
|
+
return l->unit() == tmp_r.unit() && l->value() == tmp_r.value()
|
|
866
|
+
? true
|
|
867
|
+
: false;
|
|
868
|
+
} break;
|
|
869
|
+
|
|
870
|
+
case Expression::COLOR: {
|
|
871
|
+
Color* l = static_cast<Color*>(lhs);
|
|
872
|
+
Color* r = static_cast<Color*>(rhs);
|
|
873
|
+
return l->r() == r->r() &&
|
|
874
|
+
l->g() == r->g() &&
|
|
875
|
+
l->b() == r->b() &&
|
|
876
|
+
l->a() == r->a();
|
|
877
|
+
} break;
|
|
878
|
+
|
|
879
|
+
case Expression::STRING: {
|
|
880
|
+
return unquote(static_cast<String_Constant*>(lhs)->value()) ==
|
|
881
|
+
unquote(static_cast<String_Constant*>(rhs)->value());
|
|
882
|
+
} break;
|
|
883
|
+
|
|
884
|
+
case Expression::LIST: {
|
|
885
|
+
List* l = static_cast<List*>(lhs);
|
|
886
|
+
List* r = static_cast<List*>(rhs);
|
|
887
|
+
if (l->length() != r->length()) return false;
|
|
888
|
+
if (l->separator() != r->separator()) return false;
|
|
889
|
+
for (size_t i = 0, L = l->length(); i < L; ++i) {
|
|
890
|
+
if (!eq((*l)[i], (*r)[i], ctx)) return false;
|
|
891
|
+
}
|
|
892
|
+
return true;
|
|
893
|
+
} break;
|
|
894
|
+
|
|
895
|
+
case Expression::MAP: {
|
|
896
|
+
Map* l = static_cast<Map*>(lhs);
|
|
897
|
+
Map* r = static_cast<Map*>(rhs);
|
|
898
|
+
if (l->length() != r->length()) return false;
|
|
899
|
+
for (auto key : l->keys())
|
|
900
|
+
if (!eq(l->at(key), r->at(key), ctx)) return false;
|
|
901
|
+
return true;
|
|
902
|
+
} break;
|
|
903
|
+
case Expression::NULL_VAL: {
|
|
904
|
+
return true;
|
|
905
|
+
} break;
|
|
906
|
+
|
|
907
|
+
default: break;
|
|
908
|
+
}
|
|
909
|
+
return false;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
bool lt(Expression* lhs, Expression* rhs, Context& ctx)
|
|
913
|
+
{
|
|
914
|
+
if (lhs->concrete_type() != Expression::NUMBER ||
|
|
915
|
+
rhs->concrete_type() != Expression::NUMBER)
|
|
916
|
+
error("may only compare numbers", lhs->path(), lhs->position());
|
|
917
|
+
Number* l = static_cast<Number*>(lhs);
|
|
918
|
+
Number* r = static_cast<Number*>(rhs);
|
|
919
|
+
Number tmp_r(*r);
|
|
920
|
+
tmp_r.normalize(l->find_convertible_unit());
|
|
921
|
+
string l_unit(l->unit());
|
|
922
|
+
string r_unit(tmp_r.unit());
|
|
923
|
+
if (!l_unit.empty() && !r_unit.empty() && l->unit() != tmp_r.unit()) {
|
|
924
|
+
error("cannot compare numbers with incompatible units", l->path(), l->position());
|
|
925
|
+
}
|
|
926
|
+
return l->value() < tmp_r.value();
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
Expression* op_numbers(Context& ctx, Binary_Expression* b, Expression* lhs, Expression* rhs)
|
|
930
|
+
{
|
|
931
|
+
Number* l = static_cast<Number*>(lhs);
|
|
932
|
+
Number* r = static_cast<Number*>(rhs);
|
|
933
|
+
double lv = l->value();
|
|
934
|
+
double rv = r->value();
|
|
935
|
+
Binary_Expression::Type op = b->type();
|
|
936
|
+
if (op == Binary_Expression::DIV && !rv) {
|
|
937
|
+
return new (ctx.mem) String_Constant(l->path(), b->position(), "Infinity");
|
|
938
|
+
}
|
|
939
|
+
if (op == Binary_Expression::MOD && !rv) {
|
|
940
|
+
error("division by zero", r->path(), r->position());
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
Number tmp(*r);
|
|
944
|
+
tmp.normalize(l->find_convertible_unit());
|
|
945
|
+
string l_unit(l->unit());
|
|
946
|
+
string r_unit(tmp.unit());
|
|
947
|
+
if (l_unit != r_unit && !l_unit.empty() && !r_unit.empty() &&
|
|
948
|
+
(op == Binary_Expression::ADD || op == Binary_Expression::SUB)) {
|
|
949
|
+
error("cannot add or subtract numbers with incompatible units", l->path(), l->position());
|
|
950
|
+
}
|
|
951
|
+
Number* v = new (ctx.mem) Number(*l);
|
|
952
|
+
v->position(b->position());
|
|
953
|
+
if (l_unit.empty() && (op == Binary_Expression::ADD || op == Binary_Expression::SUB || op == Binary_Expression::MOD)) {
|
|
954
|
+
v->numerator_units() = r->numerator_units();
|
|
955
|
+
v->denominator_units() = r->denominator_units();
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
v->value(ops[op](lv, tmp.value()));
|
|
959
|
+
if (op == Binary_Expression::MUL) {
|
|
960
|
+
for (size_t i = 0, S = r->numerator_units().size(); i < S; ++i) {
|
|
961
|
+
v->numerator_units().push_back(r->numerator_units()[i]);
|
|
962
|
+
}
|
|
963
|
+
for (size_t i = 0, S = r->denominator_units().size(); i < S; ++i) {
|
|
964
|
+
v->denominator_units().push_back(r->denominator_units()[i]);
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
else if (op == Binary_Expression::DIV) {
|
|
968
|
+
for (size_t i = 0, S = r->numerator_units().size(); i < S; ++i) {
|
|
969
|
+
v->denominator_units().push_back(r->numerator_units()[i]);
|
|
970
|
+
}
|
|
971
|
+
for (size_t i = 0, S = r->denominator_units().size(); i < S; ++i) {
|
|
972
|
+
v->numerator_units().push_back(r->denominator_units()[i]);
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
v->normalize();
|
|
976
|
+
return v;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
Expression* op_number_color(Context& ctx, Binary_Expression::Type op, Expression* lhs, Expression* rhs)
|
|
980
|
+
{
|
|
981
|
+
Number* l = static_cast<Number*>(lhs);
|
|
982
|
+
Color* r = static_cast<Color*>(rhs);
|
|
983
|
+
// TODO: currently SASS converts colors to standard form when adding to strings;
|
|
984
|
+
// when https://github.com/nex3/sass/issues/363 is added this can be removed to
|
|
985
|
+
// preserve the original value
|
|
986
|
+
r->disp("");
|
|
987
|
+
double lv = l->value();
|
|
988
|
+
switch (op) {
|
|
989
|
+
case Binary_Expression::ADD:
|
|
990
|
+
case Binary_Expression::MUL: {
|
|
991
|
+
return new (ctx.mem) Color(l->path(),
|
|
992
|
+
l->position(),
|
|
993
|
+
ops[op](lv, r->r()),
|
|
994
|
+
ops[op](lv, r->g()),
|
|
995
|
+
ops[op](lv, r->b()),
|
|
996
|
+
r->a());
|
|
997
|
+
} break;
|
|
998
|
+
case Binary_Expression::SUB:
|
|
999
|
+
case Binary_Expression::DIV: {
|
|
1000
|
+
string sep(op == Binary_Expression::SUB ? "-" : "/");
|
|
1001
|
+
To_String to_string;
|
|
1002
|
+
string color(r->sixtuplet() ? r->perform(&to_string) :
|
|
1003
|
+
Util::normalize_sixtuplet(r->perform(&to_string)));
|
|
1004
|
+
return new (ctx.mem) String_Constant(l->path(),
|
|
1005
|
+
l->position(),
|
|
1006
|
+
l->perform(&to_string)
|
|
1007
|
+
+ sep
|
|
1008
|
+
+ color);
|
|
1009
|
+
} break;
|
|
1010
|
+
case Binary_Expression::MOD: {
|
|
1011
|
+
error("cannot divide a number by a color", r->path(), r->position());
|
|
1012
|
+
} break;
|
|
1013
|
+
default: break; // caller should ensure that we don't get here
|
|
1014
|
+
}
|
|
1015
|
+
// unreachable
|
|
1016
|
+
return l;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
Expression* op_color_number(Context& ctx, Binary_Expression::Type op, Expression* lhs, Expression* rhs)
|
|
1020
|
+
{
|
|
1021
|
+
Color* l = static_cast<Color*>(lhs);
|
|
1022
|
+
Number* r = static_cast<Number*>(rhs);
|
|
1023
|
+
double rv = r->value();
|
|
1024
|
+
if (op == Binary_Expression::DIV && !rv) error("division by zero", r->path(), r->position());
|
|
1025
|
+
return new (ctx.mem) Color(l->path(),
|
|
1026
|
+
l->position(),
|
|
1027
|
+
ops[op](l->r(), rv),
|
|
1028
|
+
ops[op](l->g(), rv),
|
|
1029
|
+
ops[op](l->b(), rv),
|
|
1030
|
+
l->a());
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
Expression* op_colors(Context& ctx, Binary_Expression::Type op, Expression* lhs, Expression* rhs)
|
|
1034
|
+
{
|
|
1035
|
+
Color* l = static_cast<Color*>(lhs);
|
|
1036
|
+
Color* r = static_cast<Color*>(rhs);
|
|
1037
|
+
if (l->a() != r->a()) {
|
|
1038
|
+
error("alpha channels must be equal when combining colors", r->path(), r->position());
|
|
1039
|
+
}
|
|
1040
|
+
if ((op == Binary_Expression::DIV || op == Binary_Expression::MOD) &&
|
|
1041
|
+
(!r->r() || !r->g() ||!r->b())) {
|
|
1042
|
+
error("division by zero", r->path(), r->position());
|
|
1043
|
+
}
|
|
1044
|
+
return new (ctx.mem) Color(l->path(),
|
|
1045
|
+
l->position(),
|
|
1046
|
+
ops[op](l->r(), r->r()),
|
|
1047
|
+
ops[op](l->g(), r->g()),
|
|
1048
|
+
ops[op](l->b(), r->b()),
|
|
1049
|
+
l->a());
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
Expression* op_strings(Context& ctx, Binary_Expression::Type op, Expression* lhs, Expression*rhs)
|
|
1053
|
+
{
|
|
1054
|
+
To_String to_string;
|
|
1055
|
+
Expression::Concrete_Type ltype = lhs->concrete_type();
|
|
1056
|
+
Expression::Concrete_Type rtype = rhs->concrete_type();
|
|
1057
|
+
|
|
1058
|
+
string lstr(lhs->perform(&to_string));
|
|
1059
|
+
string rstr(rhs->perform(&to_string));
|
|
1060
|
+
|
|
1061
|
+
bool l_str_quoted = ((Sass::String*)lhs) && ((Sass::String*)lhs)->needs_unquoting();
|
|
1062
|
+
bool r_str_quoted = ((Sass::String*)rhs) && ((Sass::String*)rhs)->needs_unquoting();
|
|
1063
|
+
bool l_str_color = ltype == Expression::STRING && ctx.names_to_colors.count(lstr) && !l_str_quoted;
|
|
1064
|
+
bool r_str_color = rtype == Expression::STRING && ctx.names_to_colors.count(rstr) && !r_str_quoted;
|
|
1065
|
+
|
|
1066
|
+
bool unquoted = false;
|
|
1067
|
+
if (ltype == Expression::STRING && lstr[0] != '"' && lstr[0] != '\'') unquoted = true;
|
|
1068
|
+
if (l_str_color && r_str_color) {
|
|
1069
|
+
return op_colors(ctx, op, ctx.names_to_colors[lstr], ctx.names_to_colors[rstr]);
|
|
1070
|
+
}
|
|
1071
|
+
else if (l_str_color && rtype == Expression::COLOR) {
|
|
1072
|
+
return op_colors(ctx, op, ctx.names_to_colors[lstr], rhs);
|
|
1073
|
+
}
|
|
1074
|
+
else if (l_str_color && rtype == Expression::NUMBER) {
|
|
1075
|
+
return op_color_number(ctx, op, ctx.names_to_colors[lstr], rhs);
|
|
1076
|
+
}
|
|
1077
|
+
else if (ltype == Expression::COLOR && r_str_color) {
|
|
1078
|
+
return op_number_color(ctx, op, lhs, ctx.names_to_colors[rstr]);
|
|
1079
|
+
}
|
|
1080
|
+
else if (ltype == Expression::NUMBER && r_str_color) {
|
|
1081
|
+
return op_number_color(ctx, op, lhs, ctx.names_to_colors[rstr]);
|
|
1082
|
+
}
|
|
1083
|
+
if (op == Binary_Expression::MUL) error("invalid operands for multiplication", lhs->path(), lhs->position());
|
|
1084
|
+
if (op == Binary_Expression::MOD) error("invalid operands for modulo", lhs->path(), lhs->position());
|
|
1085
|
+
string sep;
|
|
1086
|
+
switch (op) {
|
|
1087
|
+
case Binary_Expression::SUB: sep = "-"; break;
|
|
1088
|
+
case Binary_Expression::DIV: sep = "/"; break;
|
|
1089
|
+
default: break;
|
|
1090
|
+
}
|
|
1091
|
+
if (ltype == Expression::NULL_VAL) error("invalid null operation: \"null plus "+quote(unquote(rstr), '"')+"\".", lhs->path(), lhs->position());
|
|
1092
|
+
if (rtype == Expression::NULL_VAL) error("invalid null operation: \""+quote(unquote(lstr), '"')+" plus null\".", lhs->path(), lhs->position());
|
|
1093
|
+
char q = '\0';
|
|
1094
|
+
if (lstr[0] == '"' || lstr[0] == '\'') q = lstr[0];
|
|
1095
|
+
else if (rstr[0] == '"' || rstr[0] == '\'') q = rstr[0];
|
|
1096
|
+
string result(unquote(lstr) + sep + unquote(rstr));
|
|
1097
|
+
return new (ctx.mem) String_Constant(lhs->path(),
|
|
1098
|
+
lhs->position(),
|
|
1099
|
+
unquoted ? result : quote(result, q));
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
Expression* cval_to_astnode(Sass_Value* v, Context& ctx, Backtrace* backtrace, string path, Position position)
|
|
1103
|
+
{
|
|
1104
|
+
using std::strlen;
|
|
1105
|
+
using std::strcpy;
|
|
1106
|
+
Expression* e = 0;
|
|
1107
|
+
switch (sass_value_get_tag(v)) {
|
|
1108
|
+
case SASS_BOOLEAN: {
|
|
1109
|
+
e = new (ctx.mem) Boolean(path, position, !!sass_boolean_get_value(v));
|
|
1110
|
+
} break;
|
|
1111
|
+
case SASS_NUMBER: {
|
|
1112
|
+
e = new (ctx.mem) Number(path, position, sass_number_get_value(v), sass_number_get_unit(v));
|
|
1113
|
+
} break;
|
|
1114
|
+
case SASS_COLOR: {
|
|
1115
|
+
e = new (ctx.mem) Color(path, position, sass_color_get_r(v), sass_color_get_g(v), sass_color_get_b(v), sass_color_get_a(v));
|
|
1116
|
+
} break;
|
|
1117
|
+
case SASS_STRING: {
|
|
1118
|
+
e = new (ctx.mem) String_Constant(path, position, sass_string_get_value(v));
|
|
1119
|
+
} break;
|
|
1120
|
+
case SASS_LIST: {
|
|
1121
|
+
List* l = new (ctx.mem) List(path, position, sass_list_get_length(v), sass_list_get_separator(v) == SASS_COMMA ? List::COMMA : List::SPACE);
|
|
1122
|
+
for (size_t i = 0, L = sass_list_get_length(v); i < L; ++i) {
|
|
1123
|
+
*l << cval_to_astnode(sass_list_get_value(v, i), ctx, backtrace, path, position);
|
|
1124
|
+
}
|
|
1125
|
+
e = l;
|
|
1126
|
+
} break;
|
|
1127
|
+
case SASS_MAP: {
|
|
1128
|
+
Map* m = new (ctx.mem) Map(path, position);
|
|
1129
|
+
for (size_t i = 0, L = sass_map_get_length(v); i < L; ++i) {
|
|
1130
|
+
*m << std::make_pair(
|
|
1131
|
+
cval_to_astnode(sass_map_get_key(v, i), ctx, backtrace, path, position),
|
|
1132
|
+
cval_to_astnode(sass_map_get_value(v, i), ctx, backtrace, path, position));
|
|
1133
|
+
}
|
|
1134
|
+
e = m;
|
|
1135
|
+
} break;
|
|
1136
|
+
case SASS_NULL: {
|
|
1137
|
+
e = new (ctx.mem) Null(path, position);
|
|
1138
|
+
} break;
|
|
1139
|
+
case SASS_ERROR: {
|
|
1140
|
+
error("Error in C function: " + string(sass_error_get_message(v)), path, position, backtrace);
|
|
1141
|
+
} break;
|
|
1142
|
+
case SASS_WARNING: {
|
|
1143
|
+
error("Warning in C function: " + string(sass_warning_get_message(v)), path, position, backtrace);
|
|
1144
|
+
} break;
|
|
1145
|
+
}
|
|
1146
|
+
return e;
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
}
|