/* returns the codepoint (could be a negative synthetic) at a given index of the string */ MVMint64 MVM_string_get_codepoint_at(MVMThreadContext *tc, MVMString *a, MVMint64 index) { MVMStringIndex agraphs; if (!IS_CONCRETE((MVMObject *)a)) { MVM_exception_throw_adhoc(tc, "codepoint_at needs a concrete string"); } agraphs = NUM_GRAPHS(a); if (index < 0 || index >= agraphs) MVM_exception_throw_adhoc(tc, "Invalid string index: max %lld, got %lld", agraphs - 1, index); return (MVMint64)MVM_string_get_codepoint_at_nocheck(tc, a, index); }
/* Returns a substring of the given string */ MVMString * MVM_string_substring(MVMThreadContext *tc, MVMString *a, MVMint64 start, MVMint64 length) { MVMString *result; MVMStrand *strands; MVMStringIndex agraphs = NUM_GRAPHS(a); if (start < 0) { start += agraphs; if (start < 0) start = 0; } if (!IS_CONCRETE((MVMObject *)a)) { MVM_exception_throw_adhoc(tc, "Substring needs a concrete string"); } if (start > agraphs) start = agraphs; if (length == -1) /* -1 signifies go to the end of the string */ length = agraphs - start; if (length < 0) MVM_exception_throw_adhoc(tc, "Substring length (%lld) cannot be negative", length); if (start + length > agraphs) length = agraphs - start; MVM_gc_root_temp_push(tc, (MVMCollectable **)&a); result = (MVMString *)REPR(a)->allocate(tc, STABLE(a)); MVM_gc_root_temp_pop(tc); strands = result->body.strands = calloc(sizeof(MVMStrand), 2); /* if we're substringing a substring, substring the same one */ if (IS_ONE_STRING_ROPE(a)) { strands->string_offset = (MVMStringIndex)start + a->body.strands->string_offset; strands->string = a->body.strands->string; } else { strands->string_offset = (MVMStringIndex)start; strands->string = a; } /* result->body.codes = 0; /* Populate this lazily. */ result->body.flags = MVM_STRING_TYPE_ROPE; result->body.num_strands = 1; strands[1].graphs = length; _STRAND_DEPTH(result) = STRAND_DEPTH(strands->string) + 1; return result; }
static void Str_length(MVMThreadContext *tc, MVMCallsite *callsite, MVMRegister *args) { MVMArgProcContext arg_ctx; arg_ctx.named_used = NULL; MVM_args_proc_init(tc, &arg_ctx, callsite, args); MVMObject* self = MVM_args_get_pos_obj(tc, &arg_ctx, 0, MVM_ARG_REQUIRED).arg.o; MVM_args_proc_cleanup(tc, &arg_ctx); MVM_gc_root_temp_push(tc, (MVMCollectable **)&self); MVMString * self_s = REPR(self)->box_funcs->get_str(tc, STABLE(self), self, OBJECT_BODY(self)); MVMint64 length = NUM_GRAPHS((MVMString*)self_s); MVM_args_set_result_int(tc, length, MVM_RETURN_CURRENT_FRAME); MVM_gc_root_temp_pop_n(tc, 1); }
/* Compares two strings for equality. */ MVMint64 MVM_string_equal(MVMThreadContext *tc, MVMString *a, MVMString *b) { if (NUM_GRAPHS(a) != NUM_GRAPHS(b)) return 0; return MVM_string_equal_at(tc, a, b, 0); }
/* Set the line separator. */ void MVM_io_syncstream_set_separator(MVMThreadContext *tc, MVMOSHandle *h, MVMString *sep) { /* For now, take last character. */ MVMIOSyncStreamData *data = (MVMIOSyncStreamData *)h->body.data; data->sep = (MVMCodepoint32)MVM_string_get_codepoint_at(tc, sep, NUM_GRAPHS(sep) - 1); }
/* Encodes the specified string to ASCII. */ MVMuint8 * MVM_string_ascii_encode(MVMThreadContext *tc, MVMString *str, MVMuint64 *output_size) { return MVM_string_ascii_encode_substr(tc, str, output_size, 0, NUM_GRAPHS(str)); }
void MVM_coerce_istrue(MVMThreadContext *tc, MVMObject *obj, MVMRegister *res_reg, MVMuint8 *true_addr, MVMuint8 *false_addr, MVMuint8 flip) { MVMint64 result; if (obj == NULL) { result = 0; } else { MVMBoolificationSpec *bs = obj->st->boolification_spec; switch (bs == NULL ? MVM_BOOL_MODE_NOT_TYPE_OBJECT : bs->mode) { case MVM_BOOL_MODE_CALL_METHOD: if (res_reg) { /* We need to do the invocation, and set this register * the result. Then we just do the call. For the flip * case, just set up special return handler to flip * the register. */ MVMObject *code = MVM_frame_find_invokee(tc, bs->method); tc->cur_frame->return_value = res_reg; tc->cur_frame->return_type = MVM_RETURN_INT; tc->cur_frame->return_address = *(tc->interp_cur_op); tc->cur_frame->args[0].o = obj; if (flip) { tc->cur_frame->special_return = flip_return; tc->cur_frame->special_return_data = res_reg; } STABLE(code)->invoke(tc, code, get_inv_callsite(), tc->cur_frame->args); } else { /* Need to set up special return hook. */ MVMObject *code = MVM_frame_find_invokee(tc, bs->method); BoolMethReturnData *data = malloc(sizeof(BoolMethReturnData)); data->true_addr = true_addr; data->false_addr = false_addr; data->flip = flip; tc->cur_frame->special_return = boolify_return; tc->cur_frame->special_return_data = data; tc->cur_frame->return_value = &data->res_reg; tc->cur_frame->return_type = MVM_RETURN_INT; tc->cur_frame->return_address = *(tc->interp_cur_op); tc->cur_frame->args[0].o = obj; STABLE(code)->invoke(tc, code, get_inv_callsite(), tc->cur_frame->args); return; } break; case MVM_BOOL_MODE_UNBOX_INT: result = !IS_CONCRETE(obj) || REPR(obj)->box_funcs->get_int(tc, STABLE(obj), obj, OBJECT_BODY(obj)) == 0 ? 0 : 1; break; case MVM_BOOL_MODE_UNBOX_NUM: result = !IS_CONCRETE(obj) || REPR(obj)->box_funcs->get_num(tc, STABLE(obj), obj, OBJECT_BODY(obj)) == 0.0 ? 0 : 1; break; case MVM_BOOL_MODE_UNBOX_STR_NOT_EMPTY: result = !IS_CONCRETE(obj) || NUM_GRAPHS(REPR(obj)->box_funcs->get_str(tc, STABLE(obj), obj, OBJECT_BODY(obj))) == 0 ? 0 : 1; break; case MVM_BOOL_MODE_UNBOX_STR_NOT_EMPTY_OR_ZERO: { MVMString *str; if (!IS_CONCRETE(obj)) { result = 0; break; } str = REPR(obj)->box_funcs->get_str(tc, STABLE(obj), obj, OBJECT_BODY(obj)); result = MVM_coerce_istrue_s(tc, str); break; } case MVM_BOOL_MODE_NOT_TYPE_OBJECT: result = !IS_CONCRETE(obj) ? 0 : 1; break; case MVM_BOOL_MODE_ITER: result = IS_CONCRETE(obj) ? MVM_iter_istrue(tc, (MVMIter *)obj) : 0; break; case MVM_BOOL_MODE_HAS_ELEMS: result = IS_CONCRETE(obj) ? MVM_repr_elems(tc, obj) != 0 : 0; break; default: MVM_exception_throw_adhoc(tc, "Invalid boolification spec mode used"); } } if (flip) result = result ? 0 : 1; if (res_reg) { res_reg->i64 = result; } else { if (result) *(tc->interp_cur_op) = true_addr; else *(tc->interp_cur_op) = false_addr; } }
MVMint64 MVM_coerce_istrue_s(MVMThreadContext *tc, MVMString *str) { return str == NULL || !IS_CONCRETE(str) || NUM_GRAPHS(str) == 0 || (NUM_GRAPHS(str) == 1 && MVM_string_get_codepoint_at_nocheck(tc, str, 0) == 48) ? 0 : 1; }