Commit 43286a1a by Marcin Cieslak

Merge branch 'noexceptions'

parents c5a16a9f 228b39d5
......@@ -60,22 +60,12 @@
'-std=c++11'
],
'OTHER_LDFLAGS': [],
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
'GCC_ENABLE_CPP_EXCEPTIONS': 'NO',
'MACOSX_DEPLOYMENT_TARGET': '10.7'
}
}],
['OS=="win"', {
'msvs_settings': {
'VCCLCompilerTool': {
'AdditionalOptions': [
'/EHsc'
]
}
}
}],
['OS!="win"', {
'cflags_cc+': [
'-fexceptions',
'-std=c++0x'
]
}]
......
......@@ -29,12 +29,7 @@ union Sass_Value* sass_custom_function(const union Sass_Value* s_args, Sass_Func
argv.push_back((void*)sass_list_get_value(s_args, i));
}
try {
return bridge(argv);
}
catch (const std::exception& e) {
return sass_make_error(e.what());
}
}
int ExtractOptions(v8::Local<v8::Object> options, void* cptr, sass_context_wrapper* ctx_w, bool is_file, bool is_sync) {
......
......@@ -98,7 +98,12 @@ T CallbackBridge<T, L>::operator()(std::vector<void*> argv) {
* post_process_args().
*/
Nan::HandleScope scope;
Nan::TryCatch try_catch;
std::vector<v8::Local<v8::Value>> argv_v8 = pre_process_args(argv);
if (try_catch.HasCaught()) {
Nan::FatalException(try_catch);
}
argv_v8.push_back(Nan::New(wrapper));
return this->post_process_return_value(
......@@ -149,6 +154,9 @@ void CallbackBridge<T, L>::dispatched_async_uv_callback(uv_async_t *req) {
Nan::TryCatch try_catch;
std::vector<v8::Local<v8::Value>> argv_v8 = bridge->pre_process_args(bridge->argv);
if (try_catch.HasCaught()) {
Nan::FatalException(try_catch);
}
argv_v8.push_back(Nan::New(bridge->wrapper));
bridge->callback->Call(argv_v8.size(), &argv_v8[0]);
......
......@@ -2,13 +2,14 @@
#include <stdexcept>
#include "custom_function_bridge.h"
#include "sass_types/factory.h"
#include "sass_types/value.h"
Sass_Value* CustomFunctionBridge::post_process_return_value(v8::Local<v8::Value> val) const {
try {
return SassTypes::Factory::unwrap(val)->get_sass_value();
}
catch (const std::invalid_argument& e) {
return sass_make_error(e.what());
SassTypes::Value *v_;
if ((v_ = SassTypes::Factory::unwrap(val))) {
return v_->get_sass_value();
} else {
return sass_make_error("A SassValue object was expected.");
}
}
......
......@@ -67,6 +67,9 @@ namespace SassTypes
}
NAN_METHOD(Boolean::GetValue) {
info.GetReturnValue().Set(Nan::New(static_cast<Boolean*>(Factory::unwrap(info.This()))->value));
Boolean *out;
if ((out = static_cast<Boolean*>(Factory::unwrap(info.This())))) {
info.GetReturnValue().Set(Nan::New(out->value));
}
}
}
......@@ -5,14 +5,14 @@ namespace SassTypes
{
Color::Color(Sass_Value* v) : SassValueWrapper(v) {}
Sass_Value* Color::construct(const std::vector<v8::Local<v8::Value>> raw_val) {
Sass_Value* Color::construct(const std::vector<v8::Local<v8::Value>> raw_val, Sass_Value **out) {
double a = 1.0, r = 0, g = 0, b = 0;
unsigned argb;
switch (raw_val.size()) {
case 1:
if (!raw_val[0]->IsNumber()) {
throw std::invalid_argument("Only argument should be an integer.");
return fail("Only argument should be an integer.", out);
}
argb = Nan::To<int32_t>(raw_val[0]).FromJust();
......@@ -24,7 +24,7 @@ namespace SassTypes
case 4:
if (!raw_val[3]->IsNumber()) {
throw std::invalid_argument("Constructor arguments should be numbers exclusively.");
return fail("Constructor arguments should be numbers exclusively.", out);
}
a = Nan::To<double>(raw_val[3]).FromJust();
......@@ -32,7 +32,7 @@ namespace SassTypes
case 3:
if (!raw_val[0]->IsNumber() || !raw_val[1]->IsNumber() || !raw_val[2]->IsNumber()) {
throw std::invalid_argument("Constructor arguments should be numbers exclusively.");
return fail("Constructor arguments should be numbers exclusively.", out);
}
r = Nan::To<double>(raw_val[0]).FromJust();
......@@ -44,10 +44,10 @@ namespace SassTypes
break;
default:
throw std::invalid_argument("Constructor should be invoked with either 0, 1, 3 or 4 arguments.");
return fail("Constructor should be invoked with either 0, 1, 3 or 4 arguments.", out);
}
return sass_make_color(r, g, b, a);
return *out = sass_make_color(r, g, b, a);
}
void Color::initPrototype(v8::Local<v8::FunctionTemplate> proto) {
......
......@@ -10,7 +10,7 @@ namespace SassTypes
public:
Color(Sass_Value*);
static char const* get_constructor_name() { return "SassColor"; }
static Sass_Value* construct(const std::vector<v8::Local<v8::Value>>);
static Sass_Value* construct(const std::vector<v8::Local<v8::Value>>, Sass_Value **);
static void initPrototype(v8::Local<v8::FunctionTemplate>);
......
......@@ -6,18 +6,18 @@ namespace SassTypes
{
Error::Error(Sass_Value* v) : SassValueWrapper(v) {}
Sass_Value* Error::construct(const std::vector<v8::Local<v8::Value>> raw_val) {
Sass_Value* Error::construct(const std::vector<v8::Local<v8::Value>> raw_val, Sass_Value **out) {
char const* value = "";
if (raw_val.size() >= 1) {
if (!raw_val[0]->IsString()) {
throw std::invalid_argument("Argument should be a string.");
return fail("Argument should be a string.", out);
}
value = create_string(raw_val[0]);
}
return sass_make_error(value);
return *out = sass_make_error(value);
}
void Error::initPrototype(v8::Local<v8::FunctionTemplate>) {}
......
......@@ -10,7 +10,7 @@ namespace SassTypes
public:
Error(Sass_Value*);
static char const* get_constructor_name() { return "SassError"; }
static Sass_Value* construct(const std::vector<v8::Local<v8::Value>>);
static Sass_Value* construct(const std::vector<v8::Local<v8::Value>>, Sass_Value **);
static void initPrototype(v8::Local<v8::FunctionTemplate>);
};
......
......@@ -39,7 +39,9 @@ namespace SassTypes
return new Error(v);
default:
throw std::invalid_argument("Unknown type encountered.");
const char *msg = "Unknown type encountered.";
Nan::ThrowTypeError(Nan::New<v8::String>(msg).ToLocalChecked());
return new Error(sass_make_error(msg));
}
}
......@@ -61,7 +63,7 @@ namespace SassTypes
Value* Factory::unwrap(v8::Local<v8::Value> obj) {
// Todo: non-SassValue objects could easily fall under that condition, need to be more specific.
if (!obj->IsObject() || obj.As<v8::Object>()->InternalFieldCount() != 1) {
throw std::invalid_argument("A SassValue object was expected.");
return NULL;
}
return static_cast<Value*>(Nan::GetInternalFieldPointer(obj.As<v8::Object>(), 0));
......
......@@ -5,27 +5,27 @@ namespace SassTypes
{
List::List(Sass_Value* v) : SassValueWrapper(v) {}
Sass_Value* List::construct(const std::vector<v8::Local<v8::Value>> raw_val) {
Sass_Value* List::construct(const std::vector<v8::Local<v8::Value>> raw_val, Sass_Value **out) {
size_t length = 0;
bool comma = true;
if (raw_val.size() >= 1) {
if (!raw_val[0]->IsNumber()) {
throw std::invalid_argument("First argument should be an integer.");
return fail("First argument should be an integer.", out);
}
length = Nan::To<uint32_t>(raw_val[0]).FromJust();
if (raw_val.size() >= 2) {
if (!raw_val[1]->IsBoolean()) {
throw std::invalid_argument("Second argument should be a boolean.");
return fail("Second argument should be a boolean.", out);
}
comma = Nan::To<bool>(raw_val[1]).FromJust();
}
}
return sass_make_list(length, comma ? SASS_COMMA : SASS_SPACE);
return *out = sass_make_list(length, comma ? SASS_COMMA : SASS_SPACE);
}
void List::initPrototype(v8::Local<v8::FunctionTemplate> proto) {
......@@ -71,7 +71,11 @@ namespace SassTypes
}
Value* sass_value = Factory::unwrap(info[1]);
if (sass_value) {
sass_list_set_value(unwrap(info.This())->value, Nan::To<uint32_t>(info[0]).FromJust(), sass_value->get_sass_value());
} else {
Nan::ThrowTypeError(Nan::New<v8::String>("A SassValue is expected as the list item").ToLocalChecked());
}
}
NAN_METHOD(List::GetSeparator) {
......
......@@ -10,7 +10,7 @@ namespace SassTypes
public:
List(Sass_Value*);
static char const* get_constructor_name() { return "SassList"; }
static Sass_Value* construct(const std::vector<v8::Local<v8::Value>>);
static Sass_Value* construct(const std::vector<v8::Local<v8::Value>>, Sass_Value **);
static void initPrototype(v8::Local<v8::FunctionTemplate>);
......
......@@ -5,18 +5,18 @@ namespace SassTypes
{
Map::Map(Sass_Value* v) : SassValueWrapper(v) {}
Sass_Value* Map::construct(const std::vector<v8::Local<v8::Value>> raw_val) {
Sass_Value* Map::construct(const std::vector<v8::Local<v8::Value>> raw_val, Sass_Value **out) {
size_t length = 0;
if (raw_val.size() >= 1) {
if (!raw_val[0]->IsNumber()) {
throw std::invalid_argument("First argument should be an integer.");
return fail("First argument should be an integer.", out);
}
length = Nan::To<uint32_t>(raw_val[0]).FromJust();
}
return sass_make_map(length);
return *out = sass_make_map(length);
}
void Map::initPrototype(v8::Local<v8::FunctionTemplate> proto) {
......@@ -62,7 +62,11 @@ namespace SassTypes
}
Value* sass_value = Factory::unwrap(info[1]);
if (sass_value) {
sass_map_set_value(unwrap(info.This())->value, Nan::To<uint32_t>(info[0]).FromJust(), sass_value->get_sass_value());
} else {
Nan::ThrowTypeError(Nan::New<v8::String>("A SassValue is expected as a map value").ToLocalChecked());
}
}
NAN_METHOD(Map::GetKey) {
......@@ -100,7 +104,11 @@ namespace SassTypes
}
Value* sass_value = Factory::unwrap(info[1]);
if (sass_value) {
sass_map_set_key(unwrap(info.This())->value, Nan::To<uint32_t>(info[0]).FromJust(), sass_value->get_sass_value());
} else {
Nan::ThrowTypeError(Nan::New<v8::String>("A SassValue is expected as a map key").ToLocalChecked());
}
}
NAN_METHOD(Map::GetLength) {
......
......@@ -10,7 +10,7 @@ namespace SassTypes
public:
Map(Sass_Value*);
static char const* get_constructor_name() { return "SassMap"; }
static Sass_Value* construct(const std::vector<v8::Local<v8::Value>>);
static Sass_Value* construct(const std::vector<v8::Local<v8::Value>>, Sass_Value **);
static void initPrototype(v8::Local<v8::FunctionTemplate>);
......
......@@ -6,27 +6,27 @@ namespace SassTypes
{
Number::Number(Sass_Value* v) : SassValueWrapper(v) {}
Sass_Value* Number::construct(const std::vector<v8::Local<v8::Value>> raw_val) {
Sass_Value* Number::construct(const std::vector<v8::Local<v8::Value>> raw_val, Sass_Value **out) {
double value = 0;
char const* unit = "";
if (raw_val.size() >= 1) {
if (!raw_val[0]->IsNumber()) {
throw std::invalid_argument("First argument should be a number.");
return fail("First argument should be a number.", out);
}
value = Nan::To<double>(raw_val[0]).FromJust();
if (raw_val.size() >= 2) {
if (!raw_val[1]->IsString()) {
throw std::invalid_argument("Second argument should be a string.");
return fail("Second argument should be a string.", out);
}
unit = create_string(raw_val[1]);
}
}
return sass_make_number(value, unit);
return *out = sass_make_number(value, unit);
}
void Number::initPrototype(v8::Local<v8::FunctionTemplate> proto) {
......
......@@ -11,7 +11,7 @@ namespace SassTypes
public:
Number(Sass_Value*);
static char const* get_constructor_name() { return "SassNumber"; }
static Sass_Value* construct(const std::vector<v8::Local<v8::Value>>);
static Sass_Value* construct(const std::vector<v8::Local<v8::Value>>, Sass_Value **out);
static void initPrototype(v8::Local<v8::FunctionTemplate>);
......
......@@ -25,6 +25,7 @@ namespace SassTypes
static v8::Local<v8::Function> get_constructor();
static v8::Local<v8::FunctionTemplate> get_constructor_template();
static NAN_METHOD(New);
static Sass_Value *fail(const char *, Sass_Value **);
protected:
Sass_Value* value;
......@@ -94,15 +95,15 @@ namespace SassTypes
localArgs[i] = info[i];
}
if (info.IsConstructCall()) {
try {
Sass_Value* value = T::construct(localArgs);
Sass_Value* value;
if (T::construct(localArgs, &value) != NULL) {
T* obj = new T(value);
sass_delete_value(value);
Nan::SetInternalFieldPointer(info.This(), 0, obj);
obj->js_object.Reset(info.This());
} catch (const std::exception& e) {
return Nan::ThrowError(Nan::New<v8::String>(e.what()).ToLocalChecked());
} else {
return Nan::ThrowError(Nan::New<v8::String>(sass_error_get_message(value)).ToLocalChecked());
}
} else {
v8::Local<v8::Function> cons = T::get_constructor();
......@@ -117,8 +118,15 @@ namespace SassTypes
template <class T>
T* SassValueWrapper<T>::unwrap(v8::Local<v8::Object> obj) {
/* This maybe NULL */
return static_cast<T*>(Factory::unwrap(obj));
}
template <class T>
Sass_Value *SassValueWrapper<T>::fail(const char *reason, Sass_Value **out) {
*out = sass_make_error(reason);
return NULL;
}
}
......
......@@ -6,18 +6,18 @@ namespace SassTypes
{
String::String(Sass_Value* v) : SassValueWrapper(v) {}
Sass_Value* String::construct(const std::vector<v8::Local<v8::Value>> raw_val) {
Sass_Value* String::construct(const std::vector<v8::Local<v8::Value>> raw_val, Sass_Value **out) {
char const* value = "";
if (raw_val.size() >= 1) {
if (!raw_val[0]->IsString()) {
throw std::invalid_argument("Argument should be a string.");
return fail("Argument should be a string.", out);
}
value = create_string(raw_val[0]);
}
return sass_make_string(value);
return *out = sass_make_string(value);
}
void String::initPrototype(v8::Local<v8::FunctionTemplate> proto) {
......
......@@ -10,7 +10,7 @@ namespace SassTypes
public:
String(Sass_Value*);
static char const* get_constructor_name() { return "SassString"; }
static Sass_Value* construct(const std::vector<v8::Local<v8::Value>>);
static Sass_Value* construct(const std::vector<v8::Local<v8::Value>>, Sass_Value **);
static void initPrototype(v8::Local<v8::FunctionTemplate>);
......
......@@ -859,6 +859,72 @@ describe('api', function() {
});
});
it('should fail when trying to set a bare number as the List item', function(done) {
sass.render({
data: 'div { color: foo(); }',
functions: {
'foo()': function() {
var out = new sass.types.List(1);
out.setValue(0, 2);
return out;
}
}
}, function(error) {
assert.ok(/Supplied value should be a SassValue object/.test(error.message));
done();
});
});
it('should fail when trying to set a bare Object as the List item', function(done) {
sass.render({
data: 'div { color: foo(); }',
functions: {
'foo()': function() {
var out = new sass.types.List(1);
out.setValue(0, {});
return out;
}
}
}, function(error) {
assert.ok(/A SassValue is expected as the list item/.test(error.message));
done();
});
});
it('should fail when trying to set a bare Object as the Map key', function(done) {
sass.render({
data: 'div { color: foo(); }',
functions: {
'foo()': function() {
var out = new sass.types.Map(1);
out.setKey(0, {});
out.setValue(0, new sass.types.String('aaa'));
return out;
}
}
}, function(error) {
assert.ok(/A SassValue is expected as a map key/.test(error.message));
done();
});
});
it('should fail when trying to set a bare Object as the Map value', function(done) {
sass.render({
data: 'div { color: foo(); }',
functions: {
'foo()': function() {
var out = new sass.types.Map(1);
out.setKey(0, new sass.types.String('aaa'));
out.setValue(0, {});
return out;
}
}
}, function(error) {
assert.ok(/A SassValue is expected as a map value/.test(error.message));
done();
});
});
it('should always map null, true and false to the same (immutable) object', function(done) {
var counter = 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment