sassc 1.8.3 → 1.8.4
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 +4 -4
- data/README.md +3 -1
- data/ext/libsass/.editorconfig +1 -1
- data/ext/libsass/.gitignore +1 -0
- data/ext/libsass/LICENSE +1 -1
- data/ext/libsass/Makefile +20 -14
- data/ext/libsass/Makefile.conf +0 -1
- data/ext/libsass/Readme.md +3 -1
- data/ext/libsass/appveyor.yml +19 -11
- data/ext/libsass/docs/api-importer-example.md +2 -1235
- data/ext/libsass/docs/build-with-autotools.md +10 -0
- data/ext/libsass/docs/build-with-makefiles.md +18 -0
- data/ext/libsass/include/sass/base.h +4 -1
- data/ext/libsass/include/sass/values.h +2 -1
- data/ext/libsass/src/ast.cpp +279 -346
- data/ext/libsass/src/ast.hpp +234 -60
- data/ext/libsass/src/base64vlq.cpp +1 -0
- data/ext/libsass/src/bind.cpp +35 -45
- data/ext/libsass/src/bind.hpp +1 -0
- data/ext/libsass/src/color_maps.cpp +1 -0
- data/ext/libsass/src/constants.cpp +4 -1
- data/ext/libsass/src/constants.hpp +2 -1
- data/ext/libsass/src/context.cpp +41 -31
- data/ext/libsass/src/context.hpp +10 -10
- data/ext/libsass/src/cssize.cpp +7 -4
- data/ext/libsass/src/cssize.hpp +1 -3
- data/ext/libsass/src/debugger.hpp +73 -14
- data/ext/libsass/src/emitter.cpp +37 -25
- data/ext/libsass/src/emitter.hpp +10 -9
- data/ext/libsass/src/environment.cpp +16 -5
- data/ext/libsass/src/environment.hpp +5 -3
- data/ext/libsass/src/error_handling.cpp +91 -14
- data/ext/libsass/src/error_handling.hpp +105 -4
- data/ext/libsass/src/eval.cpp +519 -330
- data/ext/libsass/src/eval.hpp +12 -13
- data/ext/libsass/src/expand.cpp +92 -56
- data/ext/libsass/src/expand.hpp +5 -3
- data/ext/libsass/src/extend.cpp +60 -51
- data/ext/libsass/src/extend.hpp +1 -3
- data/ext/libsass/src/file.cpp +37 -27
- data/ext/libsass/src/functions.cpp +78 -62
- data/ext/libsass/src/functions.hpp +1 -0
- data/ext/libsass/src/inspect.cpp +293 -64
- data/ext/libsass/src/inspect.hpp +2 -0
- data/ext/libsass/src/lexer.cpp +1 -0
- data/ext/libsass/src/listize.cpp +14 -15
- data/ext/libsass/src/listize.hpp +3 -5
- data/ext/libsass/src/memory_manager.cpp +1 -0
- data/ext/libsass/src/node.cpp +2 -3
- data/ext/libsass/src/operation.hpp +70 -71
- data/ext/libsass/src/output.cpp +28 -32
- data/ext/libsass/src/output.hpp +1 -2
- data/ext/libsass/src/parser.cpp +402 -183
- data/ext/libsass/src/parser.hpp +19 -9
- data/ext/libsass/src/plugins.cpp +1 -0
- data/ext/libsass/src/position.cpp +1 -0
- data/ext/libsass/src/prelexer.cpp +134 -56
- data/ext/libsass/src/prelexer.hpp +51 -3
- data/ext/libsass/src/remove_placeholders.cpp +35 -9
- data/ext/libsass/src/remove_placeholders.hpp +4 -3
- data/ext/libsass/src/sass.cpp +1 -0
- data/ext/libsass/src/sass.hpp +129 -0
- data/ext/libsass/src/sass_context.cpp +31 -14
- data/ext/libsass/src/sass_context.hpp +2 -31
- data/ext/libsass/src/sass_functions.cpp +1 -0
- data/ext/libsass/src/sass_interface.cpp +5 -6
- data/ext/libsass/src/sass_util.cpp +1 -2
- data/ext/libsass/src/sass_util.hpp +5 -5
- data/ext/libsass/src/sass_values.cpp +13 -10
- data/ext/libsass/src/source_map.cpp +4 -3
- data/ext/libsass/src/source_map.hpp +2 -2
- data/ext/libsass/src/subset_map.hpp +0 -1
- data/ext/libsass/src/to_c.cpp +1 -0
- data/ext/libsass/src/to_c.hpp +1 -3
- data/ext/libsass/src/to_value.cpp +3 -5
- data/ext/libsass/src/to_value.hpp +1 -1
- data/ext/libsass/src/units.cpp +96 -59
- data/ext/libsass/src/units.hpp +10 -8
- data/ext/libsass/src/utf8_string.cpp +5 -0
- data/ext/libsass/src/util.cpp +23 -156
- data/ext/libsass/src/util.hpp +10 -14
- data/ext/libsass/src/values.cpp +1 -0
- data/ext/libsass/test/test_node.cpp +2 -6
- data/ext/libsass/test/test_selector_difference.cpp +1 -3
- data/ext/libsass/test/test_specificity.cpp +0 -2
- data/ext/libsass/test/test_superselector.cpp +0 -2
- data/ext/libsass/test/test_unification.cpp +1 -3
- data/ext/libsass/win/libsass.targets +18 -5
- data/ext/libsass/win/libsass.vcxproj +9 -7
- data/ext/libsass/win/libsass.vcxproj.filters +148 -106
- data/lib/sassc/version.rb +1 -1
- data/test/engine_test.rb +12 -0
- data/test/native_test.rb +1 -1
- metadata +3 -4
- data/ext/libsass/src/to_string.cpp +0 -48
- data/ext/libsass/src/to_string.hpp +0 -38
data/ext/libsass/src/emitter.hpp
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
#define SASS_EMITTER_H
|
3
3
|
|
4
4
|
#include <string>
|
5
|
+
#include "sass.hpp"
|
5
6
|
#include "sass/base.h"
|
6
7
|
#include "source_map.hpp"
|
7
8
|
#include "ast_fwd_decl.hpp"
|
@@ -12,7 +13,7 @@ namespace Sass {
|
|
12
13
|
class Emitter {
|
13
14
|
|
14
15
|
public:
|
15
|
-
Emitter(
|
16
|
+
Emitter(struct Sass_Output_Options& opt);
|
16
17
|
virtual ~Emitter() { }
|
17
18
|
|
18
19
|
protected:
|
@@ -24,17 +25,19 @@ namespace Sass {
|
|
24
25
|
// proxy methods for source maps
|
25
26
|
void add_source_index(size_t idx);
|
26
27
|
void set_filename(const std::string& str);
|
27
|
-
void add_open_mapping(AST_Node* node);
|
28
|
-
void add_close_mapping(AST_Node* node);
|
28
|
+
void add_open_mapping(const AST_Node* node);
|
29
|
+
void add_close_mapping(const AST_Node* node);
|
30
|
+
void schedule_mapping(const AST_Node* node);
|
29
31
|
std::string render_srcmap(Context &ctx);
|
30
32
|
ParserState remap(const ParserState& pstate);
|
31
33
|
|
32
34
|
public:
|
33
|
-
|
35
|
+
struct Sass_Output_Options& opt;
|
34
36
|
size_t indentation;
|
35
37
|
size_t scheduled_space;
|
36
38
|
size_t scheduled_linefeed;
|
37
39
|
bool scheduled_delimiter;
|
40
|
+
const AST_Node* scheduled_mapping;
|
38
41
|
|
39
42
|
public:
|
40
43
|
// output strings different in comments
|
@@ -48,16 +51,14 @@ namespace Sass {
|
|
48
51
|
// nested lists need parentheses
|
49
52
|
bool in_space_array;
|
50
53
|
bool in_comma_array;
|
51
|
-
// list separators don't get compressed in @debug
|
52
|
-
bool in_debug;
|
53
54
|
|
54
55
|
public:
|
55
56
|
// return buffer as std::string
|
56
57
|
std::string get_buffer(void);
|
57
58
|
// flush scheduled space/linefeed
|
58
|
-
Sass_Output_Style output_style(void);
|
59
|
+
Sass_Output_Style output_style(void) const;
|
59
60
|
// add outstanding linefeed
|
60
|
-
void finalize(
|
61
|
+
void finalize(bool final = true);
|
61
62
|
// flush scheduled space/linefeed
|
62
63
|
void flush_schedules(void);
|
63
64
|
// prepend some text or token to the buffer
|
@@ -69,7 +70,7 @@ namespace Sass {
|
|
69
70
|
void append_wspace(const std::string& text);
|
70
71
|
// append some text or token to the buffer
|
71
72
|
// this adds source-mappings for node start and end
|
72
|
-
void append_token(const std::string& text, AST_Node* node);
|
73
|
+
void append_token(const std::string& text, const AST_Node* node);
|
73
74
|
|
74
75
|
public: // syntax sugar
|
75
76
|
void append_indentation();
|
@@ -1,14 +1,24 @@
|
|
1
|
+
#include "sass.hpp"
|
1
2
|
#include "ast.hpp"
|
2
3
|
#include "environment.hpp"
|
3
4
|
|
4
5
|
namespace Sass {
|
5
6
|
|
6
7
|
template <typename T>
|
7
|
-
Environment<T>::Environment(
|
8
|
+
Environment<T>::Environment(bool is_shadow)
|
9
|
+
: local_frame_(std::map<std::string, T>()),
|
10
|
+
parent_(0), is_shadow_(false)
|
11
|
+
{ }
|
8
12
|
template <typename T>
|
9
|
-
Environment<T>::Environment(Environment<T>* env
|
13
|
+
Environment<T>::Environment(Environment<T>* env, bool is_shadow)
|
14
|
+
: local_frame_(std::map<std::string, T>()),
|
15
|
+
parent_(env), is_shadow_(is_shadow)
|
16
|
+
{ }
|
10
17
|
template <typename T>
|
11
|
-
Environment<T>::Environment(Environment<T>& env
|
18
|
+
Environment<T>::Environment(Environment<T>& env, bool is_shadow)
|
19
|
+
: local_frame_(std::map<std::string, T>()),
|
20
|
+
parent_(&env), is_shadow_(is_shadow)
|
21
|
+
{ }
|
12
22
|
|
13
23
|
// link parent to create a stack
|
14
24
|
template <typename T>
|
@@ -118,12 +128,13 @@ namespace Sass {
|
|
118
128
|
template <typename T>
|
119
129
|
void Environment<T>::set_lexical(const std::string& key, T val)
|
120
130
|
{
|
121
|
-
auto cur = this;
|
122
|
-
while (cur->is_lexical()) {
|
131
|
+
auto cur = this; bool shadow = false;
|
132
|
+
while (cur->is_lexical() || shadow) {
|
123
133
|
if (cur->has_local(key)) {
|
124
134
|
cur->set_local(key, val);
|
125
135
|
return;
|
126
136
|
}
|
137
|
+
shadow = cur->is_shadow();
|
127
138
|
cur = cur->parent_;
|
128
139
|
}
|
129
140
|
set_local(key, val);
|
@@ -15,12 +15,13 @@ namespace Sass {
|
|
15
15
|
// TODO: test with map
|
16
16
|
std::map<std::string, T> local_frame_;
|
17
17
|
ADD_PROPERTY(Environment*, parent)
|
18
|
+
ADD_PROPERTY(bool, is_shadow)
|
18
19
|
|
19
20
|
public:
|
20
21
|
Memory_Manager mem;
|
21
|
-
Environment();
|
22
|
-
Environment(Environment* env);
|
23
|
-
Environment(Environment& env);
|
22
|
+
Environment(bool is_shadow = false);
|
23
|
+
Environment(Environment* env, bool is_shadow = false);
|
24
|
+
Environment(Environment& env, bool is_shadow = false);
|
24
25
|
|
25
26
|
// link parent to create a stack
|
26
27
|
void link(Environment& env);
|
@@ -87,6 +88,7 @@ namespace Sass {
|
|
87
88
|
#endif
|
88
89
|
|
89
90
|
};
|
91
|
+
|
90
92
|
}
|
91
93
|
|
92
94
|
#endif
|
@@ -1,7 +1,7 @@
|
|
1
|
+
#include "sass.hpp"
|
1
2
|
#include "ast.hpp"
|
2
3
|
#include "prelexer.hpp"
|
3
4
|
#include "backtrace.hpp"
|
4
|
-
#include "to_string.hpp"
|
5
5
|
#include "error_handling.hpp"
|
6
6
|
|
7
7
|
#include <iostream>
|
@@ -10,16 +10,12 @@ namespace Sass {
|
|
10
10
|
|
11
11
|
namespace Exception {
|
12
12
|
|
13
|
-
Base::Base(ParserState pstate, std::string msg)
|
14
|
-
: std::runtime_error(msg),
|
15
|
-
|
13
|
+
Base::Base(ParserState pstate, std::string msg, std::vector<Sass_Import_Entry>* import_stack)
|
14
|
+
: std::runtime_error(msg), msg(msg),
|
15
|
+
prefix("Error"), pstate(pstate),
|
16
|
+
import_stack(import_stack)
|
16
17
|
{ }
|
17
18
|
|
18
|
-
const char* Base::what() const throw()
|
19
|
-
{
|
20
|
-
return msg.c_str();
|
21
|
-
}
|
22
|
-
|
23
19
|
InvalidSass::InvalidSass(ParserState pstate, std::string msg)
|
24
20
|
: Base(pstate, msg)
|
25
21
|
{ }
|
@@ -29,9 +25,9 @@ namespace Sass {
|
|
29
25
|
: Base(selector->pstate()), parent(parent), selector(selector)
|
30
26
|
{
|
31
27
|
msg = "Invalid parent selector for \"";
|
32
|
-
msg += selector->to_string(
|
28
|
+
msg += selector->to_string(Sass_Inspect_Options());
|
33
29
|
msg += "\": \"";
|
34
|
-
msg += parent->to_string(
|
30
|
+
msg += parent->to_string(Sass_Inspect_Options());
|
35
31
|
msg += "\"";
|
36
32
|
}
|
37
33
|
|
@@ -39,15 +35,96 @@ namespace Sass {
|
|
39
35
|
: Base(pstate), fn(fn), arg(arg), type(type), value(value)
|
40
36
|
{
|
41
37
|
msg = arg + ": \"";
|
42
|
-
msg += value->to_string(
|
38
|
+
msg += value->to_string(Sass_Inspect_Options());
|
43
39
|
msg += "\" is not a " + type;
|
44
40
|
msg += " for `" + fn + "'";
|
45
41
|
}
|
46
42
|
|
47
|
-
InvalidSyntax::InvalidSyntax(ParserState pstate, std::string msg)
|
48
|
-
: Base(pstate, msg)
|
43
|
+
InvalidSyntax::InvalidSyntax(ParserState pstate, std::string msg, std::vector<Sass_Import_Entry>* import_stack)
|
44
|
+
: Base(pstate, msg, import_stack)
|
49
45
|
{ }
|
50
46
|
|
47
|
+
UndefinedOperation::UndefinedOperation(const Expression* lhs, const Expression* rhs, const std::string& op)
|
48
|
+
: lhs(lhs), rhs(rhs), op(op)
|
49
|
+
{
|
50
|
+
msg = def_op_msg + ": \"";
|
51
|
+
msg += lhs->to_string({ NESTED, 5 });
|
52
|
+
msg += " " + op + " ";
|
53
|
+
msg += rhs->to_string({ TO_SASS, 5 });
|
54
|
+
msg += "\".";
|
55
|
+
}
|
56
|
+
|
57
|
+
InvalidNullOperation::InvalidNullOperation(const Expression* lhs, const Expression* rhs, const std::string& op)
|
58
|
+
: UndefinedOperation(lhs, rhs, op)
|
59
|
+
{
|
60
|
+
msg = def_op_null_msg + ": \"";
|
61
|
+
msg += lhs->inspect();
|
62
|
+
msg += " " + op + " ";
|
63
|
+
msg += rhs->inspect();
|
64
|
+
msg += "\".";
|
65
|
+
}
|
66
|
+
|
67
|
+
ZeroDivisionError::ZeroDivisionError(const Expression& lhs, const Expression& rhs)
|
68
|
+
: lhs(lhs), rhs(rhs)
|
69
|
+
{
|
70
|
+
msg = "divided by 0";
|
71
|
+
}
|
72
|
+
|
73
|
+
DuplicateKeyError::DuplicateKeyError(const Map& dup, const Expression& org)
|
74
|
+
: Base(org.pstate()), dup(dup), org(org)
|
75
|
+
{
|
76
|
+
msg = "Duplicate key ";
|
77
|
+
dup.get_duplicate_key()->is_delayed(false);
|
78
|
+
msg += dup.get_duplicate_key()->inspect();
|
79
|
+
msg += " in map (";
|
80
|
+
msg += org.inspect();
|
81
|
+
msg += ").";
|
82
|
+
}
|
83
|
+
|
84
|
+
TypeMismatch::TypeMismatch(const Expression& var, const std::string type)
|
85
|
+
: Base(var.pstate()), var(var), type(type)
|
86
|
+
{
|
87
|
+
msg = var.to_string();
|
88
|
+
msg += " is not an ";
|
89
|
+
msg += type;
|
90
|
+
msg += ".";
|
91
|
+
}
|
92
|
+
|
93
|
+
InvalidValue::InvalidValue(const Expression& val)
|
94
|
+
: Base(val.pstate()), val(val)
|
95
|
+
{
|
96
|
+
msg = val.to_string();
|
97
|
+
msg += " isn't a valid CSS value.";
|
98
|
+
}
|
99
|
+
|
100
|
+
IncompatibleUnits::IncompatibleUnits(const Number& lhs, const Number& rhs)
|
101
|
+
: lhs(lhs), rhs(rhs)
|
102
|
+
{
|
103
|
+
msg = "Incompatible units: '";
|
104
|
+
msg += rhs.unit();
|
105
|
+
msg += "' and '";
|
106
|
+
msg += lhs.unit();
|
107
|
+
msg += "'.";
|
108
|
+
}
|
109
|
+
|
110
|
+
AlphaChannelsNotEqual::AlphaChannelsNotEqual(const Expression* lhs, const Expression* rhs, const std::string& op)
|
111
|
+
: lhs(lhs), rhs(rhs), op(op)
|
112
|
+
{
|
113
|
+
msg = "Alpha channels must be equal: ";
|
114
|
+
msg += lhs->to_string({ NESTED, 5 });
|
115
|
+
msg += " " + op + " ";
|
116
|
+
msg += rhs->to_string({ NESTED, 5 });
|
117
|
+
msg += ".";
|
118
|
+
}
|
119
|
+
|
120
|
+
|
121
|
+
SassValueError::SassValueError(ParserState pstate, OperationError& err)
|
122
|
+
: Base(pstate, err.what())
|
123
|
+
{
|
124
|
+
msg = err.what();
|
125
|
+
prefix = err.errtype();
|
126
|
+
}
|
127
|
+
|
51
128
|
}
|
52
129
|
|
53
130
|
|
@@ -12,16 +12,21 @@ namespace Sass {
|
|
12
12
|
|
13
13
|
namespace Exception {
|
14
14
|
|
15
|
-
const std::string def_msg = "Invalid sass";
|
15
|
+
const std::string def_msg = "Invalid sass detected";
|
16
|
+
const std::string def_op_msg = "Undefined operation";
|
17
|
+
const std::string def_op_null_msg = "Invalid null operation";
|
16
18
|
|
17
19
|
class Base : public std::runtime_error {
|
18
20
|
protected:
|
19
21
|
std::string msg;
|
22
|
+
std::string prefix;
|
20
23
|
public:
|
21
24
|
ParserState pstate;
|
25
|
+
std::vector<Sass_Import_Entry>* import_stack;
|
22
26
|
public:
|
23
|
-
Base(ParserState pstate, std::string msg = def_msg);
|
24
|
-
virtual const char*
|
27
|
+
Base(ParserState pstate, std::string msg = def_msg, std::vector<Sass_Import_Entry>* import_stack = 0);
|
28
|
+
virtual const char* errtype() const { return prefix.c_str(); }
|
29
|
+
virtual const char* what() const throw() { return msg.c_str(); }
|
25
30
|
virtual ~Base() throw() {};
|
26
31
|
};
|
27
32
|
|
@@ -53,10 +58,106 @@ namespace Sass {
|
|
53
58
|
|
54
59
|
class InvalidSyntax : public Base {
|
55
60
|
public:
|
56
|
-
InvalidSyntax(ParserState pstate, std::string msg);
|
61
|
+
InvalidSyntax(ParserState pstate, std::string msg, std::vector<Sass_Import_Entry>* import_stack = 0);
|
57
62
|
virtual ~InvalidSyntax() throw() {};
|
58
63
|
};
|
59
64
|
|
65
|
+
/* common virtual base class (has no pstate) */
|
66
|
+
class OperationError : public std::runtime_error {
|
67
|
+
protected:
|
68
|
+
std::string msg;
|
69
|
+
public:
|
70
|
+
OperationError(std::string msg = def_op_msg)
|
71
|
+
: std::runtime_error(msg), msg(msg)
|
72
|
+
{};
|
73
|
+
public:
|
74
|
+
virtual const char* errtype() const { return "Error"; }
|
75
|
+
virtual const char* what() const throw() { return msg.c_str(); }
|
76
|
+
virtual ~OperationError() throw() {};
|
77
|
+
};
|
78
|
+
|
79
|
+
class ZeroDivisionError : public OperationError {
|
80
|
+
protected:
|
81
|
+
const Expression& lhs;
|
82
|
+
const Expression& rhs;
|
83
|
+
public:
|
84
|
+
ZeroDivisionError(const Expression& lhs, const Expression& rhs);
|
85
|
+
virtual const char* errtype() const { return "ZeroDivisionError"; }
|
86
|
+
virtual ~ZeroDivisionError() throw() {};
|
87
|
+
};
|
88
|
+
|
89
|
+
class DuplicateKeyError : public Base {
|
90
|
+
protected:
|
91
|
+
const Map& dup;
|
92
|
+
const Expression& org;
|
93
|
+
public:
|
94
|
+
DuplicateKeyError(const Map& dup, const Expression& org);
|
95
|
+
virtual const char* errtype() const { return "Error"; }
|
96
|
+
virtual ~DuplicateKeyError() throw() {};
|
97
|
+
};
|
98
|
+
|
99
|
+
class TypeMismatch : public Base {
|
100
|
+
protected:
|
101
|
+
const Expression& var;
|
102
|
+
const std::string type;
|
103
|
+
public:
|
104
|
+
TypeMismatch(const Expression& var, const std::string type);
|
105
|
+
virtual const char* errtype() const { return "Error"; }
|
106
|
+
virtual ~TypeMismatch() throw() {};
|
107
|
+
};
|
108
|
+
|
109
|
+
class InvalidValue : public Base {
|
110
|
+
protected:
|
111
|
+
const Expression& val;
|
112
|
+
public:
|
113
|
+
InvalidValue(const Expression& val);
|
114
|
+
virtual const char* errtype() const { return "Error"; }
|
115
|
+
virtual ~InvalidValue() throw() {};
|
116
|
+
};
|
117
|
+
|
118
|
+
class IncompatibleUnits : public OperationError {
|
119
|
+
protected:
|
120
|
+
const Number& lhs;
|
121
|
+
const Number& rhs;
|
122
|
+
public:
|
123
|
+
IncompatibleUnits(const Number& lhs, const Number& rhs);
|
124
|
+
virtual ~IncompatibleUnits() throw() {};
|
125
|
+
};
|
126
|
+
|
127
|
+
class UndefinedOperation : public OperationError {
|
128
|
+
protected:
|
129
|
+
const Expression* lhs;
|
130
|
+
const Expression* rhs;
|
131
|
+
const std::string op;
|
132
|
+
public:
|
133
|
+
UndefinedOperation(const Expression* lhs, const Expression* rhs, const std::string& op);
|
134
|
+
// virtual const char* errtype() const { return "Error"; }
|
135
|
+
virtual ~UndefinedOperation() throw() {};
|
136
|
+
};
|
137
|
+
|
138
|
+
class InvalidNullOperation : public UndefinedOperation {
|
139
|
+
public:
|
140
|
+
InvalidNullOperation(const Expression* lhs, const Expression* rhs, const std::string& op);
|
141
|
+
virtual ~InvalidNullOperation() throw() {};
|
142
|
+
};
|
143
|
+
|
144
|
+
class AlphaChannelsNotEqual : public OperationError {
|
145
|
+
protected:
|
146
|
+
const Expression* lhs;
|
147
|
+
const Expression* rhs;
|
148
|
+
const std::string op;
|
149
|
+
public:
|
150
|
+
AlphaChannelsNotEqual(const Expression* lhs, const Expression* rhs, const std::string& op);
|
151
|
+
// virtual const char* errtype() const { return "Error"; }
|
152
|
+
virtual ~AlphaChannelsNotEqual() throw() {};
|
153
|
+
};
|
154
|
+
|
155
|
+
class SassValueError : public Base {
|
156
|
+
public:
|
157
|
+
SassValueError(ParserState pstate, OperationError& err);
|
158
|
+
virtual ~SassValueError() throw() {};
|
159
|
+
};
|
160
|
+
|
60
161
|
}
|
61
162
|
|
62
163
|
void warn(std::string msg, ParserState pstate);
|
data/ext/libsass/src/eval.cpp
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
#include "sass.hpp"
|
1
2
|
#include <cstdlib>
|
2
3
|
#include <cmath>
|
3
4
|
#include <iostream>
|
@@ -10,7 +11,6 @@
|
|
10
11
|
#include "ast.hpp"
|
11
12
|
#include "bind.hpp"
|
12
13
|
#include "util.hpp"
|
13
|
-
#include "to_string.hpp"
|
14
14
|
#include "inspect.hpp"
|
15
15
|
#include "environment.hpp"
|
16
16
|
#include "position.hpp"
|
@@ -41,8 +41,7 @@ namespace Sass {
|
|
41
41
|
|
42
42
|
Eval::Eval(Expand& exp)
|
43
43
|
: exp(exp),
|
44
|
-
ctx(exp.ctx)
|
45
|
-
listize(exp.ctx)
|
44
|
+
ctx(exp.ctx)
|
46
45
|
{ }
|
47
46
|
Eval::~Eval() { }
|
48
47
|
|
@@ -160,11 +159,11 @@ namespace Sass {
|
|
160
159
|
std::string variable(f->variable());
|
161
160
|
Expression* low = f->lower_bound()->perform(this);
|
162
161
|
if (low->concrete_type() != Expression::NUMBER) {
|
163
|
-
|
162
|
+
throw Exception::TypeMismatch(*low, "integer");
|
164
163
|
}
|
165
164
|
Expression* high = f->upper_bound()->perform(this);
|
166
165
|
if (high->concrete_type() != Expression::NUMBER) {
|
167
|
-
|
166
|
+
throw Exception::TypeMismatch(*high, "integer");
|
168
167
|
}
|
169
168
|
Number* sass_start = static_cast<Number*>(low);
|
170
169
|
Number* sass_end = static_cast<Number*>(high);
|
@@ -178,10 +177,10 @@ namespace Sass {
|
|
178
177
|
double start = sass_start->value();
|
179
178
|
double end = sass_end->value();
|
180
179
|
// only create iterator once in this environment
|
181
|
-
Env
|
182
|
-
|
183
|
-
|
184
|
-
env
|
180
|
+
Env env(environment(), true);
|
181
|
+
exp.env_stack.push_back(&env);
|
182
|
+
Number* it = SASS_MEMORY_NEW(env.mem, Number, low->pstate(), start, sass_end->unit());
|
183
|
+
env.set_local(variable, it);
|
185
184
|
Block* body = f->block();
|
186
185
|
Expression* val = 0;
|
187
186
|
if (start < end) {
|
@@ -190,7 +189,7 @@ namespace Sass {
|
|
190
189
|
i < end;
|
191
190
|
++i) {
|
192
191
|
it->value(i);
|
193
|
-
env
|
192
|
+
env.set_local(variable, it);
|
194
193
|
val = body->perform(this);
|
195
194
|
if (val) break;
|
196
195
|
}
|
@@ -200,14 +199,12 @@ namespace Sass {
|
|
200
199
|
i > end;
|
201
200
|
--i) {
|
202
201
|
it->value(i);
|
203
|
-
env
|
202
|
+
env.set_local(variable, it);
|
204
203
|
val = body->perform(this);
|
205
204
|
if (val) break;
|
206
205
|
}
|
207
206
|
}
|
208
|
-
|
209
|
-
if (!old_var) env->del_local(variable);
|
210
|
-
else env->set_local(variable, old_var);
|
207
|
+
exp.env_stack.pop_back();
|
211
208
|
return val;
|
212
209
|
}
|
213
210
|
|
@@ -217,12 +214,17 @@ namespace Sass {
|
|
217
214
|
{
|
218
215
|
std::vector<std::string> variables(e->variables());
|
219
216
|
Expression* expr = e->list()->perform(this);
|
220
|
-
Env
|
221
|
-
|
217
|
+
Env env(environment(), true);
|
218
|
+
exp.env_stack.push_back(&env);
|
219
|
+
Vectorized<Expression*>* list = 0;
|
222
220
|
Map* map = 0;
|
223
221
|
if (expr->concrete_type() == Expression::MAP) {
|
224
222
|
map = static_cast<Map*>(expr);
|
225
223
|
}
|
224
|
+
else if (Selector_List* ls = dynamic_cast<Selector_List*>(expr)) {
|
225
|
+
Listize listize(ctx.mem);
|
226
|
+
list = dynamic_cast<List*>(ls->perform(&listize));
|
227
|
+
}
|
226
228
|
else if (expr->concrete_type() != Expression::LIST) {
|
227
229
|
list = SASS_MEMORY_NEW(ctx.mem, List, expr->pstate(), 1, SASS_COMMA);
|
228
230
|
*list << expr;
|
@@ -230,12 +232,7 @@ namespace Sass {
|
|
230
232
|
else {
|
231
233
|
list = static_cast<List*>(expr);
|
232
234
|
}
|
233
|
-
|
234
|
-
std::vector<AST_Node*> old_vars(variables.size());
|
235
|
-
for (size_t i = 0, L = variables.size(); i < L; ++i) {
|
236
|
-
old_vars[i] = env->has_local(variables[i]) ? env->get_local(variables[i]) : 0;
|
237
|
-
env->set_local(variables[i], 0);
|
238
|
-
}
|
235
|
+
|
239
236
|
Block* body = e->block();
|
240
237
|
Expression* val = 0;
|
241
238
|
|
@@ -247,10 +244,10 @@ namespace Sass {
|
|
247
244
|
List* variable = SASS_MEMORY_NEW(ctx.mem, List, map->pstate(), 2, SASS_SPACE);
|
248
245
|
*variable << key;
|
249
246
|
*variable << value;
|
250
|
-
env
|
247
|
+
env.set_local(variables[0], variable);
|
251
248
|
} else {
|
252
|
-
env
|
253
|
-
env
|
249
|
+
env.set_local(variables[0], key);
|
250
|
+
env.set_local(variables[1], value);
|
254
251
|
}
|
255
252
|
|
256
253
|
val = body->perform(this);
|
@@ -258,6 +255,9 @@ namespace Sass {
|
|
258
255
|
}
|
259
256
|
}
|
260
257
|
else {
|
258
|
+
if (list->length() == 1 && dynamic_cast<Selector_List*>(list)) {
|
259
|
+
list = dynamic_cast<Vectorized<Expression*>*>(list);
|
260
|
+
}
|
261
261
|
for (size_t i = 0, L = list->length(); i < L; ++i) {
|
262
262
|
Expression* e = (*list)[i];
|
263
263
|
// unwrap value if the expression is an argument
|
@@ -266,21 +266,23 @@ namespace Sass {
|
|
266
266
|
if (List* scalars = dynamic_cast<List*>(e)) {
|
267
267
|
if (variables.size() == 1) {
|
268
268
|
Expression* var = scalars;
|
269
|
-
env
|
269
|
+
env.set_local(variables[0], var);
|
270
270
|
} else {
|
271
|
+
// XXX: this is never hit via spec tests
|
271
272
|
for (size_t j = 0, K = variables.size(); j < K; ++j) {
|
272
273
|
Expression* res = j >= scalars->length()
|
273
274
|
? SASS_MEMORY_NEW(ctx.mem, Null, expr->pstate())
|
274
275
|
: (*scalars)[j];
|
275
|
-
env
|
276
|
+
env.set_local(variables[j], res);
|
276
277
|
}
|
277
278
|
}
|
278
279
|
} else {
|
279
280
|
if (variables.size() > 0) {
|
280
|
-
env
|
281
|
+
env.set_local(variables[0], e);
|
281
282
|
for (size_t j = 1, K = variables.size(); j < K; ++j) {
|
283
|
+
// XXX: this is never hit via spec tests
|
282
284
|
Expression* res = SASS_MEMORY_NEW(ctx.mem, Null, expr->pstate());
|
283
|
-
env
|
285
|
+
env.set_local(variables[j], res);
|
284
286
|
}
|
285
287
|
}
|
286
288
|
}
|
@@ -288,11 +290,7 @@ namespace Sass {
|
|
288
290
|
if (val) break;
|
289
291
|
}
|
290
292
|
}
|
291
|
-
|
292
|
-
for (size_t j = 0, K = variables.size(); j < K; ++j) {
|
293
|
-
if(!old_vars[j]) env->del_local(variables[j]);
|
294
|
-
else env->set_local(variables[j], old_vars[j]);
|
295
|
-
}
|
293
|
+
exp.env_stack.pop_back();
|
296
294
|
return val;
|
297
295
|
}
|
298
296
|
|
@@ -300,10 +298,16 @@ namespace Sass {
|
|
300
298
|
{
|
301
299
|
Expression* pred = w->predicate();
|
302
300
|
Block* body = w->block();
|
301
|
+
Env env(environment(), true);
|
302
|
+
exp.env_stack.push_back(&env);
|
303
303
|
while (*pred->perform(this)) {
|
304
304
|
Expression* val = body->perform(this);
|
305
|
-
if (val)
|
305
|
+
if (val) {
|
306
|
+
exp.env_stack.pop_back();
|
307
|
+
return val;
|
308
|
+
}
|
306
309
|
}
|
310
|
+
exp.env_stack.pop_back();
|
307
311
|
return 0;
|
308
312
|
}
|
309
313
|
|
@@ -314,8 +318,9 @@ namespace Sass {
|
|
314
318
|
|
315
319
|
Expression* Eval::operator()(Warning* w)
|
316
320
|
{
|
321
|
+
Sass_Output_Style outstyle = ctx.c_options.output_style;
|
322
|
+
ctx.c_options.output_style = NESTED;
|
317
323
|
Expression* message = w->message()->perform(this);
|
318
|
-
To_String to_string(&ctx);
|
319
324
|
Env* env = exp.environment();
|
320
325
|
|
321
326
|
// try to use generic function
|
@@ -331,24 +336,27 @@ namespace Sass {
|
|
331
336
|
union Sass_Value* c_args = sass_make_list(1, SASS_COMMA);
|
332
337
|
sass_list_set_value(c_args, 0, message->perform(&to_c));
|
333
338
|
union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_compiler);
|
339
|
+
ctx.c_options.output_style = outstyle;
|
334
340
|
sass_delete_value(c_args);
|
335
341
|
sass_delete_value(c_val);
|
336
342
|
return 0;
|
337
343
|
|
338
344
|
}
|
339
345
|
|
340
|
-
std::string result(unquote(message->
|
346
|
+
std::string result(unquote(message->to_sass()));
|
341
347
|
Backtrace top(backtrace(), w->pstate(), "");
|
342
348
|
std::cerr << "WARNING: " << result;
|
343
|
-
std::cerr << top.to_string(
|
349
|
+
std::cerr << top.to_string();
|
344
350
|
std::cerr << std::endl << std::endl;
|
351
|
+
ctx.c_options.output_style = outstyle;
|
345
352
|
return 0;
|
346
353
|
}
|
347
354
|
|
348
355
|
Expression* Eval::operator()(Error* e)
|
349
356
|
{
|
357
|
+
Sass_Output_Style outstyle = ctx.c_options.output_style;
|
358
|
+
ctx.c_options.output_style = NESTED;
|
350
359
|
Expression* message = e->message()->perform(this);
|
351
|
-
To_String to_string(&ctx);
|
352
360
|
Env* env = exp.environment();
|
353
361
|
|
354
362
|
// try to use generic function
|
@@ -364,21 +372,24 @@ namespace Sass {
|
|
364
372
|
union Sass_Value* c_args = sass_make_list(1, SASS_COMMA);
|
365
373
|
sass_list_set_value(c_args, 0, message->perform(&to_c));
|
366
374
|
union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_compiler);
|
375
|
+
ctx.c_options.output_style = outstyle;
|
367
376
|
sass_delete_value(c_args);
|
368
377
|
sass_delete_value(c_val);
|
369
378
|
return 0;
|
370
379
|
|
371
380
|
}
|
372
381
|
|
373
|
-
std::string result(unquote(message->
|
382
|
+
std::string result(unquote(message->to_sass()));
|
383
|
+
ctx.c_options.output_style = outstyle;
|
374
384
|
error(result, e->pstate());
|
375
385
|
return 0;
|
376
386
|
}
|
377
387
|
|
378
388
|
Expression* Eval::operator()(Debug* d)
|
379
389
|
{
|
390
|
+
Sass_Output_Style outstyle = ctx.c_options.output_style;
|
391
|
+
ctx.c_options.output_style = NESTED;
|
380
392
|
Expression* message = d->value()->perform(this);
|
381
|
-
To_String to_string(&ctx, false, true);
|
382
393
|
Env* env = exp.environment();
|
383
394
|
|
384
395
|
// try to use generic function
|
@@ -394,6 +405,7 @@ namespace Sass {
|
|
394
405
|
union Sass_Value* c_args = sass_make_list(1, SASS_COMMA);
|
395
406
|
sass_list_set_value(c_args, 0, message->perform(&to_c));
|
396
407
|
union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_compiler);
|
408
|
+
ctx.c_options.output_style = outstyle;
|
397
409
|
sass_delete_value(c_args);
|
398
410
|
sass_delete_value(c_val);
|
399
411
|
return 0;
|
@@ -401,10 +413,11 @@ namespace Sass {
|
|
401
413
|
}
|
402
414
|
|
403
415
|
std::string cwd(ctx.cwd());
|
404
|
-
std::string result(unquote(message->
|
416
|
+
std::string result(unquote(message->to_sass()));
|
405
417
|
std::string abs_path(Sass::File::rel2abs(d->pstate().path, cwd, cwd));
|
406
418
|
std::string rel_path(Sass::File::abs2rel(d->pstate().path, cwd, cwd));
|
407
419
|
std::string output_path(Sass::File::path_for_console(rel_path, abs_path, d->pstate().path));
|
420
|
+
ctx.c_options.output_style = outstyle;
|
408
421
|
|
409
422
|
std::cerr << output_path << ":" << d->pstate().line+1 << " DEBUG: " << result;
|
410
423
|
std::cerr << std::endl;
|
@@ -413,7 +426,29 @@ namespace Sass {
|
|
413
426
|
|
414
427
|
Expression* Eval::operator()(List* l)
|
415
428
|
{
|
429
|
+
// special case for unevaluated map
|
430
|
+
if (l->separator() == SASS_HASH) {
|
431
|
+
Map* lm = SASS_MEMORY_NEW(ctx.mem, Map,
|
432
|
+
l->pstate(),
|
433
|
+
l->length() / 2);
|
434
|
+
for (size_t i = 0, L = l->length(); i < L; i += 2)
|
435
|
+
{
|
436
|
+
Expression* key = (*l)[i+0]->perform(this);
|
437
|
+
Expression* val = (*l)[i+1]->perform(this);
|
438
|
+
// make sure the color key never displays its real name
|
439
|
+
key->is_delayed(true);
|
440
|
+
*lm << std::make_pair(key, val);
|
441
|
+
}
|
442
|
+
if (lm->has_duplicate_key()) {
|
443
|
+
throw Exception::DuplicateKeyError(*lm, *l);
|
444
|
+
}
|
445
|
+
|
446
|
+
lm->is_interpolant(l->is_interpolant());
|
447
|
+
return lm->perform(this);
|
448
|
+
}
|
449
|
+
// check if we should expand it
|
416
450
|
if (l->is_expanded()) return l;
|
451
|
+
// regular case for unevaluated lists
|
417
452
|
List* ll = SASS_MEMORY_NEW(ctx.mem, List,
|
418
453
|
l->pstate(),
|
419
454
|
l->length(),
|
@@ -422,6 +457,7 @@ namespace Sass {
|
|
422
457
|
for (size_t i = 0, L = l->length(); i < L; ++i) {
|
423
458
|
*ll << (*l)[i]->perform(this);
|
424
459
|
}
|
460
|
+
ll->is_interpolant(l->is_interpolant());
|
425
461
|
ll->is_expanded(true);
|
426
462
|
return ll;
|
427
463
|
}
|
@@ -433,8 +469,7 @@ namespace Sass {
|
|
433
469
|
// make sure we're not starting with duplicate keys.
|
434
470
|
// the duplicate key state will have been set in the parser phase.
|
435
471
|
if (m->has_duplicate_key()) {
|
436
|
-
|
437
|
-
error("Duplicate key \"" + m->get_duplicate_key()->perform(&to_string) + "\" in map " + m->perform(&to_string) + ".", m->pstate());
|
472
|
+
throw Exception::DuplicateKeyError(*m, *m);
|
438
473
|
}
|
439
474
|
|
440
475
|
Map* mm = SASS_MEMORY_NEW(ctx.mem, Map,
|
@@ -448,8 +483,7 @@ namespace Sass {
|
|
448
483
|
|
449
484
|
// check the evaluated keys aren't duplicates.
|
450
485
|
if (mm->has_duplicate_key()) {
|
451
|
-
|
452
|
-
error("Duplicate key \"" + mm->get_duplicate_key()->perform(&to_string) + "\" in map " + m->perform(&to_string) + ".", mm->pstate());
|
486
|
+
throw Exception::DuplicateKeyError(*mm, *m);
|
453
487
|
}
|
454
488
|
|
455
489
|
mm->is_expanded(true);
|
@@ -458,33 +492,75 @@ namespace Sass {
|
|
458
492
|
|
459
493
|
Expression* Eval::operator()(Binary_Expression* b)
|
460
494
|
{
|
495
|
+
|
496
|
+
String_Schema* ret_schema = 0;
|
461
497
|
enum Sass_OP op_type = b->type();
|
498
|
+
|
462
499
|
// don't eval delayed expressions (the '/' when used as a separator)
|
463
|
-
if (op_type == Sass_OP::DIV && b->is_delayed())
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
500
|
+
if (op_type == Sass_OP::DIV && b->is_delayed()) {
|
501
|
+
b->right(b->right()->perform(this));
|
502
|
+
b->left(b->left()->perform(this));
|
503
|
+
return b;
|
504
|
+
}
|
505
|
+
|
506
|
+
// only the last item will be used to eval the binary expression
|
507
|
+
if (String_Schema* s_1 = dynamic_cast<String_Schema*>(b->left())) {
|
508
|
+
if (!s_1->is_right_interpolant()) {
|
509
|
+
ret_schema = SASS_MEMORY_NEW(ctx.mem, String_Schema, s_1->pstate());
|
510
|
+
Binary_Expression* bin_ex = SASS_MEMORY_NEW(ctx.mem, Binary_Expression, b->pstate(),
|
511
|
+
b->op(), s_1->last(), b->right());
|
512
|
+
bin_ex->is_delayed(b->left()->is_delayed() || b->right()->is_delayed());
|
513
|
+
// bin_ex->is_interpolant(b->left()->is_interpolant());
|
514
|
+
for (size_t i = 0; i < s_1->length() - 1; ++i) {
|
515
|
+
*ret_schema << s_1->at(i)->perform(this);
|
516
|
+
}
|
517
|
+
*ret_schema << bin_ex->perform(this);
|
518
|
+
return ret_schema->perform(this);
|
519
|
+
}
|
520
|
+
}
|
521
|
+
if (String_Schema* s_r = dynamic_cast<String_Schema*>(b->right())) {
|
522
|
+
if (!s_r->is_left_interpolant() || op_type == Sass_OP::DIV) {
|
523
|
+
ret_schema = SASS_MEMORY_NEW(ctx.mem, String_Schema, s_r->pstate());
|
524
|
+
Binary_Expression* bin_ex = SASS_MEMORY_NEW(ctx.mem, Binary_Expression, b->pstate(),
|
525
|
+
b->op(), b->left(), s_r->first());
|
526
|
+
bin_ex->is_delayed(b->left()->is_delayed() || b->right()->is_delayed());
|
527
|
+
// if (op_type == Sass_OP::SUB && b->is_right_interpolant()) bin_ex->is_interpolant(true);
|
528
|
+
*ret_schema << bin_ex->perform(this);
|
529
|
+
for (size_t i = 1; i < s_r->length(); ++i) {
|
530
|
+
*ret_schema << s_r->at(i)->perform(this);
|
531
|
+
}
|
532
|
+
return ret_schema->perform(this);
|
533
|
+
}
|
472
534
|
}
|
473
535
|
|
474
|
-
switch (op_type) {
|
475
|
-
case Sass_OP::AND:
|
476
|
-
return *lhs ? b->right()->perform(this) : lhs;
|
477
|
-
break;
|
478
536
|
|
479
|
-
|
480
|
-
|
481
|
-
|
537
|
+
// don't eval delayed expressions (the '/' when used as a separator)
|
538
|
+
if (op_type == Sass_OP::DIV && b->is_delayed()) {
|
539
|
+
b->right(b->right()->perform(this));
|
540
|
+
b->left(b->left()->perform(this));
|
541
|
+
return b;
|
542
|
+
}
|
482
543
|
|
483
|
-
|
484
|
-
|
544
|
+
// b->is_delayed(false);
|
545
|
+
Expression* lhs = b->left();
|
546
|
+
Expression* rhs = b->right();
|
547
|
+
|
548
|
+
// bool delay_lhs = false;
|
549
|
+
// bool delay_rhs = false;
|
550
|
+
|
551
|
+
if (String_Schema* schema = dynamic_cast<String_Schema*>(lhs)) {
|
552
|
+
if (schema->is_right_interpolant()) {
|
553
|
+
b->is_delayed(true);
|
554
|
+
// delay_lhs = true;
|
555
|
+
}
|
485
556
|
}
|
486
|
-
|
487
|
-
|
557
|
+
if (String_Schema* schema = dynamic_cast<String_Schema*>(rhs)) {
|
558
|
+
if (schema->is_left_interpolant()) {
|
559
|
+
b->is_delayed(true);
|
560
|
+
// delay_rhs = true;
|
561
|
+
}
|
562
|
+
}
|
563
|
+
|
488
564
|
// maybe fully evaluate structure
|
489
565
|
if (op_type == Sass_OP::EQ ||
|
490
566
|
op_type == Sass_OP::NEQ ||
|
@@ -493,6 +569,26 @@ namespace Sass {
|
|
493
569
|
op_type == Sass_OP::LT ||
|
494
570
|
op_type == Sass_OP::LTE)
|
495
571
|
{
|
572
|
+
|
573
|
+
if (String_Schema* schema = dynamic_cast<String_Schema*>(lhs)) {
|
574
|
+
if (schema->has_interpolants()) {
|
575
|
+
b->is_delayed(true);
|
576
|
+
}
|
577
|
+
}
|
578
|
+
if (String_Schema* schema = dynamic_cast<String_Schema*>(rhs)) {
|
579
|
+
if (schema->has_interpolants()) {
|
580
|
+
b->is_delayed(true);
|
581
|
+
}
|
582
|
+
}
|
583
|
+
lhs->is_expanded(false);
|
584
|
+
lhs->set_delayed(false);
|
585
|
+
lhs = lhs->perform(this);
|
586
|
+
lhs->is_expanded(false);
|
587
|
+
lhs->set_delayed(false);
|
588
|
+
lhs = lhs->perform(this);
|
589
|
+
rhs->is_expanded(false);
|
590
|
+
rhs->set_delayed(false);
|
591
|
+
rhs = rhs->perform(this);
|
496
592
|
rhs->is_expanded(false);
|
497
593
|
rhs->set_delayed(false);
|
498
594
|
rhs = rhs->perform(this);
|
@@ -503,6 +599,30 @@ namespace Sass {
|
|
503
599
|
// rhs = rhs->perform(this);
|
504
600
|
}
|
505
601
|
|
602
|
+
// if one of the operands is a '/' then make sure it's evaluated
|
603
|
+
lhs = lhs->perform(this);
|
604
|
+
lhs->is_delayed(false);
|
605
|
+
while (typeid(*lhs) == typeid(Binary_Expression)) {
|
606
|
+
Binary_Expression* lhs_ex = static_cast<Binary_Expression*>(lhs);
|
607
|
+
if (lhs_ex->type() == Sass_OP::DIV && lhs_ex->is_delayed()) break;
|
608
|
+
lhs = Eval::operator()(lhs_ex);
|
609
|
+
}
|
610
|
+
|
611
|
+
switch (op_type) {
|
612
|
+
case Sass_OP::AND:
|
613
|
+
return *lhs ? b->right()->perform(this) : lhs;
|
614
|
+
break;
|
615
|
+
|
616
|
+
case Sass_OP::OR:
|
617
|
+
return *lhs ? lhs : b->right()->perform(this);
|
618
|
+
break;
|
619
|
+
|
620
|
+
default:
|
621
|
+
break;
|
622
|
+
}
|
623
|
+
// not a logical connective, so go ahead and eval the rhs
|
624
|
+
rhs = rhs->perform(this);
|
625
|
+
|
506
626
|
// upgrade string to number if possible (issue #948)
|
507
627
|
if (op_type == Sass_OP::DIV || op_type == Sass_OP::MUL) {
|
508
628
|
if (String_Constant* str = dynamic_cast<String_Constant*>(rhs)) {
|
@@ -515,18 +635,6 @@ namespace Sass {
|
|
515
635
|
}
|
516
636
|
}
|
517
637
|
|
518
|
-
// see if it's a relational expression
|
519
|
-
switch(op_type) {
|
520
|
-
case Sass_OP::EQ: return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), eq(lhs, rhs));
|
521
|
-
case Sass_OP::NEQ: return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), !eq(lhs, rhs));
|
522
|
-
case Sass_OP::GT: return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), !lt(lhs, rhs) && !eq(lhs, rhs));
|
523
|
-
case Sass_OP::GTE: return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), !lt(lhs, rhs));
|
524
|
-
case Sass_OP::LT: return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), lt(lhs, rhs));
|
525
|
-
case Sass_OP::LTE: return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), lt(lhs, rhs) || eq(lhs, rhs));
|
526
|
-
|
527
|
-
default: break;
|
528
|
-
}
|
529
|
-
|
530
638
|
|
531
639
|
Expression::Concrete_Type l_type = lhs->concrete_type();
|
532
640
|
Expression::Concrete_Type r_type = rhs->concrete_type();
|
@@ -534,23 +642,25 @@ namespace Sass {
|
|
534
642
|
// Is one of the operands an interpolant?
|
535
643
|
String_Schema* s1 = dynamic_cast<String_Schema*>(b->left());
|
536
644
|
String_Schema* s2 = dynamic_cast<String_Schema*>(b->right());
|
645
|
+
Binary_Expression* b1 = dynamic_cast<Binary_Expression*>(b->left());
|
646
|
+
Binary_Expression* b2 = dynamic_cast<Binary_Expression*>(b->right());
|
537
647
|
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
case Sass_OP::MUL: sep = "*"; break;
|
545
|
-
default: break;
|
546
|
-
}
|
648
|
+
bool schema_op = false;
|
649
|
+
|
650
|
+
bool force_delay = (s2 && s2->is_left_interpolant()) ||
|
651
|
+
(s1 && s1->is_right_interpolant()) ||
|
652
|
+
(b1 && b1->is_right_interpolant()) ||
|
653
|
+
(b2 && b2->is_left_interpolant());
|
547
654
|
|
655
|
+
if ((s1 && s1->has_interpolants()) || (s2 && s2->has_interpolants()) || force_delay)
|
656
|
+
{
|
548
657
|
// If possible upgrade LHS to a number
|
549
|
-
if (op_type == Sass_OP::DIV || op_type == Sass_OP::MUL || op_type == Sass_OP::ADD || op_type == Sass_OP::SUB
|
658
|
+
if (op_type == Sass_OP::DIV || op_type == Sass_OP::MUL || op_type == Sass_OP::MOD || op_type == Sass_OP::ADD || op_type == Sass_OP::SUB ||
|
659
|
+
op_type == Sass_OP::EQ) {
|
550
660
|
if (String_Constant* str = dynamic_cast<String_Constant*>(lhs)) {
|
551
661
|
std::string value(str->value());
|
552
662
|
const char* start = value.c_str();
|
553
|
-
if (Prelexer::sequence < Prelexer::
|
663
|
+
if (Prelexer::sequence < Prelexer::dimension, Prelexer::end_of_file >(start) != 0) {
|
554
664
|
lhs = SASS_MEMORY_NEW(ctx.mem, Textual, lhs->pstate(), Textual::DIMENSION, str->value());
|
555
665
|
lhs->is_delayed(false); lhs = lhs->perform(this);
|
556
666
|
}
|
@@ -568,54 +678,118 @@ namespace Sass {
|
|
568
678
|
To_Value to_value(ctx, ctx.mem);
|
569
679
|
Value* v_l = dynamic_cast<Value*>(lhs->perform(&to_value));
|
570
680
|
Value* v_r = dynamic_cast<Value*>(rhs->perform(&to_value));
|
571
|
-
|
572
|
-
|
681
|
+
l_type = lhs->concrete_type();
|
682
|
+
r_type = rhs->concrete_type();
|
683
|
+
|
684
|
+
if (s2 && s2->has_interpolants() && s2->length()) {
|
685
|
+
Textual* front = dynamic_cast<Textual*>(s2->elements().front());
|
686
|
+
if (front && !front->is_interpolant())
|
687
|
+
{
|
688
|
+
// XXX: this is never hit via spec tests
|
689
|
+
schema_op = true;
|
690
|
+
rhs = front->perform(this);
|
691
|
+
}
|
692
|
+
}
|
573
693
|
|
574
|
-
|
575
|
-
|
576
|
-
|
694
|
+
if (force_delay) {
|
695
|
+
std::string str("");
|
696
|
+
str += v_l->to_string(ctx.c_options);
|
697
|
+
if (b->op().ws_before) str += " ";
|
698
|
+
str += b->separator();
|
699
|
+
if (b->op().ws_after) str += " ";
|
700
|
+
str += v_r->to_string(ctx.c_options);
|
701
|
+
String_Constant* val = SASS_MEMORY_NEW(ctx.mem, String_Constant, lhs->pstate(), str);
|
702
|
+
val->is_interpolant(b->left()->has_interpolant());
|
703
|
+
return val;
|
704
|
+
}
|
705
|
+
}
|
706
|
+
|
707
|
+
// see if it's a relational expression
|
708
|
+
try {
|
709
|
+
switch(op_type) {
|
710
|
+
case Sass_OP::EQ: return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), eq(lhs, rhs));
|
711
|
+
case Sass_OP::NEQ: return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), !eq(lhs, rhs));
|
712
|
+
case Sass_OP::GT: return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), !lt(lhs, rhs, "gt") && !eq(lhs, rhs));
|
713
|
+
case Sass_OP::GTE: return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), !lt(lhs, rhs, "gte"));
|
714
|
+
case Sass_OP::LT: return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), lt(lhs, rhs, "lt"));
|
715
|
+
case Sass_OP::LTE: return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), lt(lhs, rhs, "lte") || eq(lhs, rhs));
|
716
|
+
default: break;
|
577
717
|
}
|
578
718
|
}
|
719
|
+
catch (Exception::OperationError& err)
|
720
|
+
{
|
721
|
+
// throw Exception::Base(b->pstate(), err.what());
|
722
|
+
throw Exception::SassValueError(b->pstate(), err);
|
723
|
+
}
|
724
|
+
|
725
|
+
l_type = lhs->concrete_type();
|
726
|
+
r_type = rhs->concrete_type();
|
579
727
|
|
580
728
|
// ToDo: throw error in op functions
|
581
729
|
// ToDo: then catch and re-throw them
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
730
|
+
Expression* rv = 0;
|
731
|
+
try {
|
732
|
+
ParserState pstate(b->pstate());
|
733
|
+
if (l_type == Expression::NUMBER && r_type == Expression::NUMBER) {
|
734
|
+
const Number* l_n = dynamic_cast<const Number*>(lhs);
|
735
|
+
const Number* r_n = dynamic_cast<const Number*>(rhs);
|
736
|
+
rv = op_numbers(ctx.mem, op_type, *l_n, *r_n, ctx.c_options, &pstate);
|
737
|
+
}
|
738
|
+
else if (l_type == Expression::NUMBER && r_type == Expression::COLOR) {
|
739
|
+
const Number* l_n = dynamic_cast<const Number*>(lhs);
|
740
|
+
const Color* r_c = dynamic_cast<const Color*>(rhs);
|
741
|
+
rv = op_number_color(ctx.mem, op_type, *l_n, *r_c, ctx.c_options, &pstate);
|
742
|
+
}
|
743
|
+
else if (l_type == Expression::COLOR && r_type == Expression::NUMBER) {
|
744
|
+
const Color* l_c = dynamic_cast<const Color*>(lhs);
|
745
|
+
const Number* r_n = dynamic_cast<const Number*>(rhs);
|
746
|
+
rv = op_color_number(ctx.mem, op_type, *l_c, *r_n, ctx.c_options, &pstate);
|
747
|
+
}
|
748
|
+
else if (l_type == Expression::COLOR && r_type == Expression::COLOR) {
|
749
|
+
const Color* l_c = dynamic_cast<const Color*>(lhs);
|
750
|
+
const Color* r_c = dynamic_cast<const Color*>(rhs);
|
751
|
+
rv = op_colors(ctx.mem, op_type, *l_c, *r_c, ctx.c_options, &pstate);
|
752
|
+
}
|
753
|
+
else {
|
754
|
+
To_Value to_value(ctx, ctx.mem);
|
755
|
+
Value* v_l = dynamic_cast<Value*>(lhs->perform(&to_value));
|
756
|
+
Value* v_r = dynamic_cast<Value*>(rhs->perform(&to_value));
|
757
|
+
bool interpolant = b->is_right_interpolant() ||
|
758
|
+
b->is_left_interpolant() ||
|
759
|
+
b->is_interpolant();
|
760
|
+
if (op_type == Sass_OP::SUB) interpolant = false;
|
761
|
+
// if (op_type == Sass_OP::DIV) interpolant = true;
|
762
|
+
Value* ex = op_strings(ctx.mem, b->op(), *v_l, *v_r, ctx.c_options, &pstate, !interpolant); // pass true to compress
|
763
|
+
if (String_Constant* str = dynamic_cast<String_Constant*>(ex))
|
764
|
+
{
|
765
|
+
if (str->concrete_type() == Expression::STRING)
|
766
|
+
{
|
767
|
+
String_Constant* lstr = dynamic_cast<String_Constant*>(lhs);
|
768
|
+
String_Constant* rstr = dynamic_cast<String_Constant*>(rhs);
|
769
|
+
if (op_type != Sass_OP::SUB) {
|
770
|
+
if (String_Constant* org = lstr ? lstr : rstr)
|
771
|
+
{ str->quote_mark(org->quote_mark()); }
|
772
|
+
}
|
773
|
+
}
|
774
|
+
}
|
775
|
+
ex->is_interpolant(b->is_interpolant());
|
776
|
+
rv = ex;
|
777
|
+
}
|
778
|
+
}
|
779
|
+
catch (Exception::OperationError& err)
|
611
780
|
{
|
612
|
-
|
613
|
-
|
614
|
-
String_Constant* rstr = dynamic_cast<String_Constant*>(rhs);
|
615
|
-
if (String_Constant* org = lstr ? lstr : rstr)
|
616
|
-
{ str->quote_mark(org->quote_mark()); }
|
781
|
+
// throw Exception::Base(b->pstate(), err.what());
|
782
|
+
throw Exception::SassValueError(b->pstate(), err);
|
617
783
|
}
|
618
|
-
|
784
|
+
|
785
|
+
if (rv) {
|
786
|
+
if (schema_op) {
|
787
|
+
// XXX: this is never hit via spec tests
|
788
|
+
(*s2)[0] = rv;
|
789
|
+
rv = s2->perform(this);
|
790
|
+
}
|
791
|
+
}
|
792
|
+
return rv;
|
619
793
|
|
620
794
|
}
|
621
795
|
|
@@ -635,16 +809,15 @@ namespace Sass {
|
|
635
809
|
return result;
|
636
810
|
}
|
637
811
|
else {
|
638
|
-
To_String to_string(&ctx);
|
639
812
|
// Special cases: +/- variables which evaluate to null ouput just +/-,
|
640
813
|
// but +/- null itself outputs the string
|
641
|
-
if (operand->concrete_type() == Expression::NULL_VAL &&
|
814
|
+
if (operand->concrete_type() == Expression::NULL_VAL && dynamic_cast<Variable*>(u->operand())) {
|
642
815
|
u->operand(SASS_MEMORY_NEW(ctx.mem, String_Quoted, u->pstate(), ""));
|
643
816
|
}
|
644
817
|
else u->operand(operand);
|
645
818
|
String_Constant* result = SASS_MEMORY_NEW(ctx.mem, String_Quoted,
|
646
819
|
u->pstate(),
|
647
|
-
u->
|
820
|
+
u->inspect());
|
648
821
|
return result;
|
649
822
|
}
|
650
823
|
// unreachable
|
@@ -654,6 +827,7 @@ namespace Sass {
|
|
654
827
|
Expression* Eval::operator()(Function_Call* c)
|
655
828
|
{
|
656
829
|
if (backtrace()->parent != NULL && backtrace()->depth() > Constants::MaxCallStack) {
|
830
|
+
// XXX: this is never hit via spec tests
|
657
831
|
std::ostringstream stm;
|
658
832
|
stm << "Stack depth exceeded max of " << Constants::MaxCallStack;
|
659
833
|
error(stm.str(), c->pstate(), backtrace());
|
@@ -673,13 +847,14 @@ namespace Sass {
|
|
673
847
|
c->pstate(),
|
674
848
|
c->name(),
|
675
849
|
args);
|
676
|
-
To_String to_string(&ctx);
|
677
850
|
if (args->has_named_arguments()) {
|
678
851
|
error("Function " + c->name() + " doesn't support keyword arguments", c->pstate());
|
679
852
|
}
|
680
|
-
|
681
|
-
|
682
|
-
|
853
|
+
String_Quoted* str = SASS_MEMORY_NEW(ctx.mem, String_Quoted,
|
854
|
+
c->pstate(),
|
855
|
+
lit->to_string(ctx.c_options));
|
856
|
+
str->is_interpolant(c->is_interpolant());
|
857
|
+
return str;
|
683
858
|
} else {
|
684
859
|
// call generic function
|
685
860
|
full_name = "*[f]";
|
@@ -711,10 +886,9 @@ namespace Sass {
|
|
711
886
|
bind(std::string("Function"), c->name(), params, args, &ctx, &fn_env, this);
|
712
887
|
Backtrace here(backtrace(), c->pstate(), ", in function `" + c->name() + "`");
|
713
888
|
exp.backtrace_stack.push_back(&here);
|
714
|
-
// if
|
715
|
-
if (body) result = body->perform(this);
|
716
|
-
|
717
|
-
else result = func(fn_env, *env, ctx, def->signature(), c->pstate(), backtrace());
|
889
|
+
// eval the body if user-defined or special, invoke underlying CPP function if native
|
890
|
+
if (body && !Prelexer::re_special_fun(c->name().c_str())) { result = body->perform(this); }
|
891
|
+
else if (func) { result = func(fn_env, *env, ctx, def->signature(), c->pstate(), backtrace()); }
|
718
892
|
if (!result) error(std::string("Function ") + c->name() + " did not return a value", c->pstate());
|
719
893
|
exp.backtrace_stack.pop_back();
|
720
894
|
}
|
@@ -767,6 +941,7 @@ namespace Sass {
|
|
767
941
|
|
768
942
|
result->is_delayed(result->concrete_type() == Expression::STRING);
|
769
943
|
if (!result->is_delayed()) result = result->perform(this);
|
944
|
+
result->is_interpolant(c->is_interpolant());
|
770
945
|
exp.env_stack.pop_back();
|
771
946
|
return result;
|
772
947
|
}
|
@@ -782,13 +957,11 @@ namespace Sass {
|
|
782
957
|
|
783
958
|
Expression* Eval::operator()(Variable* v)
|
784
959
|
{
|
785
|
-
To_String to_string(&ctx);
|
786
960
|
std::string name(v->name());
|
787
961
|
Expression* value = 0;
|
788
962
|
Env* env = environment();
|
789
963
|
if (env->has(name)) value = static_cast<Expression*>((*env)[name]);
|
790
964
|
else error("Undefined variable: \"" + v->name() + "\".", v->pstate());
|
791
|
-
// std::cerr << "name: " << v->name() << "; type: " << typeid(*value).name() << "; value: " << value->perform(&to_string) << std::endl;
|
792
965
|
if (typeid(*value) == typeid(Argument)) value = static_cast<Argument*>(value)->value();
|
793
966
|
|
794
967
|
// behave according to as ruby sass (add leading zero)
|
@@ -800,7 +973,7 @@ namespace Sass {
|
|
800
973
|
if (auto str = dynamic_cast<String_Quoted*>(value)) {
|
801
974
|
value = SASS_MEMORY_NEW(ctx.mem, String_Quoted, *str);
|
802
975
|
} else if (auto str = dynamic_cast<String_Constant*>(value)) {
|
803
|
-
value = SASS_MEMORY_NEW(ctx.mem, String_Quoted, str->pstate(), str->
|
976
|
+
value = SASS_MEMORY_NEW(ctx.mem, String_Quoted, str->pstate(), str->value());
|
804
977
|
}
|
805
978
|
}
|
806
979
|
else if (value->concrete_type() == Expression::LIST) {
|
@@ -822,16 +995,21 @@ namespace Sass {
|
|
822
995
|
value = value->perform(this); // ->perform(&listize);
|
823
996
|
}
|
824
997
|
|
825
|
-
|
826
|
-
|
998
|
+
value->is_interpolant(v->is_interpolant());
|
999
|
+
value->is_expanded(false);
|
1000
|
+
return value->perform(this);
|
827
1001
|
}
|
828
1002
|
|
829
1003
|
Expression* Eval::operator()(Textual* t)
|
830
1004
|
{
|
831
1005
|
using Prelexer::number;
|
832
1006
|
Expression* result = 0;
|
833
|
-
|
834
|
-
|
1007
|
+
size_t L = t->value().length();
|
1008
|
+
bool zero = !( (L > 0 && t->value().substr(0, 1) == ".") ||
|
1009
|
+
(L > 1 && t->value().substr(0, 2) == "0.") ||
|
1010
|
+
(L > 1 && t->value().substr(0, 2) == "-.") ||
|
1011
|
+
(L > 2 && t->value().substr(0, 3) == "-0.")
|
1012
|
+
);
|
835
1013
|
|
836
1014
|
const std::string& text = t->value();
|
837
1015
|
size_t num_pos = text.find_first_not_of(" \n\r\t");
|
@@ -854,7 +1032,7 @@ namespace Sass {
|
|
854
1032
|
t->pstate(),
|
855
1033
|
sass_atof(num.c_str()),
|
856
1034
|
"%",
|
857
|
-
|
1035
|
+
true);
|
858
1036
|
break;
|
859
1037
|
case Textual::DIMENSION:
|
860
1038
|
result = SASS_MEMORY_NEW(ctx.mem, Number,
|
@@ -878,7 +1056,7 @@ namespace Sass {
|
|
878
1056
|
static_cast<double>(strtol(r.c_str(), NULL, 16)),
|
879
1057
|
static_cast<double>(strtol(g.c_str(), NULL, 16)),
|
880
1058
|
static_cast<double>(strtol(b.c_str(), NULL, 16)),
|
881
|
-
1,
|
1059
|
+
1, // alpha channel
|
882
1060
|
t->value());
|
883
1061
|
}
|
884
1062
|
else {
|
@@ -887,11 +1065,12 @@ namespace Sass {
|
|
887
1065
|
static_cast<double>(strtol(std::string(2,hext[0]).c_str(), NULL, 16)),
|
888
1066
|
static_cast<double>(strtol(std::string(2,hext[1]).c_str(), NULL, 16)),
|
889
1067
|
static_cast<double>(strtol(std::string(2,hext[2]).c_str(), NULL, 16)),
|
890
|
-
1,
|
1068
|
+
1, // alpha channel
|
891
1069
|
t->value());
|
892
1070
|
}
|
893
1071
|
} break;
|
894
1072
|
}
|
1073
|
+
result->is_interpolant(t->is_interpolant());
|
895
1074
|
return result;
|
896
1075
|
}
|
897
1076
|
|
@@ -905,139 +1084,113 @@ namespace Sass {
|
|
905
1084
|
return b;
|
906
1085
|
}
|
907
1086
|
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
if (
|
913
|
-
|
1087
|
+
void Eval::interpolation(Context& ctx, std::string& res, Expression* ex, bool into_quotes, bool was_itpl) {
|
1088
|
+
|
1089
|
+
bool needs_closing_brace = false;
|
1090
|
+
//debug_ast(ex);
|
1091
|
+
if (Arguments* args = dynamic_cast<Arguments*>(ex)) {
|
1092
|
+
List* ll = SASS_MEMORY_NEW(ctx.mem, List, args->pstate(), 0, SASS_COMMA);
|
1093
|
+
for(auto arg : *args) {
|
1094
|
+
*ll << arg->value();
|
1095
|
+
}
|
1096
|
+
ll->is_interpolant(args->is_interpolant());
|
1097
|
+
needs_closing_brace = true;
|
1098
|
+
res += "(";
|
1099
|
+
ex = ll;
|
1100
|
+
}
|
1101
|
+
if (Number* nr = dynamic_cast<Number*>(ex)) {
|
1102
|
+
if (!nr->is_valid_css_unit()) {
|
1103
|
+
throw Exception::InvalidValue(*nr);
|
1104
|
+
}
|
914
1105
|
}
|
915
|
-
|
916
|
-
|
1106
|
+
if (Argument* arg = dynamic_cast<Argument*>(ex)) {
|
1107
|
+
ex = arg->value();
|
1108
|
+
}
|
1109
|
+
if (String_Quoted* sq = dynamic_cast<String_Quoted*>(ex)) {
|
1110
|
+
if (was_itpl) {
|
1111
|
+
bool was_interpolant = ex->is_interpolant();
|
1112
|
+
ex = SASS_MEMORY_NEW(ctx.mem, String_Constant, sq->pstate(), sq->value());
|
1113
|
+
ex->is_interpolant(was_interpolant);
|
1114
|
+
}
|
917
1115
|
}
|
918
|
-
}
|
919
1116
|
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
1117
|
+
if (dynamic_cast<Null*>(ex)) { return; }
|
1118
|
+
|
1119
|
+
// parent selector needs another go
|
1120
|
+
if (dynamic_cast<Parent_Selector*>(ex)) {
|
1121
|
+
// XXX: this is never hit via spec tests
|
1122
|
+
ex = ex->perform(this);
|
1123
|
+
}
|
1124
|
+
|
1125
|
+
if (List* l = dynamic_cast<List*>(ex)) {
|
1126
|
+
List* ll = SASS_MEMORY_NEW(ctx.mem, List, l->pstate(), 0, l->separator());
|
1127
|
+
// this fixes an issue with bourbon sample, not really sure why
|
1128
|
+
if (l->size() && dynamic_cast<Null*>((*l)[0])) { res += " "; }
|
1129
|
+
for(auto item : *l) {
|
1130
|
+
item->is_interpolant(l->is_interpolant());
|
1131
|
+
std::string rl(""); interpolation(ctx, rl, item, into_quotes, l->is_interpolant());
|
1132
|
+
if (rl != "") *ll << SASS_MEMORY_NEW(ctx.mem, String_Quoted, item->pstate(), rl);
|
931
1133
|
}
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
auto esc = evacuate_escapes(res);
|
949
|
-
auto unq = unquote(esc);
|
950
|
-
if (unq == esc) {
|
951
|
-
return string_to_output(res);
|
1134
|
+
res += (ll->to_string(ctx.c_options));
|
1135
|
+
ll->is_interpolant(l->is_interpolant());
|
1136
|
+
}
|
1137
|
+
|
1138
|
+
// Value
|
1139
|
+
// Textual
|
1140
|
+
// Function_Call
|
1141
|
+
// Selector_List
|
1142
|
+
// String_Quoted
|
1143
|
+
// String_Constant
|
1144
|
+
// Parent_Selector
|
1145
|
+
// Binary_Expression
|
1146
|
+
else {
|
1147
|
+
// ex = ex->perform(this);
|
1148
|
+
if (into_quotes && ex->is_interpolant()) {
|
1149
|
+
res += evacuate_escapes(ex ? ex->to_string(ctx.c_options) : "");
|
952
1150
|
} else {
|
953
|
-
|
1151
|
+
res += ex ? ex->to_string(ctx.c_options) : "";
|
954
1152
|
}
|
955
|
-
} else if (List* list = dynamic_cast<List*>(s)) {
|
956
|
-
std::string acc = ""; // ToDo: different output styles
|
957
|
-
std::string sep = list->separator() == SASS_COMMA ? "," : " ";
|
958
|
-
if (ctx.output_style() != SASS_STYLE_COMPRESSED && sep == ",") sep += " ";
|
959
|
-
bool initial = false;
|
960
|
-
for(auto item : list->elements()) {
|
961
|
-
if (item->concrete_type() != Expression::NULL_VAL) {
|
962
|
-
if (initial) acc += sep;
|
963
|
-
acc += interpolation(item);
|
964
|
-
initial = true;
|
965
|
-
}
|
966
|
-
}
|
967
|
-
return evacuate_quotes(acc);
|
968
|
-
} else if (Variable* var = dynamic_cast<Variable*>(s)) {
|
969
|
-
std::string name(var->name());
|
970
|
-
if (!env->has(name)) error("Undefined variable: \"" + var->name() + "\".", var->pstate());
|
971
|
-
Expression* value = static_cast<Expression*>((*env)[name]);
|
972
|
-
return evacuate_quotes(interpolation(value));
|
973
|
-
} else if (dynamic_cast<Binary_Expression*>(s)) {
|
974
|
-
Expression* ex = s->perform(this);
|
975
|
-
// avoid recursive calls if same object gets returned
|
976
|
-
// since we will call interpolate again for the result
|
977
|
-
if (ex == s) {
|
978
|
-
To_String to_string(&ctx);
|
979
|
-
return evacuate_quotes(s->perform(&to_string));
|
980
|
-
}
|
981
|
-
return evacuate_quotes(interpolation(ex));
|
982
|
-
} else if (dynamic_cast<Function_Call*>(s)) {
|
983
|
-
Expression* ex = s->perform(this);
|
984
|
-
return evacuate_quotes(unquote(interpolation(ex)));
|
985
|
-
} else if (dynamic_cast<Unary_Expression*>(s)) {
|
986
|
-
Expression* ex = s->perform(this);
|
987
|
-
return evacuate_quotes(interpolation(ex));
|
988
|
-
} else if (dynamic_cast<Map*>(s)) {
|
989
|
-
To_String to_string(&ctx);
|
990
|
-
std::string dbg(s->perform(&to_string));
|
991
|
-
error(dbg + " isn't a valid CSS value.", s->pstate());
|
992
|
-
return dbg;
|
993
|
-
} else {
|
994
|
-
To_String to_string(&ctx);
|
995
|
-
return evacuate_quotes(s->perform(&to_string));
|
996
1153
|
}
|
1154
|
+
|
1155
|
+
if (needs_closing_brace) res += ")";
|
1156
|
+
|
997
1157
|
}
|
998
1158
|
|
999
1159
|
Expression* Eval::operator()(String_Schema* s)
|
1000
1160
|
{
|
1001
|
-
std::string acc;
|
1002
|
-
bool into_quotes = false;
|
1003
1161
|
size_t L = s->length();
|
1162
|
+
bool into_quotes = false;
|
1004
1163
|
if (L > 1) {
|
1164
|
+
if (!dynamic_cast<String_Quoted*>((*s)[0]) && !dynamic_cast<String_Quoted*>((*s)[L - 1])) {
|
1005
1165
|
if (String_Constant* l = dynamic_cast<String_Constant*>((*s)[0])) {
|
1006
1166
|
if (String_Constant* r = dynamic_cast<String_Constant*>((*s)[L - 1])) {
|
1007
1167
|
if (l->value()[0] == '"' && r->value()[r->value().size() - 1] == '"') into_quotes = true;
|
1008
1168
|
if (l->value()[0] == '\'' && r->value()[r->value().size() - 1] == '\'') into_quotes = true;
|
1009
1169
|
}
|
1010
1170
|
}
|
1171
|
+
}
|
1011
1172
|
}
|
1173
|
+
std::string res("");
|
1012
1174
|
for (size_t i = 0; i < L; ++i) {
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
Expression* ex = (*s)[i]->perform(this);
|
1018
|
-
if (auto sq = dynamic_cast<String_Quoted*>(ex)) {
|
1019
|
-
if (sq->is_delayed() && ! s->has_interpolants()) {
|
1020
|
-
acc += string_escape(quote(sq->value(), sq->quote_mark()));
|
1021
|
-
} else {
|
1022
|
-
acc += interpolation((*s)[i], into_quotes);
|
1023
|
-
}
|
1024
|
-
} else if (ex) {
|
1025
|
-
acc += interpolation((*s)[i], into_quotes);
|
1026
|
-
}
|
1027
|
-
} else if ((*s)[i]) {
|
1028
|
-
acc += interpolation((*s)[i], into_quotes);
|
1029
|
-
}
|
1175
|
+
(*s)[i]->perform(this);
|
1176
|
+
Expression* ex = (*s)[i]->is_delayed() ? (*s)[i] : (*s)[i]->perform(this);
|
1177
|
+
interpolation(ctx, res, ex, into_quotes, ex->is_interpolant());
|
1178
|
+
|
1030
1179
|
}
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
} else if (str->quote_mark()) {
|
1035
|
-
str->quote_mark('*');
|
1180
|
+
if (!s->is_interpolant()) {
|
1181
|
+
if (res == "") return SASS_MEMORY_NEW(ctx.mem, Null, s->pstate());
|
1182
|
+
return SASS_MEMORY_NEW(ctx.mem, String_Constant, s->pstate(), res);
|
1036
1183
|
}
|
1037
|
-
str->
|
1184
|
+
String_Quoted* str = SASS_MEMORY_NEW(ctx.mem, String_Quoted, s->pstate(), res);
|
1185
|
+
// if (s->is_interpolant()) str->quote_mark(0);
|
1186
|
+
// String_Constant* str = SASS_MEMORY_NEW(ctx.mem, String_Constant, s->pstate(), res);
|
1187
|
+
if (str->quote_mark()) str->quote_mark('*');
|
1188
|
+
else if (!is_in_comment) str->value(string_to_output(str->value()));
|
1189
|
+
str->is_interpolant(s->is_interpolant());
|
1038
1190
|
return str;
|
1039
1191
|
}
|
1040
1192
|
|
1193
|
+
|
1041
1194
|
Expression* Eval::operator()(String_Constant* s)
|
1042
1195
|
{
|
1043
1196
|
if (!s->is_delayed() && name_to_color(s->value())) {
|
@@ -1051,7 +1204,11 @@ namespace Sass {
|
|
1051
1204
|
|
1052
1205
|
Expression* Eval::operator()(String_Quoted* s)
|
1053
1206
|
{
|
1054
|
-
|
1207
|
+
String_Quoted* str = SASS_MEMORY_NEW(ctx.mem, String_Quoted, s->pstate(), "");
|
1208
|
+
str->value(s->value());
|
1209
|
+
str->quote_mark(s->quote_mark());
|
1210
|
+
str->is_interpolant(s->is_interpolant());
|
1211
|
+
return str;
|
1055
1212
|
}
|
1056
1213
|
|
1057
1214
|
Expression* Eval::operator()(Supports_Operator* c)
|
@@ -1111,7 +1268,6 @@ namespace Sass {
|
|
1111
1268
|
|
1112
1269
|
Expression* Eval::operator()(Media_Query* q)
|
1113
1270
|
{
|
1114
|
-
To_String to_string(&ctx);
|
1115
1271
|
String* t = q->media_type();
|
1116
1272
|
t = static_cast<String*>(t ? t->perform(this) : 0);
|
1117
1273
|
Media_Query* qq = SASS_MEMORY_NEW(ctx.mem, Media_Query,
|
@@ -1138,6 +1294,7 @@ namespace Sass {
|
|
1138
1294
|
Expression* value = e->value();
|
1139
1295
|
value = (value ? value->perform(this) : 0);
|
1140
1296
|
if (value && dynamic_cast<String_Quoted*>(value)) {
|
1297
|
+
// XXX: this is never hit via spec tests
|
1141
1298
|
value = SASS_MEMORY_NEW(ctx.mem, String_Quoted,
|
1142
1299
|
value->pstate(),
|
1143
1300
|
dynamic_cast<String_Quoted*>(value)->value());
|
@@ -1191,8 +1348,49 @@ namespace Sass {
|
|
1191
1348
|
{
|
1192
1349
|
Arguments* aa = SASS_MEMORY_NEW(ctx.mem, Arguments, a->pstate());
|
1193
1350
|
for (size_t i = 0, L = a->length(); i < L; ++i) {
|
1194
|
-
*
|
1351
|
+
Argument* arg = static_cast<Argument*>((*a)[i]->perform(this));
|
1352
|
+
if (!(arg->is_rest_argument() || arg->is_keyword_argument())) {
|
1353
|
+
*aa << arg;
|
1354
|
+
}
|
1355
|
+
}
|
1356
|
+
|
1357
|
+
if (a->has_rest_argument()) {
|
1358
|
+
Expression* splat = static_cast<Argument*>(
|
1359
|
+
a->get_rest_argument()->perform(this)
|
1360
|
+
)->value()->perform(this);
|
1361
|
+
|
1362
|
+
Sass_Separator separator = SASS_COMMA;
|
1363
|
+
List* ls = dynamic_cast<List*>(splat);
|
1364
|
+
Map* ms = dynamic_cast<Map*>(splat);
|
1365
|
+
|
1366
|
+
List* arglist = SASS_MEMORY_NEW(ctx.mem, List,
|
1367
|
+
splat->pstate(),
|
1368
|
+
0,
|
1369
|
+
ls ? ls->separator() : separator,
|
1370
|
+
true);
|
1371
|
+
|
1372
|
+
if (ls && ls->is_arglist()) {
|
1373
|
+
for (auto as : *ls) *arglist << as;
|
1374
|
+
} else if (ms) {
|
1375
|
+
*aa << SASS_MEMORY_NEW(ctx.mem, Argument, splat->pstate(), ms, "", false, true);
|
1376
|
+
} else if (ls) {
|
1377
|
+
for (auto as : *ls) *arglist << as;
|
1378
|
+
} else {
|
1379
|
+
*arglist << splat;
|
1380
|
+
}
|
1381
|
+
if (arglist->length()) {
|
1382
|
+
*aa << SASS_MEMORY_NEW(ctx.mem, Argument, splat->pstate(), arglist, "", true);
|
1383
|
+
}
|
1384
|
+
}
|
1385
|
+
|
1386
|
+
if (a->has_keyword_argument()) {
|
1387
|
+
Expression* kwarg = static_cast<Argument*>(
|
1388
|
+
a->get_keyword_argument()->perform(this)
|
1389
|
+
)->value()->perform(this);
|
1390
|
+
|
1391
|
+
*aa << SASS_MEMORY_NEW(ctx.mem, Argument, kwarg->pstate(), kwarg, "", false, true);
|
1195
1392
|
}
|
1393
|
+
|
1196
1394
|
return aa;
|
1197
1395
|
}
|
1198
1396
|
|
@@ -1214,25 +1412,27 @@ namespace Sass {
|
|
1214
1412
|
return lhs && rhs && *lhs == *rhs;
|
1215
1413
|
}
|
1216
1414
|
|
1217
|
-
bool Eval::lt(Expression* lhs, Expression* rhs)
|
1415
|
+
bool Eval::lt(Expression* lhs, Expression* rhs, std::string op)
|
1218
1416
|
{
|
1219
1417
|
Number* l = dynamic_cast<Number*>(lhs);
|
1220
1418
|
Number* r = dynamic_cast<Number*>(rhs);
|
1221
|
-
|
1222
|
-
if (!r)
|
1419
|
+
// use compare operator from ast node
|
1420
|
+
if (!l || !r) throw Exception::UndefinedOperation(lhs, rhs, op);
|
1223
1421
|
// use compare operator from ast node
|
1224
1422
|
return *l < *r;
|
1225
1423
|
}
|
1226
1424
|
|
1227
|
-
Value* Eval::op_numbers(Memory_Manager& mem, enum Sass_OP op, const Number& l, const Number& r,
|
1425
|
+
Value* Eval::op_numbers(Memory_Manager& mem, enum Sass_OP op, const Number& l, const Number& r, struct Sass_Inspect_Options opt, ParserState* pstate)
|
1228
1426
|
{
|
1229
1427
|
double lv = l.value();
|
1230
1428
|
double rv = r.value();
|
1231
|
-
if (op == Sass_OP::DIV &&
|
1232
|
-
|
1429
|
+
if (op == Sass_OP::DIV && rv == 0) {
|
1430
|
+
// XXX: this is never hit via spec tests
|
1431
|
+
return SASS_MEMORY_NEW(mem, String_Quoted, pstate ? *pstate : l.pstate(), lv ? "Infinity" : "NaN");
|
1233
1432
|
}
|
1234
1433
|
if (op == Sass_OP::MOD && !rv) {
|
1235
|
-
|
1434
|
+
// XXX: this is never hit via spec tests
|
1435
|
+
throw Exception::ZeroDivisionError(l, r);
|
1236
1436
|
}
|
1237
1437
|
|
1238
1438
|
Number tmp(r);
|
@@ -1240,10 +1440,6 @@ namespace Sass {
|
|
1240
1440
|
tmp.normalize(l.find_convertible_unit(), strict);
|
1241
1441
|
std::string l_unit(l.unit());
|
1242
1442
|
std::string r_unit(tmp.unit());
|
1243
|
-
if (l_unit != r_unit && !l_unit.empty() && !r_unit.empty() &&
|
1244
|
-
(op == Sass_OP::ADD || op == Sass_OP::SUB)) {
|
1245
|
-
error("Incompatible units: '"+r_unit+"' and '"+l_unit+"'.", pstate ? *pstate : r.pstate());
|
1246
|
-
}
|
1247
1443
|
Number* v = SASS_MEMORY_NEW(mem, Number, l);
|
1248
1444
|
v->pstate(pstate ? *pstate : l.pstate());
|
1249
1445
|
if (l_unit.empty() && (op == Sass_OP::ADD || op == Sass_OP::SUB || op == Sass_OP::MOD)) {
|
@@ -1269,16 +1465,20 @@ namespace Sass {
|
|
1269
1465
|
v->numerator_units().push_back(r.denominator_units()[i]);
|
1270
1466
|
}
|
1271
1467
|
} else {
|
1468
|
+
Number rh(r);
|
1469
|
+
v->value(ops[op](lv, rh.value() * r.convert_factor(l)));
|
1470
|
+
// v->normalize();
|
1471
|
+
return v;
|
1472
|
+
|
1272
1473
|
v->value(ops[op](lv, tmp.value()));
|
1273
1474
|
}
|
1274
1475
|
v->normalize();
|
1275
1476
|
return v;
|
1276
1477
|
}
|
1277
1478
|
|
1278
|
-
Value* Eval::op_number_color(Memory_Manager& mem, enum Sass_OP op, const Number& l, const Color& rh,
|
1479
|
+
Value* Eval::op_number_color(Memory_Manager& mem, enum Sass_OP op, const Number& l, const Color& rh, struct Sass_Inspect_Options opt, ParserState* pstate)
|
1279
1480
|
{
|
1280
1481
|
Color r(rh);
|
1281
|
-
r.disp("");
|
1282
1482
|
double lv = l.value();
|
1283
1483
|
switch (op) {
|
1284
1484
|
case Sass_OP::ADD:
|
@@ -1293,15 +1493,15 @@ namespace Sass {
|
|
1293
1493
|
case Sass_OP::SUB:
|
1294
1494
|
case Sass_OP::DIV: {
|
1295
1495
|
std::string sep(op == Sass_OP::SUB ? "-" : "/");
|
1296
|
-
std::string color(r.to_string(
|
1496
|
+
std::string color(r.to_string(opt));
|
1297
1497
|
return SASS_MEMORY_NEW(mem, String_Quoted,
|
1298
1498
|
pstate ? *pstate : l.pstate(),
|
1299
|
-
l.to_string(
|
1499
|
+
l.to_string(opt)
|
1300
1500
|
+ sep
|
1301
1501
|
+ color);
|
1302
1502
|
} break;
|
1303
1503
|
case Sass_OP::MOD: {
|
1304
|
-
|
1504
|
+
throw Exception::UndefinedOperation(&l, &r, sass_op_to_name(op));
|
1305
1505
|
} break;
|
1306
1506
|
default: break; // caller should ensure that we don't get here
|
1307
1507
|
}
|
@@ -1309,10 +1509,13 @@ namespace Sass {
|
|
1309
1509
|
return SASS_MEMORY_NEW(mem, Color, rh);
|
1310
1510
|
}
|
1311
1511
|
|
1312
|
-
Value* Eval::op_color_number(Memory_Manager& mem, enum Sass_OP op, const Color& l, const Number& r,
|
1512
|
+
Value* Eval::op_color_number(Memory_Manager& mem, enum Sass_OP op, const Color& l, const Number& r, struct Sass_Inspect_Options opt, ParserState* pstate)
|
1313
1513
|
{
|
1314
1514
|
double rv = r.value();
|
1315
|
-
if (op == Sass_OP::DIV && !rv)
|
1515
|
+
if (op == Sass_OP::DIV && !rv) {
|
1516
|
+
// comparison of Fixnum with Float failed?
|
1517
|
+
throw Exception::ZeroDivisionError(l, r);
|
1518
|
+
}
|
1316
1519
|
return SASS_MEMORY_NEW(mem, Color,
|
1317
1520
|
pstate ? *pstate : l.pstate(),
|
1318
1521
|
ops[op](l.r(), rv),
|
@@ -1321,13 +1524,14 @@ namespace Sass {
|
|
1321
1524
|
l.a());
|
1322
1525
|
}
|
1323
1526
|
|
1324
|
-
Value* Eval::op_colors(Memory_Manager& mem, enum Sass_OP op, const Color& l, const Color& r,
|
1527
|
+
Value* Eval::op_colors(Memory_Manager& mem, enum Sass_OP op, const Color& l, const Color& r, struct Sass_Inspect_Options opt, ParserState* pstate)
|
1325
1528
|
{
|
1326
1529
|
if (l.a() != r.a()) {
|
1327
|
-
|
1530
|
+
throw Exception::AlphaChannelsNotEqual(&l, &r, "+");
|
1328
1531
|
}
|
1329
1532
|
if (op == Sass_OP::DIV && (!r.r() || !r.g() ||!r.b())) {
|
1330
|
-
|
1533
|
+
// comparison of Fixnum with Float failed?
|
1534
|
+
throw Exception::ZeroDivisionError(l, r);
|
1331
1535
|
}
|
1332
1536
|
return SASS_MEMORY_NEW(mem, Color,
|
1333
1537
|
pstate ? *pstate : l.pstate(),
|
@@ -1337,66 +1541,39 @@ namespace Sass {
|
|
1337
1541
|
l.a());
|
1338
1542
|
}
|
1339
1543
|
|
1340
|
-
Value* Eval::op_strings(Memory_Manager& mem,
|
1544
|
+
Value* Eval::op_strings(Memory_Manager& mem, Sass::Operand operand, Value& lhs, Value& rhs, struct Sass_Inspect_Options opt, ParserState* pstate, bool delayed)
|
1341
1545
|
{
|
1342
1546
|
Expression::Concrete_Type ltype = lhs.concrete_type();
|
1343
1547
|
Expression::Concrete_Type rtype = rhs.concrete_type();
|
1548
|
+
enum Sass_OP op = operand.operand;
|
1344
1549
|
|
1345
1550
|
String_Quoted* lqstr = dynamic_cast<String_Quoted*>(&lhs);
|
1346
1551
|
String_Quoted* rqstr = dynamic_cast<String_Quoted*>(&rhs);
|
1347
1552
|
|
1348
|
-
std::string lstr(lqstr ? lqstr->value() : lhs.to_string(
|
1349
|
-
std::string rstr(rqstr ? rqstr->value() : rhs.to_string(
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
if (l_str_color && r_str_color) {
|
1357
|
-
const Color* c_l = name_to_color(lstr);
|
1358
|
-
const Color* c_r = name_to_color(rstr);
|
1359
|
-
return op_colors(mem, op,*c_l, *c_r, compressed, precision);
|
1360
|
-
}
|
1361
|
-
else if (l_str_color && rtype == Expression::COLOR) {
|
1362
|
-
const Color* c_l = name_to_color(lstr);
|
1363
|
-
const Color* c_r = dynamic_cast<const Color*>(&rhs);
|
1364
|
-
return op_colors(mem, op, *c_l, *c_r, compressed, precision);
|
1365
|
-
}
|
1366
|
-
else if (ltype == Expression::COLOR && r_str_color) {
|
1367
|
-
const Color* c_l = dynamic_cast<const Color*>(&lhs);
|
1368
|
-
const Color* c_r = name_to_color(rstr);
|
1369
|
-
return op_colors(mem, op, *c_l, *c_r, compressed, precision);
|
1370
|
-
}
|
1371
|
-
else if (l_str_color && rtype == Expression::NUMBER) {
|
1372
|
-
const Color* c_l = name_to_color(lstr);
|
1373
|
-
const Number* n_r = dynamic_cast<const Number*>(&rhs);
|
1374
|
-
return op_color_number(mem, op, *c_l, *n_r, compressed, precision);
|
1375
|
-
}
|
1376
|
-
else if (ltype == Expression::NUMBER && r_str_color) {
|
1377
|
-
const Number* n_l = dynamic_cast<const Number*>(&lhs);
|
1378
|
-
const Color* c_r = name_to_color(rstr);
|
1379
|
-
return op_number_color(mem, op, *n_l, *c_r, compressed, precision);
|
1380
|
-
}
|
1381
|
-
if (op == Sass_OP::MUL) error("invalid operands for multiplication", lhs.pstate());
|
1382
|
-
if (op == Sass_OP::MOD) error("invalid operands for modulo", lhs.pstate());
|
1553
|
+
std::string lstr(lqstr ? lqstr->value() : lhs.to_string(opt));
|
1554
|
+
std::string rstr(rqstr ? rqstr->value() : rhs.to_string(opt));
|
1555
|
+
|
1556
|
+
if (ltype == Expression::NULL_VAL) throw Exception::InvalidNullOperation(&lhs, &rhs, sass_op_to_name(op));
|
1557
|
+
if (rtype == Expression::NULL_VAL) throw Exception::InvalidNullOperation(&lhs, &rhs, sass_op_to_name(op));
|
1558
|
+
if (op == Sass_OP::MOD) throw Exception::UndefinedOperation(&lhs, &rhs, sass_op_to_name(op));
|
1559
|
+
if (op == Sass_OP::MUL) throw Exception::UndefinedOperation(&lhs, &rhs, sass_op_to_name(op));
|
1383
1560
|
std::string sep;
|
1384
1561
|
switch (op) {
|
1385
1562
|
case Sass_OP::SUB: sep = "-"; break;
|
1386
1563
|
case Sass_OP::DIV: sep = "/"; break;
|
1564
|
+
case Sass_OP::MUL: sep = "*"; break;
|
1565
|
+
case Sass_OP::MOD: sep = "%"; break;
|
1566
|
+
case Sass_OP::EQ: sep = "=="; break;
|
1567
|
+
case Sass_OP::NEQ: sep = "!="; break;
|
1568
|
+
case Sass_OP::LT: sep = "<"; break;
|
1569
|
+
case Sass_OP::GT: sep = ">"; break;
|
1570
|
+
case Sass_OP::LTE: sep = "<="; break;
|
1571
|
+
case Sass_OP::GTE: sep = ">="; break;
|
1387
1572
|
default: break;
|
1388
1573
|
}
|
1389
|
-
if (ltype == Expression::NULL_VAL) error("Invalid null operation: \"null plus "+quote(unquote(rstr), '"')+"\".", lhs.pstate());
|
1390
|
-
if (rtype == Expression::NULL_VAL) error("Invalid null operation: \""+quote(unquote(lstr), '"')+" plus null\".", rhs.pstate());
|
1391
|
-
|
1392
|
-
if (ltype == Expression::NUMBER && sep == "/" && rtype == Expression::STRING)
|
1393
|
-
{
|
1394
|
-
return SASS_MEMORY_NEW(mem, String_Constant, lhs.pstate(),
|
1395
|
-
lhs.to_string() + sep + rhs.to_string());
|
1396
|
-
}
|
1397
1574
|
|
1398
|
-
if ( (
|
1399
|
-
(sep != "/" || !rqstr || !rqstr->quote_mark())
|
1575
|
+
if ( (sep == "") /* &&
|
1576
|
+
(sep != "/" || !rqstr || !rqstr->quote_mark()) */
|
1400
1577
|
) {
|
1401
1578
|
char quote_mark = 0;
|
1402
1579
|
std::string unq(unquote(lstr + sep + rstr, "e_mark, true));
|
@@ -1405,7 +1582,19 @@ namespace Sass {
|
|
1405
1582
|
}
|
1406
1583
|
return SASS_MEMORY_NEW(mem, String_Quoted, lhs.pstate(), lstr + sep + rstr);
|
1407
1584
|
}
|
1408
|
-
|
1585
|
+
|
1586
|
+
if (sep != "" && !delayed) {
|
1587
|
+
if (operand.ws_before) sep = " " + sep;
|
1588
|
+
if (operand.ws_after) sep = sep + " ";
|
1589
|
+
}
|
1590
|
+
|
1591
|
+
if (op == Sass_OP::SUB || op == Sass_OP::DIV) {
|
1592
|
+
if (lqstr && lqstr->quote_mark()) lstr = quote(lstr);
|
1593
|
+
if (rqstr && rqstr->quote_mark()) rstr = quote(rstr);
|
1594
|
+
return SASS_MEMORY_NEW(mem, String_Constant, lhs.pstate(), lstr + sep + rstr);
|
1595
|
+
}
|
1596
|
+
|
1597
|
+
return SASS_MEMORY_NEW(mem, String_Constant, lhs.pstate(), (lstr) + sep + (rstr));
|
1409
1598
|
}
|
1410
1599
|
|
1411
1600
|
Expression* cval_to_astnode(Memory_Manager& mem, union Sass_Value* v, Context& ctx, Backtrace* backtrace, ParserState pstate)
|
@@ -1496,6 +1685,7 @@ namespace Sass {
|
|
1496
1685
|
|
1497
1686
|
}
|
1498
1687
|
|
1688
|
+
// XXX: this is never hit via spec tests
|
1499
1689
|
Attribute_Selector* Eval::operator()(Attribute_Selector* s)
|
1500
1690
|
{
|
1501
1691
|
String* attr = s->value();
|
@@ -1507,9 +1697,8 @@ namespace Sass {
|
|
1507
1697
|
|
1508
1698
|
Selector_List* Eval::operator()(Selector_Schema* s)
|
1509
1699
|
{
|
1510
|
-
To_String to_string;
|
1511
1700
|
// the parser will look for a brace to end the selector
|
1512
|
-
std::string result_str(s->contents()->perform(this)->
|
1701
|
+
std::string result_str(s->contents()->perform(this)->to_string(ctx.c_options));
|
1513
1702
|
result_str = unquote(Util::rtrim(result_str)) + "{";
|
1514
1703
|
Parser p = Parser::from_c_str(result_str.c_str(), ctx, s->pstate());
|
1515
1704
|
return operator()(p.parse_selector_list(exp.block_stack.back()->is_root()));
|