SLVAL sl_regexp_match(sl_vm_t* vm, SLVAL self, size_t argc, SLVAL* argv) { sl_regexp_t* re = get_regexp_check(vm, self); sl_string_t* str = sl_get_string(vm, argv[0]); int offset = 0, rc, ncaps; int* caps; sl_regexp_match_t* match; if(argc > 1) { offset = sl_get_int(sl_expect(vm, argv[1], vm->lib.Int)); } offset = sl_string_byte_offset_for_index(vm, argv[0], offset); if(offset < 0) { return vm->lib.nil; } pcre_fullinfo(re->re, re->study, PCRE_INFO_CAPTURECOUNT, &ncaps); ncaps += 1; ncaps *= 3; caps = sl_alloc(vm->arena, sizeof(int) * ncaps); rc = pcre_exec(re->re, re->study, (char*)str->buff, str->buff_len, offset, PCRE_NEWLINE_LF, caps, ncaps); if(rc == PCRE_ERROR_NOMATCH) { return vm->lib.nil; } check_pcre_error(vm, rc); match = (sl_regexp_match_t*)sl_get_ptr(sl_allocate(vm, vm->lib.Regexp_Match)); match->re = re; match->match_string = argv[0]; match->capture_count = ncaps / 3; match->captures = caps; return sl_make_ptr((sl_object_t*)match); }
void sl_pre_init_class(sl_vm_t* vm) { sl_class_t* obj = (sl_class_t*)allocate_class(vm); vm->lib.Class = sl_make_ptr((sl_object_t*)obj); obj->extra->allocator = allocate_class; obj->base.klass = vm->lib.Class; }
static SLVAL range_enumerate(sl_vm_t* vm, SLVAL self) { sl_range_t* range = get_range(vm, self); sl_range_enumerator_t* range_enum = get_range_enumerator(vm, sl_allocate(vm, vm->lib.Range_Enumerator)); range_enum->current = range->left; range_enum->right = range->right; range_enum->method = range->exclusive ? vm->id.op_lt : vm->id.op_lte; range_enum->state = ES_BEFORE; return sl_make_ptr((sl_object_t*)range_enum); }
SLVAL sl_method_bind(sl_vm_t* vm, SLVAL method, SLVAL receiver) { sl_method_t* methp = (sl_method_t*)sl_get_ptr(method); if(!(methp->base.user_flags & SL_FLAG_METHOD_INITIALIZED)) { sl_throw_message2(vm, vm->lib.TypeError, "Can't bind uninitialized Method"); } sl_method_t* bmethp = method_dup(vm, methp); bmethp->extra->bound_self = sl_expect(vm, receiver, methp->extra->klass); bmethp->base.klass = vm->lib.BoundMethod; return sl_make_ptr((sl_object_t*)bmethp); }
static sl_node_base_t* call_expression(sl_parse_state_t* ps) { sl_node_base_t* left = primary_expression(ps); sl_node_base_t** nodes; size_t node_len; size_t node_cap; sl_token_t* tok; if(left->type == SL_NODE_VAR && peek_token(ps)->type == SL_TOK_OPEN_PAREN) { left = send_with_args_expression(ps, sl_make_self_node(ps), sl_intern2(ps->vm, sl_make_ptr((sl_object_t*)((sl_node_var_t*)left)->name))); } while(1) { tok = peek_token(ps); switch(tok->type) { case SL_TOK_DOT: next_token(ps); left = send_expression(ps, left); break; case SL_TOK_COLON: next_token(ps); left = sl_make_bind_method_node(ps, left, def_expression_method_name(ps)); break; case SL_TOK_PAAMAYIM_NEKUDOTAYIM: next_token(ps); tok = expect_token(ps, SL_TOK_CONSTANT); left = sl_make_const_node(ps, left, sl_intern2(ps->vm, sl_make_string(ps->vm, tok->as.str.buff, tok->as.str.len))); break; case SL_TOK_OPEN_BRACKET: next_token(ps); node_cap = 1; node_len = 0; nodes = sl_alloc(ps->vm->arena, sizeof(SLVAL) * node_cap); while(peek_token(ps)->type != SL_TOK_CLOSE_BRACKET) { if(node_len >= node_cap) { node_cap *= 2; nodes = sl_realloc(ps->vm->arena, nodes, sizeof(SLVAL) * node_cap); } nodes[node_len++] = expression(ps); if(peek_token(ps)->type != SL_TOK_CLOSE_BRACKET) { expect_token(ps, SL_TOK_COMMA); } } expect_token(ps, SL_TOK_CLOSE_BRACKET); left = sl_make_send_node(ps, left, sl_intern(ps->vm, "[]"), node_len, nodes); break; default: return left; } } }
static SLVAL bound_method_unbind(sl_vm_t* vm, SLVAL bmethod) { sl_method_t* bmethp = (sl_method_t*)sl_get_ptr(bmethod); if(!(bmethp->base.user_flags & SL_FLAG_METHOD_INITIALIZED)) { sl_throw_message2(vm, vm->lib.TypeError, "Can't unbind uninitalized BoundMethod"); } sl_method_t* methp = method_dup(vm, bmethp); methp->extra->bound_self = vm->lib.nil; methp->base.klass = vm->lib.Method; return sl_make_ptr((sl_object_t*)methp); }
static SLVAL bound_method_unbind(sl_vm_t* vm, SLVAL bmethod) { sl_bound_method_t* bmethp = (sl_bound_method_t*)sl_get_ptr(bmethod); sl_method_t* methp = (sl_method_t*)sl_get_ptr(sl_allocate(vm, vm->lib.Method)); methp->name = bmethp->method.name; methp->is_c_func = bmethp->method.is_c_func; methp->arity = bmethp->method.arity; methp->klass = bmethp->method.klass; methp->as = bmethp->method.as; methp->initialized = 1; return sl_make_ptr((sl_object_t*)methp); }
void sl_response_set_opts(sl_vm_t* vm, sl_response_opts_t* opts) { sl_response_internal_opts_t* iopts = sl_alloc(vm->arena, sizeof(sl_response_internal_opts_t)); iopts->status = 200; iopts->buffered = opts->buffered; iopts->output_cap = 4; iopts->output_len = 0; iopts->output = sl_alloc(vm->arena, sizeof(SLVAL) * iopts->output_cap); iopts->write = opts->write; iopts->header_cap = 2; iopts->header_count = 0; iopts->headers = sl_alloc(vm->arena, sizeof(sl_response_key_value_t) * iopts->header_cap); iopts->descriptive_error_pages = opts->descriptive_error_pages; sl_vm_store_put(vm, &Response_opts, sl_make_ptr((sl_object_t*)iopts)); }
void sl_pre_init_class(sl_vm_t* vm) { sl_class_t* obj = sl_alloc(vm->arena, sizeof(sl_class_t)); vm->lib.Class = sl_make_ptr((sl_object_t*)obj); obj->name.id = 0; obj->super = vm->lib.Object; obj->in = vm->lib.Object; obj->constants = sl_st_init_table(vm, &sl_id_hash_type); obj->class_variables = sl_st_init_table(vm, &sl_id_hash_type); obj->instance_methods = sl_st_init_table(vm, &sl_id_hash_type); obj->allocator = allocate_class; obj->base.klass = vm->lib.Class; obj->base.primitive_type = SL_T_CLASS; obj->base.instance_variables = sl_st_init_table(vm, &sl_id_hash_type); }
SLVAL sl_string_times(sl_vm_t* vm, SLVAL self, SLVAL other) { sl_string_t* str = sl_get_string(vm, self); long mul = sl_get_int(sl_expect(vm, other, vm->lib.Int)); if(mul && (size_t)LONG_MAX / mul < str->buff_len) { sl_throw_message2(vm, vm->lib.ArgumentError, "String multiplier is too big"); } sl_string_t* new_str = sl_get_string(vm, sl_make_string(vm, NULL, 0)); new_str->buff_len = str->buff_len * mul; new_str->buff = sl_alloc(vm->arena, new_str->buff_len); for(size_t i = 0; i < new_str->buff_len; i += str->buff_len) { memcpy(new_str->buff + i, str->buff, str->buff_len); } new_str->char_len = str->char_len * mul; return sl_make_ptr((sl_object_t*)new_str); }
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_method_bind(sl_vm_t* vm, SLVAL method, SLVAL receiver) { sl_method_t* methp = (sl_method_t*)sl_get_ptr(method); sl_bound_method_t* bmethp = (sl_bound_method_t*)sl_get_ptr(sl_allocate(vm, vm->lib.BoundMethod)); if(!methp->initialized) { sl_throw_message2(vm, vm->lib.TypeError, "Can't bind uninitialized Method"); } bmethp->method.initialized = 1; bmethp->method.name = methp->name; bmethp->method.klass = methp->klass; bmethp->method.is_c_func = methp->is_c_func; bmethp->method.arity = methp->arity; bmethp->method.as = methp->as; bmethp->self = sl_expect(vm, receiver, methp->klass); return sl_make_ptr((sl_object_t*)bmethp); }
SLVAL sl_string_lower(sl_vm_t* vm, SLVAL selfv) { sl_string_t* self = sl_get_string(vm, selfv); sl_string_t* retn = sl_get_string(vm, sl_allocate(vm, vm->lib.String)); memcpy(retn, self, sizeof(sl_string_t)); retn->buff = sl_alloc_buffer(vm->arena, retn->buff_len); size_t len = self->buff_len; uint8_t* buff = self->buff; size_t out_offset = 0; uint32_t lower_c; while(len) { uint32_t c = sl_utf8_each_char(vm, &buff, &len); lower_c = sl_unicode_tolower(c); out_offset += sl_utf32_char_to_utf8(vm, lower_c, retn->buff + out_offset); } return sl_make_ptr((sl_object_t*)retn); }
SLVAL sl_regexp_match(sl_vm_t* vm, SLVAL self, size_t argc, SLVAL* argv) { sl_regexp_t* re = get_regexp_check(vm, self); sl_string_t* str = sl_get_string(vm, argv[0]); int offset = 0, rc, ncaps; int* caps; char err_buff[256]; sl_regexp_match_t* match; if(argc > 1) { offset = sl_get_int(sl_expect(vm, argv[1], vm->lib.Int)); } offset = sl_string_byte_offset_for_index(vm, argv[0], offset); if(offset < 0) { return vm->lib.nil; } pcre_fullinfo(re->re, re->study, PCRE_INFO_CAPTURECOUNT, &ncaps); ncaps += 1; ncaps *= 3; caps = sl_alloc(vm->arena, sizeof(int) * ncaps); rc = pcre_exec(re->re, re->study, (char*)str->buff, str->buff_len, offset, PCRE_NEWLINE_LF, caps, ncaps); if(rc < 0) { if(rc == PCRE_ERROR_NOMATCH) { return vm->lib.nil; } if(rc == PCRE_ERROR_BADUTF8) { sl_throw_message2(vm, vm->lib.EncodingError, "Invalid UTF-8 in regular expression or match text"); } sprintf(err_buff, "PCRE error (%d)", rc); sl_throw_message2(vm, vm->lib.Error, err_buff); } match = (sl_regexp_match_t*)sl_get_ptr(sl_allocate(vm, vm->lib.Regexp_Match)); match->re = re; match->match_string = argv[0]; match->capture_count = ncaps / 3; match->captures = caps; return sl_make_ptr((sl_object_t*)match); }
static SLVAL sl_class_instance_method(sl_vm_t* vm, SLVAL self, SLVAL method_name) { sl_class_t* klass = get_class(vm, self); SLVAL method; SLID mid = sl_intern2(vm, method_name); method_name = sl_to_s(vm, method_name); if(sl_st_lookup(klass->instance_methods, (sl_st_data_t)mid.id, (sl_st_data_t*)&method)) { if(sl_get_primitive_type(method) == SL_T_CACHED_METHOD_ENTRY) { sl_cached_method_entry_t* cme = (void*)sl_get_ptr(method); // TODO - improve cache invalidation. this is too coarse if(cme->state == vm->state_method) { return sl_make_ptr((sl_object_t*)cme->method); } } else { return method; } } if(sl_get_primitive_type(klass->super) == SL_T_CLASS) { return sl_class_instance_method(vm, klass->super, method_name); } return vm->lib.nil; }
NODE(sl_node_var_t, var) { sl_vm_insn_t insn; size_t frame; sl_compile_state_t* xcs = cs; size_t index = 0xCAFE; SLVAL err; frame = 0; while(xcs) { if(st_lookup(xcs->vars, (st_data_t)node->name, (st_data_t*)&index)) { if(frame == 0) { insn.opcode = SL_OP_MOV; emit(cs, insn); } else { insn.opcode = SL_OP_GET_OUTER; emit(cs, insn); insn.uint = frame; emit(cs, insn); mark_upper_scopes_as_closure_unsafe(cs, frame); } insn.uint = index; emit(cs, insn); insn.uint = dest; emit(cs, insn); return; } xcs = xcs->parent; frame++; } err = sl_make_cstring(cs->vm, "Undefined variable '"); err = sl_string_concat(cs->vm, err, sl_make_ptr((sl_object_t*)node->name)); err = sl_string_concat(cs->vm, err, sl_make_cstring(cs->vm, "' ")); err = sl_make_error2(cs->vm, cs->vm->lib.NameError, err); sl_error_add_frame(cs->vm, err, sl_make_cstring(cs->vm, "<compiler>"), sl_make_cstring(cs->vm, (char*)cs->section->filename), sl_make_int(cs->vm, node->base.line)); sl_throw(cs->vm, err); }
static SLVAL sl_regexp_match_regexp(sl_vm_t* vm, SLVAL self) { return sl_make_ptr((sl_object_t*)get_regexp_match(vm, self)->re); }
NODE(sl_node_var_t, cvar) { SLID id = sl_intern2(cs->vm, sl_make_ptr((sl_object_t*)node->name)); op_get_cvar(cs, id, dest); }