CELL func_substring(CELL frame) { CELL string = FV0; CELL start = FV1; CELL end = FV2; if (!STRINGP(string)) { return make_exception("expects a string"); } if (!INTP(start)) { return make_exception("expects a non-negative start index"); } if (!INTP(end)) { return make_exception("expects a non-negative end index"); } size_t len = GET_STRING(string)->len; size_t starti = GET_INT(start); size_t endi = GET_INT(end); if (starti < 0 || starti > len) { return make_exception("start index %d out of range [0,%d]", starti, len); } if (endi < starti || endi > len) { return make_exception("end index %d out of range [%d,%d]", endi, starti, len); } gc_root_1("func_substring", string); CELL result = make_string_raw(endi - starti); gc_unroot(); memcpy(GET_STRING(result)->data, GET_STRING(string)->data + starti, endi - starti); return result; }
CELL func_make_string(CELL frame) { if (!(INTP(FV0) && GET_INT(FV0) >= 0)) { return make_exception("1st argument expects non-negative integer"); } if (FC == 2 && !CHARP(FV1)) { return make_exception("2nd argument expects character"); } return make_string_filled(GET_INT(FV0), (FC == 2) ? GET_CHAR(FV1) : -1); }
/***************************************************************************** * driving logic *****************************************************************************/ int main( int argc, char *argv[]) { AsyncAPI api; // successful write(): prime AsyncAPI with some data write( api, "abcd"); // successful read(): retrieve it std::string data( read( api) ); assert( data == "abcd"); // successful write_ec() AsyncAPI::errorcode ec( write_ec( api, "efgh") ); assert( ec == 0); // write_ec() with error api.inject_error(1); ec = write_ec( api, "ijkl"); assert( ec == 1); // write() with error std::string thrown; api.inject_error(2); try { write(api, "mnop"); } catch ( std::exception const& e) { thrown = e.what(); } assert( thrown == make_exception("write", 2).what() ); // successful read_ec() //[callbacks_read_ec_call std::tie( ec, data) = read_ec( api); //] assert( ! ec); assert( data == "efgh"); // last successful write_ec() // read_ec() with error api.inject_error(3); std::tie( ec, data) = read_ec( api); assert( ec == 3); // 'data' in unspecified state, don't test // read() with error thrown.clear(); api.inject_error(4); try { data = read(api); } catch ( std::exception const& e) { thrown = e.what(); } assert( thrown == make_exception("read", 4).what() ); std::cout << "done." << std::endl; return EXIT_SUCCESS; }
CELL func_string_fill(CELL frame) { CELL string = FV0; CELL ch = FV1; if (!STRINGP(string)) { return make_exception("expects a string for 1st argument"); } if (!CHARP(ch)) { return make_exception("expects a character for 2nd argument"); } STRING *str = GET_STRING(string); memset(str->data, GET_CHAR(ch), str->len); return V_VOID; }
CELL func_string_to_list(CELL frame) { CELL string = FV0; if (!STRINGP(string)) { return make_exception("expects string"); } CELL result = V_NULL; CELL pre_tail = V_EMPTY; gc_root_3("func_string_to_list", string, result, pre_tail); const size_t len = GET_STRING(string)->len; int i; for(i = 0; i < len; ++i) { const CELL next = make_cons(make_char(GET_STRING(string)->data[i]), V_NULL); if (i == 0) { result = next; } else { CDR(pre_tail) = next; } pre_tail = next; } gc_unroot(); return result; }
CELL func_char_downcase(CELL frame) { if (!CHARP(FV0)) { return make_exception("expects a <character> argument"); } return make_char(tolower(GET_CHAR(FV0))); }
CELL func_string_length(CELL frame) { if (!STRINGP(FV0)) { return make_exception("expects string"); } return make_int(GET_STRING(FV0)->len); }
CELL func_append(CELL frame) { if (FC == 0) { return V_NULL; } CELL pre_tail = V_EMPTY; CELL result = V_EMPTY; CELL arg = V_EMPTY; gc_root_4("func_append", frame, pre_tail, result, arg); result = FV[FC-1]; int argi = 0; while(argi < FC-1) { arg = FV[argi++]; while(CONSP(arg)) { const CELL next = make_cons(CAR(arg), FV[FC-1]); if (EMPTYP(pre_tail)) { pre_tail = result = next; } else { pre_tail = CDR(pre_tail) = next; } arg = CDR(arg); } if (!NULLP(arg)) { gc_unroot(); return make_exception("expects a <proper list> for all but last argument"); } } gc_unroot(); return result; }
CELL func_cdr(CELL frame) { if (CONSP(FV0)) { return CDR(FV0); } return make_exception("expects a pair"); }
CELL func_car(CELL frame) { if (CONSP(FV0)) { return CAR(FV0); } return make_exception("expects a <pair>"); }
CELL func_char_to_integer(CELL frame) { if (!CHARP(FV0)) { return make_exception("expects a <character> argument"); } return make_int((unsigned char)GET_CHAR(FV0)); }
CELL func_integer_to_char(CELL frame) { if (!(INTP(FV0) && GET_INT(FV0) >= 0 && GET_INT(FV0) <= 255)) { return make_exception("expects an <integer> in [0,255]"); } return make_char(GET_INT(FV0)); }
TEST( expect, void_expect_With_exception ) { auto expect = q::refuse< void >( make_exception( ) ); EXPECT_TRUE( expect.has_exception( ) ); EXPECT_NO_THROW( expect.exception( ) ); EXPECT_THROW( expect.get( ), test_exception ); EXPECT_THROW( expect.consume( ), test_exception ); }
TEST( expect, exception_expect_with_value ) { auto expect = q::fulfill< std::exception_ptr >( make_exception( ) ); EXPECT_FALSE( expect.has_exception( ) ); EXPECT_EQ( expect.exception( ), std::exception_ptr( ) ); EXPECT_NO_THROW( expect.get( ) ); EXPECT_NO_THROW( expect.consume( ) ); }
CELL func_string_ref(CELL frame) { CELL string = FV0; CELL k = FV1; if (!STRINGP(string)) { return make_exception("expects a string"); } if (!INTP(k)) { return make_exception("expects a non-negative integer index"); } STRING *str = GET_STRING(string); size_t kth = GET_INT(k); if (! (kth >= 0 && kth < str->len) ) { return make_exception("index %d out of range [0,%d]", kth, str->len - 1); } return make_char(str->data[kth]); }
TEST( expect, movable_expect_with_exception ) { auto expect = q::refuse< Movable >( make_exception( ) ); EXPECT_TRUE( expect.has_exception( ) ); EXPECT_NO_THROW( expect.exception( ) ); EXPECT_THROW( expect.get( ), test_exception ); EXPECT_THROW( expect.consume( ), test_exception ); }
CELL func_set_cdr(CELL frame) { if (!CONSP(FV0)) { return make_exception("1st argument was not a <pair>"); } GET_CONS(FV0)->cdr = FV1; return V_VOID; }
TEST( expect, exception_expect_with_exception ) { auto expect = q::refuse< std::exception_ptr >( make_exception( ) ); EXPECT_TRUE( expect.has_exception( ) ); EXPECT_NE( expect.exception( ), std::exception_ptr( ) ); EXPECT_THROW( expect.get( ), test_exception ); EXPECT_THROW( expect.consume( ), test_exception ); }
// FIXME can't cope with circular lists CELL func_length(CELL frame) { int n = proper_list_length(FV0); if (n == -1) { return make_exception("expects a <proper list>"); } return make_int(n); }
void Exception::object_bounds_exceeded_error(STATE, Object* obj, size_t index) { TypeInfo* info = state->find_type(obj->type_id()); // HACK use object std::ostringstream msg; msg << "Bounds of object exceeded:" << std::endl; msg << " type: " << info->type_name << ", bytes: " << obj->body_in_bytes(state) << ", accessed: " << index << std::endl; RubyException::raise(make_exception(state, get_object_bounds_exceeded_error(state), msg.str().c_str())); }
Exception* Exception::make_type_error(STATE, object_type type, Object* object, const char* reason) { if(reason) { return make_exception(state, get_type_error(state), reason); } std::ostringstream msg; TypeInfo* wanted = state->find_type(type); if(!object->reference_p()) { msg << " Tried to use non-reference value " << object; } else { TypeInfo* was = state->find_type(object->type_id()); msg << " Tried to use object of type " << was->type_name << " (" << was->type << ")"; } msg << " as type " << wanted->type_name << " (" << wanted->type << ")"; return make_exception(state, get_type_error(state), msg.str().c_str()); }
// FIXME - should typecheck all list elements before allocating storage? CELL func_list_to_string(CELL frame) { CELL list = FV0; int n = proper_list_length(list); if (n == -1) { return make_exception("expects list of characters"); } gc_root_1("func_list_to_string", list); CELL result = make_string_raw(n); gc_unroot(); CHAR* data = GET_STRING(result)->data; int i; for(i = 0; i < n; ++i) { CELL ch = CAR(list); list = CDR(list); if (!CHARP(ch)) { return make_exception("expects list of characters"); } data[i] = GET_CHAR(ch); } return result; }
CELL func_list_ref(CELL frame) { CELL list = FV0; CELL k = FV1; if (!INTP(k) || GET_INT(k) < 0) { return make_exception("expects a positive integer index"); } int kth = GET_INT(k); int i = 0; while(1) { if (NULLP(list)) { return make_exception("index %d too large for list", kth); } if (!CONSP(list)) { return make_exception("index %d too large for (improper) list", kth); } if (i++ == kth) { return CAR(list); } list = CDR(list); } }
CELL func_string_copy(CELL frame) { CELL string = FV0; if (!STRINGP(string)) { return make_exception("expects a string"); } gc_root_1("func_string_copy", string); CELL result = make_string_raw(GET_STRING(string)->len); gc_unroot(); STRING *str = GET_STRING(string); memcpy(GET_STRING(result)->data, str->data, str->len); return result; }
// FIXME does not support immutable strings CELL func_string_set(CELL frame) { CELL string = FV0; CELL k = FV1; CELL ch = FV2; if (!STRINGP(string)) { return make_exception("expects a string"); } if (!INTP(k)) { return make_exception("expects a non-negative integer index"); } if (!CHARP(ch)) { return make_exception("expects a character for 3rd argument"); } STRING *str = GET_STRING(string); size_t kth = GET_INT(k); if (! (kth >= 0 && kth < str->len) ) { return make_exception("index %d out of range [0,%d]", kth, str->len - 1); } str->data[kth] = GET_CHAR(ch); return V_VOID; }
//[callbacks_read std::string read( AsyncAPI & api) { boost::fibers::promise< std::string > promise; boost::fibers::future< std::string > future( promise.get_future() ); // Both 'promise' and 'future' will survive until our lambda has been // called. api.init_read([&promise]( AsyncAPI::errorcode ec, std::string const& data) mutable { if ( ! ec) { promise.set_value( data); } else { promise.set_exception( std::make_exception_ptr( make_exception("read", ec) ) ); } }); return future.get(); }
CELL func_reverse(CELL frame) { CELL list = FV0; CELL result = V_NULL; gc_root_2("func_reverse", list, result); while(CONSP(list)) { result = make_cons(CAR(list), result); list = CDR(list); } if (!NULLP(list)) { gc_unroot(); return make_exception("expects a <proper list>"); } gc_unroot(); return result; }
CELL func_string(CELL frame) { CELL s = V_EMPTY; gc_root_2("func_string", frame, s); s = make_string_raw(FC); CHAR* data = GET_STRING(s)->data; int argi; for(argi = 0; argi < FC; ++argi) { if (!CHARP(FV[argi])) { gc_unroot(); return make_exception("expects character arguments"); } data[argi] = GET_CHAR(FV[argi]); } gc_unroot(); return s; }
void Exception::errno_error(STATE, const char* reason, int ern) { Exception* exc; if(ern == 0) ern = errno; Class* exc_class = get_errno_error(state, Fixnum::from(ern)); if(exc_class->nil_p()) { std::ostringstream msg; msg << "Unknown errno "; if(reason) msg << ": " << reason; exc = make_exception(state, get_system_call_error(state), msg.str().c_str()); } else { String* msg = reason ? String::create(state, reason) : (String*)Qnil; exc = make_errno_exception(state, exc_class, msg); } RubyException::raise(exc); }
CELL func_string_append(CELL frame) { size_t len = 0; int argi; for(argi = 0; argi < FC; ++argi) { if (!STRINGP(FV[argi])) { return make_exception("expects string arguments"); } len += GET_STRING(FV[argi])->len; } gc_root_1("func_string_append", frame); CELL result = make_string_raw(len); gc_unroot(); CHAR *data = GET_STRING(result)->data; for(argi = 0; argi < FC; ++argi) { STRING *arg_str = GET_STRING(FV[argi]); memcpy(data, arg_str->data, arg_str->len); data += arg_str->len; } return result; }