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++; } } }
static void parse_cookie_string(sl_vm_t* vm, SLVAL dict, size_t len, uint8_t* cookies) { uint8_t *key = NULL, *value = NULL; size_t key_len = 0, value_len = 0; size_t i; for(i = 0; i <= len; i++) { if(i == len || cookies[i] == ';') { if(key_len) { sl_dict_set(vm, dict, sl_string_url_decode(vm, sl_make_string(vm, key, key_len)), sl_string_url_decode(vm, sl_make_string(vm, value, value_len))); } key_len = 0; value_len = 0; key = NULL; value = NULL; } if(cookies[i] != ' ' && !key) { key = cookies + i; key_len++; continue; } if(cookies[i] == '=' && !value) { value = cookies + i + 1; continue; } if(!value) { key_len++; } else { value_len++; } } }
static int on_map_key(void* ctx, const uint8_t* str, size_t len) { json_parse_t* json = ctx; json->key = sl_make_string(json->vm, (uint8_t*)str, len); return 1; }
SLVAL sl_string_html_escape(sl_vm_t* vm, SLVAL self) { sl_string_t* str = sl_get_string(vm, self); size_t out_cap = 32; size_t out_len = 0; size_t str_i; uint8_t* out = sl_alloc_buffer(vm->arena, out_cap); for(str_i = 0; str_i < str->buff_len; str_i++) { if(out_len + 8 >= out_cap) { out_cap *= 2; out = sl_realloc(vm->arena, out, out_cap); } if(str->buff[str_i] == '<') { memcpy(out + out_len, "<", 4); out_len += 4; } else if(str->buff[str_i] == '>') { memcpy(out + out_len, ">", 4); out_len += 4; } else if(str->buff[str_i] == '"') { memcpy(out + out_len, """, 6); out_len += 6; } else if(str->buff[str_i] == '\'') { memcpy(out + out_len, "'", 6); out_len += 6; } else if(str->buff[str_i] == '&') { memcpy(out + out_len, "&", 5); out_len += 5; } else { out[out_len++] = str->buff[str_i]; } } return sl_make_string(vm, out, out_len); }
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); }
SLVAL sl_string_url_decode(sl_vm_t* vm, SLVAL self) { sl_string_t* str = sl_get_string(vm, self); size_t out_cap = 32; size_t out_len = 0; uint8_t* out = sl_alloc_buffer(vm->arena, out_cap); size_t str_i; char tmp[3]; for(str_i = 0; str_i < str->buff_len; str_i++) { if(out_len + 8 >= out_cap) { out_cap *= 2; out = sl_realloc(vm->arena, out, out_cap); } if(str->buff[str_i] == '%') { if(str_i + 2 < str->buff_len) { if(is_hex_char(str->buff[str_i + 1]) && is_hex_char(str->buff[str_i + 2])) { tmp[0] = str->buff[str_i + 1]; tmp[1] = str->buff[str_i + 2]; tmp[2] = 0; out[out_len++] = strtol(tmp, NULL, 16); str_i += 2; continue; } } } if(str->buff[str_i] == '+') { out[out_len++] = ' '; continue; } out[out_len++] = str->buff[str_i]; } return sl_make_string(vm, out, out_len); }
static int on_string(void* ctx, const uint8_t* str, size_t len) { json_parse_t* json = ctx; SLVAL s = sl_make_string(json->vm, (uint8_t*)str, len); JSON_ADD_VALUE(s); return 1; }
SLVAL sl_regexp_match_after(sl_vm_t* vm, SLVAL self) { sl_regexp_match_t* match = get_regexp_match(vm, self); int index = cap_index(vm, self, sl_make_int(vm, 0)); sl_string_t* str = (sl_string_t*)sl_get_ptr(match->match_string); return sl_make_string(vm, str->buff + match->captures[index + 1], str->buff_len - match->captures[index + 1]); }
static SLVAL sl_mysql_escape(sl_vm_t* vm, SLVAL self, SLVAL str) { mysql_t* mysql = get_mysql(vm, self); sl_string_t* s = sl_get_string(vm, str); char* esc = sl_alloc(vm->arena, s->buff_len * 2 + 1); size_t esc_len = mysql_real_escape_string(&mysql->mysql, esc, (char*)s->buff, s->buff_len); return sl_make_string(vm, (uint8_t*)esc, esc_len); }
SLVAL sl_string_concat(sl_vm_t* vm, SLVAL self, SLVAL other) { sl_string_t* a = sl_get_string(vm, self); sl_string_t* b = sl_get_string(vm, other); uint8_t* buff = (uint8_t*)sl_alloc_buffer(vm->arena, a->buff_len + b->buff_len); memcpy(buff, a->buff, a->buff_len); memcpy(buff + a->buff_len, b->buff, b->buff_len); return sl_make_string(vm, buff, a->buff_len + b->buff_len); }
static sl_node_base_t* lambda_expression(sl_parse_state_t* ps) { sl_node_base_t* body; sl_token_t* tok; size_t arg_count = 0, arg_cap = 2; sl_string_t** args = sl_alloc(ps->vm->arena, sizeof(sl_string_t*) * arg_cap); sl_parse_scope_t scope; expect_token(ps, SL_TOK_LAMBDA); if(peek_token(ps)->type == SL_TOK_IDENTIFIER) { tok = next_token(ps); args[arg_count++] = (sl_string_t*)sl_get_ptr( sl_make_string(ps->vm, tok->as.str.buff, tok->as.str.len)); } else if(peek_token(ps)->type != SL_TOK_OPEN_BRACE && peek_token(ps)->type != SL_TOK_DOT) { expect_token(ps, SL_TOK_OPEN_PAREN); while(peek_token(ps)->type != SL_TOK_CLOSE_PAREN) { if(arg_count >= arg_cap) { arg_cap *= 2; args = sl_realloc(ps->vm->arena, args, sizeof(sl_string_t*) * arg_cap); } tok = expect_token(ps, SL_TOK_IDENTIFIER); args[arg_count++] = (sl_string_t*)sl_get_ptr( sl_make_string(ps->vm, tok->as.str.buff, tok->as.str.len)); if(peek_token(ps)->type != SL_TOK_CLOSE_PAREN) { expect_token(ps, SL_TOK_COMMA); } } expect_token(ps, SL_TOK_CLOSE_PAREN); } scope.prev = ps->scope; scope.flags = SL_PF_CAN_RETURN; ps->scope = &scope; if(peek_token(ps)->type == SL_TOK_DOT) { next_token(ps); body = expression(ps); } else { body = body_expression(ps); } ps->scope = scope.prev; ps->scope->flags |= SL_PF_SCOPE_CLOSURE; return sl_make_lambda_node(ps, arg_count, args, body); }
SLVAL sl_regexp_match_index(sl_vm_t* vm, SLVAL self, SLVAL i) { sl_regexp_match_t* match = get_regexp_match(vm, self); int index = cap_index(vm, self, i); if(index < 0) { return vm->lib.nil; } sl_string_t* str = (sl_string_t*)sl_get_ptr(match->match_string); return sl_make_string(vm, str->buff + match->captures[index], match->captures[index + 1] - match->captures[index]); }
static sl_node_base_t* class_expression(sl_parse_state_t* ps) { sl_token_t* class_token = expect_token(ps, SL_TOK_CLASS); SLVAL doc = ps->vm->lib.nil; if(class_token->comment) { doc = sl_make_string(ps->vm, class_token->comment->buff, class_token->comment->len); } sl_token_t* tok = expect_token(ps, SL_TOK_CONSTANT); SLID name = sl_intern2(ps->vm, sl_make_string(ps->vm, tok->as.str.buff, tok->as.str.len)); sl_node_base_t *extends, *body; if(peek_token(ps)->type == SL_TOK_EXTENDS) { next_token(ps); extends = expression(ps); } else { extends = NULL; } body = body_expression(ps); return sl_make_class_node(ps, name, doc, extends, body); }
static sl_node_base_t* send_expression(sl_parse_state_t* ps, sl_node_base_t* recv) { SLVAL id; sl_token_t* tok; tok = expect_token(ps, SL_TOK_IDENTIFIER); id = sl_make_string(ps->vm, tok->as.str.buff, tok->as.str.len); if(peek_token(ps)->type != SL_TOK_OPEN_PAREN) { return sl_make_send_node(ps, recv, sl_intern2(ps->vm, id), 0, NULL); } return send_with_args_expression(ps, recv, sl_intern2(ps->vm, id)); }
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 void output(sl_vm_t* sub_vm, char* buff, size_t len) { slash_t* sl = sub_vm->data; sl_vm_t* vm = sl->host_vm; if(sl_responds_to2(vm, sl->output_handler, vm->id.call)) { SLVAL ex; sl_vm_frame_t catch_frame; SL_TRY(catch_frame, SL_UNWIND_ALL, { SLVAL string = sl_make_string(vm, (uint8_t*)buff, len); sl_send_id(vm, sl->output_handler, vm->id.call, 1, string); }, ex, {
SLVAL sl_string_concat(sl_vm_t* vm, SLVAL self, SLVAL other) { sl_string_t* a = sl_get_string(vm, self); sl_string_t* b = sl_get_string(vm, other); if(strcmp(a->encoding, b->encoding) != 0) { return sl_string_concat(vm, self, sl_string_encode(vm, other, a->encoding)); } uint8_t* buff = (uint8_t*)sl_alloc_buffer(vm->arena, a->buff_len + b->buff_len); memcpy(buff, a->buff, a->buff_len); memcpy(buff + a->buff_len, b->buff, b->buff_len); return sl_make_string(vm, buff, a->buff_len + b->buff_len); }
static SLVAL sl_gcrypt_algorithm_hex_digest(sl_vm_t* vm, SLVAL self, SLVAL strv) { size_t i; sl_string_t* str = sl_get_string(vm, strv); gcrypt_algorithm_t* algo = get_algo_check(vm, self); size_t digest_len = gcry_md_get_algo_dlen(algo->algo); char* digest = alloca(digest_len); char* hex_digest = alloca(digest_len * 2); gcry_md_hash_buffer(algo->algo, digest, str->buff, str->buff_len); for(i = 0; i < digest_len; i++) { sprintf(hex_digest + 2 * i, "%02x", (uint8_t)digest[i]); } return sl_make_string(vm, (uint8_t*)hex_digest, digest_len * 2); }
static SLVAL sl_json_dump(sl_vm_t* vm, SLVAL self, SLVAL object) { json_dump_t dump; dump.vm = vm; dump.buffer_len = 0; dump.buffer_cap = 32; dump.buffer = sl_alloc_buffer(vm->arena, dump.buffer_cap); dump.seen_len = 0; dump.seen_cap = 32; dump.seen_ptrs = sl_alloc(vm->arena, sizeof(void*) * dump.seen_cap); json_dump(&dump, object); return sl_make_string(vm, dump.buffer, dump.buffer_len); (void)self; }
SLVAL sl_string_url_encode(sl_vm_t* vm, SLVAL self) { sl_string_t* str = sl_get_string(vm, self); size_t out_cap = 32; size_t out_len = 0; uint8_t* out = sl_alloc_buffer(vm->arena, out_cap); size_t clen = str->buff_len; uint8_t* cbuff = str->buff; uint32_t c; uint8_t utf8buff[8]; uint32_t utf8len; while(clen) { if(out_len + 16 >= out_cap) { out_cap *= 2; out = sl_realloc(vm->arena, out, out_cap); } c = sl_utf8_each_char(vm, &cbuff, &clen); if(c >= 'A' && c <= 'Z') { out[out_len++] = c; continue; } if(c >= 'a' && c <= 'z') { out[out_len++] = c; continue; } if(c >= '0' && c <= '9') { out[out_len++] = c; continue; } if(c == '-' || c == '_' || c == '.' || c == '~') { out[out_len++] = c; continue; } if(c == ' ') { out[out_len++] = '+'; continue; } utf8len = sl_utf32_char_to_utf8(vm, c, utf8buff); for(unsigned int i = 0; i < utf8len; i++) { sprintf((char*)out + out_len, "%%%2X", utf8buff[i]); out_len += 3; } } return sl_make_string(vm, out, out_len); }
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); }
SLVAL sl_string_inspect(sl_vm_t* vm, SLVAL self) { sl_string_t* str = sl_get_string(vm, self); size_t out_cap = 32; size_t out_len = 0; size_t str_i; uint8_t* out = sl_alloc_buffer(vm->arena, out_cap); out[out_len++] = '"'; for(str_i = 0; str_i < str->buff_len; str_i++) { if(out_len + 8 >= out_cap) { out_cap *= 2; out = sl_realloc(vm->arena, out, out_cap); } if(str->buff[str_i] == '"') { memcpy(out + out_len, "\\\"", 2); out_len += 2; } else if(str->buff[str_i] == '\\') { memcpy(out + out_len, "\\\\", 2); out_len += 2; } else if(str->buff[str_i] == '\n') { memcpy(out + out_len, "\\n", 2); out_len += 2; } else if(str->buff[str_i] == '\r') { memcpy(out + out_len, "\\r", 2); out_len += 2; } else if(str->buff[str_i] == '\t') { memcpy(out + out_len, "\\t", 2); out_len += 2; } else if(str->buff[str_i] < 0x20) { out[out_len++] = '\\'; out[out_len++] = 'x'; out[out_len++] = '0' + str->buff[str_i] / 0x10; if(str->buff[str_i] % 0x10 < 10) { out[out_len++] = '0' + str->buff[str_i] % 0x10; } else { out[out_len++] = 'A' + (str->buff[str_i] % 0x10) - 10; } } else { out[out_len++] = str->buff[str_i]; } } out[out_len++] = '"'; return sl_make_string(vm, out, out_len); }
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); }
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)); }
static SLVAL sl_mysql_raw_query(sl_vm_t* vm, SLVAL self, SLVAL query) { mysql_t* mysql = get_mysql(vm, self); sl_string_t* str = sl_get_string(vm, query); if(mysql_real_query(&mysql->mysql, (char*)str->buff, str->buff_len)) { sl_mysql_check_error(vm, &mysql->mysql); } MYSQL_RES* result; if((result = mysql_store_result(&mysql->mysql))) { /* do shit */ int ncolumns = mysql_num_fields(result); int nrows = mysql_num_rows(result); SLVAL* rows = sl_alloc(vm->arena, sizeof(SLVAL) * nrows); MYSQL_FIELD* fields = mysql_fetch_fields(result); for(int i = 0; i < nrows; i++) { SLVAL* cells = sl_alloc(vm->arena, sizeof(SLVAL) * ncolumns * 2); MYSQL_ROW row = mysql_fetch_row(result); size_t* lengths = mysql_fetch_lengths(result); for(int j = 0; j < ncolumns; j++) { cells[j * 2] = sl_make_cstring(vm, fields[j].name); if(row[j]) { cells[j * 2 + 1] = sl_make_string(vm, (uint8_t*)row[j], lengths[j]); } else { cells[j * 2 + 1] = vm->lib.nil; } } rows[i] = sl_make_dict(vm, ncolumns, cells); } mysql_free_result(result); return sl_make_array(vm, nrows, rows); } else { if(mysql_field_count(&mysql->mysql) != 0) { sl_mysql_check_error(vm, &mysql->mysql); } return sl_make_int(vm, mysql_affected_rows(&mysql->mysql)); } }
static void sl_setup_regexp(sl_vm_t* vm, sl_regexp_t* re_ptr, uint8_t* re_buff, size_t re_len, uint8_t* opts_buff, size_t opts_len) { char buff[256]; const char* error; char* rez; int error_offset; int opts = DEFAULT_OPTIONS; pcre* re; size_t i; for(i = 0; i < opts_len; i++) { switch(opts_buff[i]) { case 'i': opts |= PCRE_CASELESS; break; case 'x': opts |= PCRE_EXTENDED; break; default: sprintf(buff, "Unknown regular expression option '%c'", opts_buff[i]); sl_throw_message2(vm, vm->lib.ArgumentError, buff); } } if(memchr(re_buff, 0, re_len)) { sl_throw_message2(vm, vm->lib.ArgumentError, "Regular expression contains null byte"); } rez = sl_alloc_buffer(vm->arena, re_len + 1); memcpy(rez, re_buff, re_len); rez[re_len] = 0; re = pcre_compile(rez, opts, &error, &error_offset, NULL); if(!re) { sl_throw_message2(vm, vm->lib.SyntaxError, (char*)error); } re_ptr->source = sl_make_string(vm, re_buff, re_len); re_ptr->options = opts; re_ptr->re = re; re_ptr->study = NULL; }
static SLVAL sl_mysql_stmt_execute(sl_vm_t* vm, SLVAL self, size_t argc, SLVAL* argv) { mysql_stmt_t* stmt = get_mysql_stmt(vm, self); size_t req = mysql_stmt_param_count(stmt->stmt); if(argc < req) { char buff[100]; sprintf(buff, "Prepared statement has %lu parameter markers, but only %lu parameters were given", req, argc); sl_throw_message2(vm, vm->lib.ArgumentError, buff); } if(!stmt->bind) { stmt->bind = sl_alloc(vm->arena, sizeof(MYSQL_BIND) * req); } for(size_t i = 0; i < req; i++) { stmt->bind[i].buffer_type = MYSQL_TYPE_STRING; sl_string_t* str = sl_get_string(vm, sl_to_s(vm, argv[i])); stmt->bind[i].buffer = str->buff; stmt->bind[i].buffer_length = str->buff_len; stmt->bind[i].length = NULL; stmt->bind[i].is_null = NULL; stmt->bind[i].is_unsigned = 1; stmt->bind[i].error = NULL; } if(mysql_stmt_bind_param(stmt->stmt, stmt->bind)) { sl_mysql_stmt_check_error(vm, stmt->stmt); } if(mysql_stmt_execute(stmt->stmt)) { sl_mysql_stmt_check_error(vm, stmt->stmt); } MYSQL_RES* res = mysql_stmt_result_metadata(stmt->stmt); if(!res) { /* query did not produce a result set */ return sl_make_int(vm, mysql_stmt_affected_rows(stmt->stmt)); } int field_count = mysql_stmt_field_count(stmt->stmt); MYSQL_FIELD* field; SLVAL field_names[field_count]; enum enum_field_types field_types[field_count]; size_t field_i = 0; while((field = mysql_fetch_field(res))) { field_names[field_i] = sl_make_cstring(vm, field->name); if(field->type == MYSQL_TYPE_LONG || field->type == MYSQL_TYPE_SHORT || field->type == MYSQL_TYPE_TINY) { field_types[field_i] = MYSQL_TYPE_LONG; } else { field_types[field_i] = MYSQL_TYPE_STRING; } field_i++; } MYSQL_BIND output_binds[field_count]; my_bool output_errors[field_count]; my_bool output_is_nulls[field_count]; unsigned long output_lengths[field_count]; for(int i = 0; i < field_count; i++) { output_binds[i].buffer_type = MYSQL_TYPE_STRING; output_binds[i].buffer = NULL; output_binds[i].buffer_length = 0; output_binds[i].length = &output_lengths[i]; output_binds[i].is_null = &output_is_nulls[i]; output_binds[i].error = &output_errors[i]; } if(mysql_stmt_bind_result(stmt->stmt, output_binds)) { sl_mysql_stmt_check_error(vm, stmt->stmt); } SLVAL result_rows = sl_make_array(vm, 0, NULL); while(1) { int code = mysql_stmt_fetch(stmt->stmt); if(code == MYSQL_NO_DATA) { break; } if(code == 1) { sl_mysql_stmt_check_error(vm, stmt->stmt); } SLVAL row = sl_make_dict(vm, 0, NULL); for(int i = 0; i < field_count; i++) { MYSQL_BIND cell; cell.length = &output_lengths[i]; cell.is_null = &output_is_nulls[i]; cell.error = &output_errors[i]; cell.buffer_type = field_types[i]; int buffer_long; switch(field_types[i]) { case MYSQL_TYPE_LONG: cell.buffer = &buffer_long; cell.buffer_length = sizeof(buffer_long); break; default: /* MYSQL_TYPE_STRING */ cell.buffer = sl_alloc_buffer(vm->arena, output_lengths[i] + 1); cell.buffer_length = output_lengths[i]; break; } if(mysql_stmt_fetch_column(stmt->stmt, &cell, i, 0)) { sl_mysql_stmt_check_error(vm, stmt->stmt); } switch(field_types[i]) { case MYSQL_TYPE_LONG: sl_dict_set(vm, row, field_names[i], sl_make_int(vm, buffer_long)); break; default: /* MYSQL_TYPE_STRING */ sl_dict_set(vm, row, field_names[i], sl_make_string(vm, cell.buffer, output_lengths[i])); break; } } sl_array_push(vm, result_rows, 1, &row); } return result_rows; }
static sl_node_base_t* static_string_expression(sl_parse_state_t* ps) { sl_token_t* tok = expect_token(ps, SL_TOK_STRING); return sl_make_immediate_node(ps, sl_make_string(ps->vm, tok->as.str.buff, tok->as.str.len)); }
static sl_node_base_t* primary_expression(sl_parse_state_t* ps) { sl_token_t* tok; sl_node_base_t* node; switch(peek_token(ps)->type) { case SL_TOK_INTEGER: tok = next_token(ps); return sl_make_immediate_node(ps, sl_integer_parse(ps->vm, tok->as.str.buff, tok->as.str.len)); case SL_TOK_FLOAT: return sl_make_immediate_node(ps, sl_make_float(ps->vm, next_token(ps)->as.dbl)); case SL_TOK_STRING: tok = next_token(ps); return sl_make_immediate_node(ps, sl_make_string(ps->vm, tok->as.str.buff, tok->as.str.len)); case SL_TOK_REGEXP: return regexp_expression(ps); case SL_TOK_CONSTANT: tok = next_token(ps); return sl_make_const_node(ps, NULL, sl_intern2(ps->vm, sl_make_string(ps->vm, tok->as.str.buff, tok->as.str.len))); case SL_TOK_IDENTIFIER: tok = next_token(ps); return sl_make_var_node(ps, SL_NODE_VAR, sl_make_string(ps->vm, tok->as.str.buff, tok->as.str.len)); case SL_TOK_TRUE: next_token(ps); return sl_make_immediate_node(ps, ps->vm->lib._true); case SL_TOK_FALSE: next_token(ps); return sl_make_immediate_node(ps, ps->vm->lib._false); case SL_TOK_NIL: next_token(ps); return sl_make_immediate_node(ps, ps->vm->lib.nil); case SL_TOK_SELF: next_token(ps); return sl_make_self_node(ps); case SL_TOK_IVAR: tok = next_token(ps); node = sl_make_var_node(ps, SL_NODE_IVAR, sl_make_string(ps->vm, tok->as.str.buff, tok->as.str.len)); return node; case SL_TOK_CVAR: tok = next_token(ps); node = sl_make_var_node(ps, SL_NODE_CVAR, sl_make_string(ps->vm, tok->as.str.buff, tok->as.str.len)); return node; case SL_TOK_IF: case SL_TOK_UNLESS: return if_expression(ps); case SL_TOK_WHILE: case SL_TOK_UNTIL: return while_expression(ps); case SL_TOK_FOR: return for_expression(ps); case SL_TOK_CLASS: return class_expression(ps); case SL_TOK_DEF: return def_expression(ps); case SL_TOK_LAMBDA: return lambda_expression(ps); case SL_TOK_TRY: return try_expression(ps); case SL_TOK_OPEN_BRACKET: return array_expression(ps); case SL_TOK_OPEN_PAREN: return bracketed_expression(ps); case SL_TOK_OPEN_BRACE: return dict_expression(ps); case SL_TOK_NEXT: tok = next_token(ps); if(!(ps->scope->flags & SL_PF_CAN_NEXT_LAST)) { error(ps, sl_make_cstring(ps->vm, "next invalid outside loop"), tok); } return sl_make_singleton_node(ps, SL_NODE_NEXT); case SL_TOK_LAST: tok = next_token(ps); if(!(ps->scope->flags & SL_PF_CAN_NEXT_LAST)) { error(ps, sl_make_cstring(ps->vm, "last invalid outside loop"), tok); } return sl_make_singleton_node(ps, SL_NODE_LAST); case SL_TOK_RANGE_EX: next_token(ps); return sl_make_singleton_node(ps, SL_NODE_YADA_YADA); default: unexpected(ps, peek_token(ps)); return NULL; } }
static sl_node_base_t* def_expression(sl_parse_state_t* ps) { SLID name; sl_node_base_t* on = NULL; sl_node_base_t* body; sl_token_t* tok; size_t req_arg_count = 0, req_arg_cap = 2; sl_string_t** req_args = sl_alloc(ps->vm->arena, sizeof(sl_string_t*) * req_arg_cap); size_t opt_arg_count = 0, opt_arg_cap = 2; sl_node_opt_arg_t* opt_args = sl_alloc(ps->vm->arena, sizeof(sl_node_opt_arg_t) * opt_arg_cap); sl_parse_scope_t scope; expect_token(ps, SL_TOK_DEF); switch(peek_token(ps)->type) { case SL_TOK_IDENTIFIER: if(peek_token_n(ps, 2)->type == SL_TOK_DOT) { on = sl_make_var_node(ps, SL_NODE_VAR, next_token(ps)->str); next_token(ps); name = def_expression_method_name(ps); } else { on = NULL; name = def_expression_method_name(ps); } break; case SL_TOK_SELF: case SL_TOK_IVAR: case SL_TOK_CVAR: case SL_TOK_CONSTANT: on = primary_expression(ps); expect_token(ps, SL_TOK_DOT); name = def_expression_method_name(ps); break; default: name = def_expression_method_name(ps); } if(peek_token(ps)->type == SL_TOK_EQUALS) { next_token(ps); name = sl_intern2(ps->vm, sl_string_concat(ps->vm, sl_id_to_string(ps->vm, name), sl_make_cstring(ps->vm, "="))); } int at_opt_args = 0; if(peek_token(ps)->type != SL_TOK_OPEN_BRACE) { expect_token(ps, SL_TOK_OPEN_PAREN); if(peek_token(ps)->type == SL_TOK_SELF) { error(ps, sl_make_cstring(ps->vm, "not a chance"), peek_token(ps)); } while(peek_token(ps)->type != SL_TOK_CLOSE_PAREN) { tok = expect_token(ps, SL_TOK_IDENTIFIER); if(peek_token(ps)->type == SL_TOK_EQUALS) { at_opt_args = 1; } if(at_opt_args) { expect_token(ps, SL_TOK_EQUALS); if(opt_arg_count >= opt_arg_cap) { opt_arg_cap *= 2; opt_args = sl_realloc(ps->vm->arena, opt_args, sizeof(sl_node_opt_arg_t) * opt_arg_cap); } opt_args[opt_arg_count].name = (sl_string_t*)sl_get_ptr( sl_make_string(ps->vm, tok->as.str.buff, tok->as.str.len)); opt_args[opt_arg_count++].default_value = expression(ps); } else { if(req_arg_count >= req_arg_cap) { req_arg_cap *= 2; req_args = sl_realloc(ps->vm->arena, req_args, sizeof(sl_string_t*) * req_arg_cap); } req_args[req_arg_count++] = (sl_string_t*)sl_get_ptr( sl_make_string(ps->vm, tok->as.str.buff, tok->as.str.len)); } if(peek_token(ps)->type != SL_TOK_CLOSE_PAREN) { expect_token(ps, SL_TOK_COMMA); } } expect_token(ps, SL_TOK_CLOSE_PAREN); } scope.prev = ps->scope; scope.flags = SL_PF_CAN_RETURN; ps->scope = &scope; body = body_expression(ps); ps->scope = scope.prev; ps->scope->flags |= SL_PF_SCOPE_CLOSURE; return sl_make_def_node(ps, name, on, req_arg_count, req_args, opt_arg_count, opt_args, body); }