SLVAL sl_string_char_at_index(sl_vm_t* vm, SLVAL self, SLVAL index) { sl_string_t* str = sl_get_string(vm, self); if(sl_is_a(vm, index, vm->lib.Range_Inclusive) || sl_is_a(vm, index, vm->lib.Range_Exclusive)) { return string_range_index(vm, self, index); } long idx = sl_get_int(sl_expect(vm, index, vm->lib.Int)); if(idx < 0) { idx += str->char_len; } if(idx < 0 || idx >= (long)str->char_len) { return vm->lib.nil; } uint8_t* buff_ptr = str->buff; size_t len = str->buff_len; while(idx) { sl_utf8_each_char(vm, &buff_ptr, &len); idx--; } size_t slice_len = 1; while(slice_len < len && (buff_ptr[slice_len] & 0xc0) == 0x80) { slice_len++; } return sl_make_string(vm, buff_ptr, slice_len); }
static SLVAL sl_string_replace(sl_vm_t* vm, SLVAL self, SLVAL search, SLVAL replace) { if(sl_is_a(vm, search, vm->lib.String)) { return sl_enumerable_join(vm, sl_string_split(vm, self, 1, &search), 1, &replace); } sl_expect(vm, search, vm->lib.Regexp); SLVAL retn = sl_make_cstring(vm, ""); while(1) { SLVAL match = sl_regexp_match(vm, search, 1, &self); if(!sl_is_truthy(match)) { return sl_string_concat(vm, retn, self); } else { SLVAL part = sl_regexp_match_before(vm, match); if(sl_is_a(vm, replace, vm->lib.String)) { part = sl_string_concat(vm, part, replace); } else { part = sl_string_concat(vm, part, sl_send_id(vm, replace, vm->id.call, 1, match)); } retn = sl_string_concat(vm, retn, part); } self = sl_regexp_match_after(vm, match); } }
SLVAL sl_float_pow(sl_vm_t* vm, SLVAL self, SLVAL other) { if(sl_is_a(vm, other, vm->lib.Bignum)) { return sl_float_pow(vm, self, sl_bignum_to_f(vm, other)); } if(sl_is_a(vm, other, vm->lib.Int)) { return sl_float_pow(vm, self, sl_make_float(vm, sl_get_int(other))); } return sl_make_float(vm, pow(sl_get_float(vm, self), sl_get_float(vm, other))); }
static void parse_query_string(sl_vm_t* vm, SLVAL dict, size_t len, uint8_t* query_string) { uint8_t *key = query_string, *value = NULL; size_t key_len = 0, value_len = 0; size_t i; SLVAL addee = dict, k, v; int bracket_mode = 0, in_bracket = 0; for(i = 0; i <= len; i++) { if(i == len || query_string[i] == '&') { if(key_len > 0) { k = sl_string_url_decode(vm, sl_make_string(vm, key, key_len)); if(value) { v = sl_string_url_decode(vm, sl_make_string(vm, value, value_len)); } sl_dict_set(vm, addee, k, value ? v : vm->lib.nil); } key = query_string + i + 1; key_len = 0; value = NULL; value_len = 0; addee = dict; in_bracket = 0; bracket_mode = 0; continue; } if(query_string[i] == '=' && !value) { value = query_string + i + 1; continue; } if(value) { value_len++; } else { if(query_string[i] == '[') { k = sl_make_string(vm, key, key_len); key = query_string + i + 1; key_len = 0; if(!sl_is_a(vm, sl_dict_get(vm, addee, k), vm->lib.Dict)) { sl_dict_set(vm, addee, k, sl_make_dict(vm, 0, NULL)); } addee = sl_dict_get(vm, addee, k); in_bracket = 1; bracket_mode = 1; continue; } if(query_string[i] == ']' && in_bracket) { in_bracket = 0; continue; } if(bracket_mode && !in_bracket) { /* skip until \0, & or = */ while(i + 1 < len && query_string[i + 1] != '&' && query_string[i + 1] != '=') { i++; } continue; } key_len++; } } }
SLVAL sl_float_cmp(sl_vm_t* vm, SLVAL self, SLVAL other) { if(sl_is_a(vm, other, vm->lib.Int)) { return sl_float_cmp(vm, self, sl_make_float(vm, sl_get_int(other))); } if(sl_is_a(vm, other, vm->lib.Bignum)) { return sl_make_int(vm, -sl_get_int(sl_bignum_cmp(vm, other, self))); } sl_expect(vm, other, vm->lib.Float); if(sl_get_float(vm, self) < sl_get_float(vm, other)) { return sl_make_int(vm, -1); } else if(sl_get_float(vm, self) > sl_get_float(vm, other)) { return sl_make_int(vm, 1); } else { return sl_make_int(vm, 0); } }
SLVAL sl_float_eq(sl_vm_t* vm, SLVAL self, SLVAL other) { if(sl_is_a(vm, other, vm->lib.Int)) { return sl_float_eq(vm, self, sl_make_float(vm, sl_get_int(other))); } if(sl_is_a(vm, other, vm->lib.Bignum)) { if(fmod(sl_get_float(vm, self), 1.0) == 0.0) { return sl_bignum_eq(vm, sl_make_bignum_f(vm, sl_get_float(vm, self)), other); } else { return vm->lib._false; } } if(!sl_is_a(vm, other, vm->lib.Float)) { return vm->lib._false; } return sl_make_bool(vm, sl_get_float(vm, self) == sl_get_float(vm, other)); }
SLVAL sl_string_is_match(sl_vm_t* vm, SLVAL self, SLVAL other) { if(sl_is_a(vm, other, vm->lib.String)) { SLVAL idx = sl_string_index(vm, self, other); return sl_make_bool(vm, sl_get_ptr(idx) != sl_get_ptr(vm->lib.nil)); } return sl_regexp_is_match(vm, other, self); }
static SLVAL string_range_index(sl_vm_t* vm, SLVAL self, SLVAL range) { sl_string_t* str = sl_get_string(vm, self); SLVAL lowerv = sl_range_lower(vm, range); SLVAL upperv = sl_range_upper(vm, range); if(!sl_is_a(vm, lowerv, vm->lib.Int) || !sl_is_a(vm, upperv, vm->lib.Int)) { sl_throw_message2(vm, vm->lib.TypeError, "Expected range of integers"); } long lower = sl_get_int(lowerv), upper = sl_get_int(upperv); if(lower < 0) { lower += str->char_len; } if(lower < 0 || (size_t)lower >= str->char_len) { return sl_make_cstring(vm, ""); } if(upper < 0) { upper += str->char_len; } if(upper < 0) { return sl_make_cstring(vm, ""); } if(sl_range_is_exclusive(vm, range)) { upper--; } if(upper < lower) { return sl_make_cstring(vm, ""); } uint8_t* begin_ptr = str->buff; uint8_t* end_ptr; size_t len = str->buff_len; long idx = 0; while(idx < lower && len) { idx++; sl_utf8_each_char(vm, &begin_ptr, &len); } end_ptr = begin_ptr; while(lower <= upper) { lower++; sl_utf8_each_char(vm, &end_ptr, &len); } return sl_make_string(vm, begin_ptr, (size_t)end_ptr - (size_t)begin_ptr); }
SLVAL sl_string_eq(sl_vm_t* vm, SLVAL self, SLVAL other) { if(!sl_is_a(vm, other, vm->lib.String)) { return vm->lib._false; } sl_string_t* a = sl_get_string(vm, self); sl_string_t* b = sl_get_string(vm, other); return sl_make_bool(vm, str_cmp(vm, a, b) == 0); }
static SLVAL vm_helper_define_singleton_method(sl_vm_exec_ctx_t* ctx, SLVAL on, SLID name, sl_vm_section_t* section) { SLVAL klass = on, method; if(!sl_is_a(ctx->vm, klass, ctx->vm->lib.Class)) { klass = sl_class_of(ctx->vm, klass); } method = sl_make_method(ctx->vm, klass, name, section, ctx); sl_define_singleton_method3(ctx->vm, on, name, method); return method; }
static int cap_index(sl_vm_t* vm, SLVAL regexp_match, SLVAL i) { sl_regexp_match_t* match = get_regexp_match(vm, regexp_match); int index; if(sl_is_a(vm, i, vm->lib.String)) { char* named_cap = sl_to_cstr(vm, i); index = pcre_get_stringnumber(match->re->re, named_cap); if(index < 0) { return -1; } } else { index = sl_get_int(sl_expect(vm, i, vm->lib.Int)); } if(index < 0 || index >= match->capture_count) { return -1; } return index * 2; }
static SLVAL sl_regexp_eq(sl_vm_t* vm, SLVAL self, SLVAL other) { if(!sl_is_a(vm, other, vm->lib.Regexp)) { return vm->lib._false; } sl_regexp_t* re = get_regexp(vm, self); sl_regexp_t* oth = get_regexp(vm, other); if(!oth->re || !re->re) { return vm->lib._false; } if(!sl_is_truthy(sl_string_eq(vm, re->source, oth->source))) { return vm->lib._false; } if(re->options != oth->options) { return vm->lib._false; } return vm->lib._true; }
void sl_request_set_opts(sl_vm_t* vm, sl_request_opts_t* opts) { size_t i; SLVAL n, v, cookies; sl_string_t* str; sl_request_internal_opts_t* req = sl_alloc(vm->arena, sizeof(sl_request_internal_opts_t)); req->method = sl_make_cstring(vm, opts->method); req->uri = sl_make_cstring(vm, opts->uri); req->path_info = sl_make_cstring(vm, opts->path_info ? opts->path_info : ""); req->query_string = sl_make_cstring(vm, opts->query_string ? opts->query_string : ""); req->remote_addr = sl_make_cstring(vm, opts->remote_addr); req->headers = sl_make_dict(vm, 0, NULL); req->env = sl_make_dict(vm, 0, NULL); req->get = sl_make_dict(vm, 0, NULL); req->post = sl_make_dict(vm, 0, NULL); req->post_data = sl_make_string(vm, (uint8_t*)opts->post_data, opts->post_length); req->cookies = sl_make_dict(vm, 0, NULL); for(i = 0; i < opts->header_count; i++) { n = sl_make_cstring(vm, opts->headers[i].name); v = sl_make_cstring(vm, opts->headers[i].value); sl_dict_set(vm, req->headers, n, v); } for(i = 0; i < opts->env_count; i++) { n = sl_make_cstring(vm, opts->env[i].name); v = sl_make_cstring(vm, opts->env[i].value); sl_dict_set(vm, req->env, n, v); } if(opts->query_string) { parse_query_string(vm, req->get, strlen(opts->query_string), (uint8_t*)opts->query_string); } if(opts->content_type && strcmp(opts->content_type, "application/x-www-form-urlencoded") == 0) { parse_query_string(vm, req->post, opts->post_length, (uint8_t*)opts->post_data); } cookies = sl_dict_get(vm, req->headers, sl_make_cstring(vm, "Cookie")); if(sl_is_a(vm, cookies, vm->lib.String)) { str = (sl_string_t*)sl_get_ptr(cookies); parse_cookie_string(vm, req->cookies, str->buff_len, str->buff); } req->params = sl_dict_merge(vm, req->get, req->post); sl_vm_store_put(vm, &Request_opts, sl_make_ptr((sl_object_t*)req)); }
SLVAL sl_string_eq(sl_vm_t* vm, SLVAL self, SLVAL other) { if(!sl_is_a(vm, other, vm->lib.String)) { return vm->lib._false; } sl_string_t* a = sl_get_string(vm, self); sl_string_t* b = sl_get_string(vm, other); if(a->encoding == b->encoding) { if(str_cmp((sl_string_t*)sl_get_ptr(self), (sl_string_t*)sl_get_ptr(other)) == 0) { return vm->lib._true; } else { return vm->lib._false; } } sl_vm_frame_t frame; SLVAL err; volatile SLVAL retn; SL_TRY(frame, SL_UNWIND_EXCEPTION, { retn = sl_string_eq(vm, self, sl_string_encode(vm, other, a->encoding)); }, err, {
static SLVAL vm_helper_define_class(sl_vm_exec_ctx_t* ctx, SLID name, SLVAL extends, sl_vm_section_t* section) { SLVAL klass, in; sl_vm_exec_ctx_t* subctx; if(sl_class_has_const2(ctx->vm, ctx->self, name)) { /* @TODO: verify same superclass */ klass = sl_class_get_const2(ctx->vm, ctx->self, name); } else { in = ctx->self; if(!sl_is_a(ctx->vm, in, ctx->vm->lib.Class)) { in = sl_class_of(ctx->vm, in); } klass = sl_define_class3(ctx->vm, name, extends, in); } subctx = sl_alloc(ctx->vm->arena, sizeof(sl_vm_exec_ctx_t)); subctx->vm = ctx->vm; subctx->section = section; subctx->registers = sl_alloc(ctx->vm->arena, sizeof(SLVAL) * section->max_registers); subctx->self = klass; subctx->parent = ctx; sl_vm_exec(subctx, 0); return klass; }
static SLVAL true_eq(sl_vm_t* vm, SLVAL self, SLVAL other) { (void)self; return sl_make_bool(vm, sl_is_a(vm, other, vm->lib.True)); }