From a7791b50cfcda1753d8718f220d588e766f87014 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Tue, 14 Jul 2015 00:15:35 +0200 Subject: [PATCH] Expose sass operations on C-API Adds new value converter functions. --- Makefile | 1 + Makefile.am | 1 + sass_values.cpp | 63 ++++++++++++++++++++++ sass_values.h | 6 +++ values.cpp | 125 ++++++++++++++++++++++++++++++++++++++++++++ values.hpp | 12 +++++ win/libsass.filters | 6 +++ win/libsass.vcxproj | 2 + 8 files changed, 216 insertions(+) create mode 100644 values.cpp create mode 100644 values.hpp diff --git a/Makefile b/Makefile index 0e7e33f0e1..9d78254646 100644 --- a/Makefile +++ b/Makefile @@ -193,6 +193,7 @@ SOURCES = \ to_value.cpp \ units.cpp \ utf8_string.cpp \ + values.cpp \ util.cpp CSOURCES = cencode.c diff --git a/Makefile.am b/Makefile.am index d8a9ae1d63..9b6a6dabd0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -80,6 +80,7 @@ libsass_la_SOURCES = \ to_value.cpp to_value.hpp \ units.cpp units.hpp \ utf8_string.cpp utf8_string.hpp \ + values.cpp values.hpp \ util.cpp util.hpp libsass_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 0:9:0 diff --git a/sass_values.cpp b/sass_values.cpp index 84f74365b7..2c03ebc5a0 100644 --- a/sass_values.cpp +++ b/sass_values.cpp @@ -7,6 +7,8 @@ #include #include #include "util.hpp" +#include "eval.hpp" +#include "values.hpp" #include "sass_values.h" extern "C" { @@ -351,4 +353,65 @@ extern "C" { } + union Sass_Value* ADDCALL sass_value_stringify (const union Sass_Value* v, bool compressed, int precision) + { + Memory_Manager mem; + Value* val = sass_value_to_ast_node(mem, v); + string str(val->to_string(compressed, precision)); + return sass_make_qstring(str.c_str()); + } + + union Sass_Value* ADDCALL sass_value_op (enum Sass_OP op, const union Sass_Value* a, const union Sass_Value* b) + { + + Sass::Value* rv = 0; + Memory_Manager mem; + Value* lhs = sass_value_to_ast_node(mem, a); + Value* rhs = sass_value_to_ast_node(mem, b); + + // see if it's a relational expression + switch(op) { + case Sass_OP::EQ: return sass_make_boolean(Eval::eq(lhs, rhs)); + case Sass_OP::NEQ: return sass_make_boolean(!Eval::eq(lhs, rhs)); + case Sass_OP::GT: return sass_make_boolean(!Eval::lt(lhs, rhs) && !Eval::eq(lhs, rhs)); + case Sass_OP::GTE: return sass_make_boolean(!Eval::lt(lhs, rhs)); + case Sass_OP::LT: return sass_make_boolean(Eval::lt(lhs, rhs)); + case Sass_OP::LTE: return sass_make_boolean(Eval::lt(lhs, rhs) || Eval::eq(lhs, rhs)); + default: break; + } + + if (sass_value_is_number(a) && sass_value_is_number(b)) { + const Number* l_n = dynamic_cast(lhs); + const Number* r_n = dynamic_cast(rhs); + rv = Eval::op_numbers(mem, op, *l_n, *r_n); + } + else if (sass_value_is_number(a) && sass_value_is_color(a)) { + const Number* l_n = dynamic_cast(lhs); + const Color* r_c = dynamic_cast(rhs); + rv = Eval::op_number_color(mem, op, *l_n, *r_c); + } + else if (sass_value_is_color(a) && sass_value_is_number(b)) { + const Color* l_c = dynamic_cast(lhs); + const Number* r_n = dynamic_cast(rhs); + rv = Eval::op_color_number(mem, op, *l_c, *r_n); + } + else if (sass_value_is_color(a) && sass_value_is_color(b)) { + const Color* l_c = dynamic_cast(lhs); + const Color* r_c = dynamic_cast(rhs); + rv = Eval::op_colors(mem, op, *l_c, *r_c); + } + else /* convert other stuff to string and apply operation */ { + Value* l_v = dynamic_cast(lhs); + Value* r_v = dynamic_cast(rhs); + rv = Eval::op_strings(mem, op, *l_v, *r_v); + } + + // ToDo: maybe we should should return null value? + if (!rv) return sass_make_error("invalid return value"); + + // convert result back to ast node + return ast_node_to_sass_value(rv); + + } + } diff --git a/sass_values.h b/sass_values.h index 31dffb7603..3d8ae32dd8 100644 --- a/sass_values.h +++ b/sass_values.h @@ -127,6 +127,12 @@ ADDAPI void ADDCALL sass_delete_value (union Sass_Value* val); // Make a deep cloned copy of the given sass value ADDAPI union Sass_Value* ADDCALL sass_clone_value (const union Sass_Value* val); +// Stringify a Sass_Values and also return the result as a Sass_Value (of type STRING) +ADDAPI union Sass_Value* ADDCALL sass_value_stringify (const union Sass_Value* a, bool compressed, int precision); + +// Execute an operation for two Sass_Values and return the result as a Sass_Value too +ADDAPI union Sass_Value* ADDCALL sass_value_op (enum Sass_OP op, const union Sass_Value* a, const union Sass_Value* b); + #ifdef __cplusplus } // __cplusplus defined. diff --git a/values.cpp b/values.cpp new file mode 100644 index 0000000000..1ef3f154a8 --- /dev/null +++ b/values.cpp @@ -0,0 +1,125 @@ +#include "sass.h" +#include "values.hpp" + +#include + +namespace Sass { + using namespace std; + + // convert value from C++ side to C-API + union Sass_Value* ast_node_to_sass_value (const Expression* val) + { + if (val->concrete_type() == Expression::NUMBER) + { + const Number* res = dynamic_cast(val); + return sass_make_number(res->value(), res->unit().c_str()); + } + else if (val->concrete_type() == Expression::COLOR) + { + const Color* col = dynamic_cast(val); + return sass_make_color(col->r(), col->g(), col->b(), col->a()); + } + else if (val->concrete_type() == Expression::LIST) + { + const List* l = dynamic_cast(val); + union Sass_Value* list = sass_make_list(l->size(), l->separator()); + for (size_t i = 0, L = l->length(); i < L; ++i) { + auto val = ast_node_to_sass_value((*l)[i]); + sass_list_set_value(list, i, val); + } + return list; + } + else if (val->concrete_type() == Expression::MAP) + { + const Map* m = dynamic_cast(val); + union Sass_Value* map = sass_make_map(m->length()); + size_t i = 0; for (auto key : m->keys()) { + sass_map_set_key(map, i, ast_node_to_sass_value(key)); + sass_map_set_value(map, i, ast_node_to_sass_value(m->at(key))); + ++ i; + } + return map; + } + else if (val->concrete_type() == Expression::NULL_VAL) + { + return sass_make_null(); + } + else if (val->concrete_type() == Expression::BOOLEAN) + { + const Boolean* res = dynamic_cast(val); + return sass_make_boolean(res->value()); + } + else if (val->concrete_type() == Expression::STRING) + { + if (const String_Quoted* qstr = dynamic_cast(val)) + { + return sass_make_qstring(qstr->value().c_str()); + } + else if (const String_Constant* cstr = dynamic_cast(val)) + { + return sass_make_string(cstr->value().c_str()); + } + } + return sass_make_error("unknown sass value type"); + } + + // convert value from C-API to C++ side + Value* sass_value_to_ast_node (Memory_Manager& mem, const union Sass_Value* val) + { + switch (sass_value_get_tag(val)) { + case SASS_NUMBER: + return new (mem) Number(ParserState("[C-VALUE]"), + sass_number_get_value(val), + sass_number_get_unit(val)); + break; + case SASS_BOOLEAN: + return new (mem) Boolean(ParserState("[C-VALUE]"), + sass_boolean_get_value(val)); + break; + case SASS_COLOR: + return new (mem) Color(ParserState("[C-VALUE]"), + sass_color_get_r(val), + sass_color_get_g(val), + sass_color_get_b(val), + sass_color_get_a(val)); + break; + case SASS_STRING: + return new (mem) String_Quoted(ParserState("[C-VALUE]"), + sass_string_get_value(val)); + break; + case SASS_LIST: { + List* l = new (mem) List(ParserState("[C-VALUE]"), + sass_list_get_length(val), + sass_list_get_separator(val)); + for (size_t i = 0, L = sass_list_get_length(val); i < L; ++i) { + *l << sass_value_to_ast_node(mem, sass_list_get_value(val, i)); + } + return l; + } + break; + case SASS_MAP: { + Map* m = new (mem) Map(ParserState("[C-VALUE]")); + for (size_t i = 0, L = sass_map_get_length(val); i < L; ++i) { + *m << std::make_pair( + sass_value_to_ast_node(mem, sass_map_get_key(val, i)), + sass_value_to_ast_node(mem, sass_map_get_value(val, i))); + } + return m; + } + break; + case SASS_NULL: + return new (mem) Null(ParserState("[C-VALUE]")); + break; + case SASS_ERROR: + return new (mem) Custom_Error(ParserState("[C-VALUE]"), + sass_error_get_message(val)); + break; + case SASS_WARNING: + return new (mem) Custom_Warning(ParserState("[C-VALUE]"), + sass_warning_get_message(val)); + break; + } + return 0; + } + +} diff --git a/values.hpp b/values.hpp new file mode 100644 index 0000000000..765ed8619c --- /dev/null +++ b/values.hpp @@ -0,0 +1,12 @@ +#ifndef SASS_VALUES_H +#define SASS_VALUES_H + +#include "ast.hpp" + +namespace Sass { + + union Sass_Value* ast_node_to_sass_value (const Expression* val); + Value* sass_value_to_ast_node (Memory_Manager& mem, const union Sass_Value* val); + +} +#endif diff --git a/win/libsass.filters b/win/libsass.filters index 794d0b218f..6770211213 100644 --- a/win/libsass.filters +++ b/win/libsass.filters @@ -132,6 +132,9 @@ Source Files + + Source Files + Source Files @@ -305,6 +308,9 @@ Header Files + + Header Files + Header Files diff --git a/win/libsass.vcxproj b/win/libsass.vcxproj index 5b0cb39131..fe2952da59 100644 --- a/win/libsass.vcxproj +++ b/win/libsass.vcxproj @@ -203,6 +203,7 @@ + @@ -262,6 +263,7 @@ +