Skip to content

Commit

Permalink
Expose sass operations on C-API
Browse files Browse the repository at this point in the history
Adds new value converter functions.
  • Loading branch information
mgreter committed Jul 15, 2015
1 parent f3ba848 commit a7791b5
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 0 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ SOURCES = \
to_value.cpp \
units.cpp \
utf8_string.cpp \
values.cpp \
util.cpp

CSOURCES = cencode.c
Expand Down
1 change: 1 addition & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
63 changes: 63 additions & 0 deletions sass_values.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include <cstdlib>
#include <cstring>
#include "util.hpp"
#include "eval.hpp"
#include "values.hpp"
#include "sass_values.h"

extern "C" {
Expand Down Expand Up @@ -351,4 +353,65 @@ extern "C" {

}

union Sass_Value* ADDCALL sass_value_stringify (const union Sass_Value* v, bool compressed, int precision)
{
Memory_Manager<AST_Node> 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<AST_Node> 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<const Number*>(lhs);
const Number* r_n = dynamic_cast<const Number*>(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<const Number*>(lhs);
const Color* r_c = dynamic_cast<const Color*>(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<const Color*>(lhs);
const Number* r_n = dynamic_cast<const Number*>(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<const Color*>(lhs);
const Color* r_c = dynamic_cast<const Color*>(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<Value*>(lhs);
Value* r_v = dynamic_cast<Value*>(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);

}

}
6 changes: 6 additions & 0 deletions sass_values.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
125 changes: 125 additions & 0 deletions values.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#include "sass.h"
#include "values.hpp"

#include <stdint.h>

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<const Number*>(val);
return sass_make_number(res->value(), res->unit().c_str());
}
else if (val->concrete_type() == Expression::COLOR)
{
const Color* col = dynamic_cast<const Color*>(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<const List*>(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<const Map*>(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<const Boolean*>(val);
return sass_make_boolean(res->value());
}
else if (val->concrete_type() == Expression::STRING)
{
if (const String_Quoted* qstr = dynamic_cast<const String_Quoted*>(val))
{
return sass_make_qstring(qstr->value().c_str());
}
else if (const String_Constant* cstr = dynamic_cast<const String_Constant*>(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<AST_Node>& 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;
}

}
12 changes: 12 additions & 0 deletions values.hpp
Original file line number Diff line number Diff line change
@@ -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<AST_Node>& mem, const union Sass_Value* val);

}
#endif
6 changes: 6 additions & 0 deletions win/libsass.filters
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@
<ClCompile Include="..\util.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\values.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\cencode.c">
<Filter>Source Files</Filter>
</ClCompile>
Expand Down Expand Up @@ -305,6 +308,9 @@
<ClInclude Include="..\util.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\values.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\json.hpp">
<Filter>Header Files</Filter>
</ClInclude>
Expand Down
2 changes: 2 additions & 0 deletions win/libsass.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@
<ClCompile Include="..\units.cpp" />
<ClCompile Include="..\utf8_string.cpp" />
<ClCompile Include="..\util.cpp" />
<ClCompile Include="..\values.cpp" />
<ClCompile Include="..\sassc\sassc.c" />
</ItemGroup>
<ItemGroup>
Expand Down Expand Up @@ -262,6 +263,7 @@
<ClInclude Include="..\utf8\unchecked.h" />
<ClInclude Include="..\utf8_string.hpp" />
<ClInclude Include="..\util.hpp" />
<ClInclude Include="..\values.hpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
Expand Down

0 comments on commit a7791b5

Please sign in to comment.