Example #1
0
static int
run_slash_script(request_rec* r, void* stack_top)
{
    sl_vm_t* vm;
    slash_context_t ctx;
    sl_vm_frame_t exit_frame, exception_frame;
    char* last_slash;
    SLVAL error;
    sl_static_init();
    vm = sl_init("apache2");
    sl_gc_set_stack_top(vm->arena, stack_top);
    vm->cwd = sl_alloc_buffer(vm->arena, strlen(r->canonical_filename) + 10);
    strcpy(vm->cwd, r->canonical_filename);
    last_slash = strrchr(vm->cwd, '/');
    if(last_slash) {
        *last_slash = 0;
    }
    SL_TRY(exit_frame, SL_UNWIND_ALL, {
        SL_TRY(exception_frame, SL_UNWIND_EXCEPTION, {
            ctx.headers_sent = 0;
            ctx.vm = vm;
            ctx.r = r;
            vm->data = &ctx;
            setup_request_object(vm, r);
            setup_response_object(vm);
            ap_set_content_type(r, "text/html; charset=utf-8");
            sl_do_file(vm, r->canonical_filename);
        }, error, {
            sl_response_clear(vm);
            sl_render_error_page(vm, error);
        });
Example #2
0
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);
}
Example #3
0
File: string.c Project: richo/slash
char*
sl_iconv(sl_vm_t* vm, char* input_string, size_t input_length, char* from_encoding, char* to_encoding, size_t* output_length)
{
    iconv_t cd = iconv_open(to_encoding, from_encoding);
    if(cd == (iconv_t)(-1)) {
        sl_throw_message2(vm, vm->lib.EncodingError, "Unknown encoding");
    }
    char* in_buff = input_string;
    size_t in_bytes_left = input_length;
    size_t out_bytes_left = in_bytes_left * 4 + 15;
    size_t out_cap = out_bytes_left;
    char* out_buff = sl_alloc_buffer(vm->arena, out_cap);
    char* retn_out_buff = out_buff;
    while(1) {
        size_t ret = iconv(cd, &in_buff, &in_bytes_left, &out_buff, &out_bytes_left);
        if(ret != (size_t)(-1)) {
            break;
        }
        if(errno == E2BIG) {
            out_bytes_left = input_length;
            out_cap += input_length;
            out_buff = sl_realloc(vm->arena, out_buff, out_cap);
            continue;
        }
        if(errno == EILSEQ || errno == EINVAL) {
            iconv_close(cd);
            sl_throw_message2(vm, vm->lib.EncodingError, "Invalid encoding in source buffer");
        }
        break;
    }
    iconv_close(cd);
    *output_length = out_cap - out_bytes_left;
    return retn_out_buff;
}
Example #4
0
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, "&lt;", 4);
            out_len += 4;
        } else if(str->buff[str_i] == '>') {
            memcpy(out + out_len, "&gt;", 4);
            out_len += 4;
        } else if(str->buff[str_i] == '"') {
            memcpy(out + out_len, "&quot;", 6);
            out_len += 6;
        } else if(str->buff[str_i] == '\'') {
            memcpy(out + out_len, "&#039;", 6);
            out_len += 6;
        } else if(str->buff[str_i] == '&') {
            memcpy(out + out_len, "&amp;", 5);
            out_len += 5;
        } else {
            out[out_len++] = str->buff[str_i];
        }
    }
    return sl_make_string(vm, out, out_len);
}
Example #5
0
static void
init_compile_state(sl_compile_state_t* cs, sl_vm_t* vm, sl_compile_state_t* parent, size_t init_registers)
{
    size_t i;
    cs->vm = vm;
    cs->vars = sl_st_init_table(vm, &sl_string_hash_type);
    cs->parent = parent;
    cs->section = sl_alloc(vm->arena, sizeof(sl_vm_section_t));
    if(parent) {
        cs->section->filename = parent->section->filename;
    }
    cs->section->max_registers = init_registers;
    cs->section->req_registers = 0;
    cs->section->arg_registers = 0;
    cs->section->insns_cap = 16;
    cs->section->insns_count = 0;
    cs->section->insns = sl_alloc(vm->arena, sizeof(sl_vm_insn_t) * cs->section->insns_cap);
    cs->section->line_mappings_cap = 2;
    cs->section->line_mappings_count = 0;
    cs->section->line_mappings = sl_alloc_buffer(vm->arena, sizeof(sl_vm_line_mapping_t) * cs->section->line_mappings_cap);
    cs->section->can_stack_alloc_frame = true;
    cs->section->has_try_catch = false;
    cs->section->opt_skip = NULL;
    cs->registers = sl_alloc(vm->arena, cs->section->max_registers);
    for(i = 0; i < init_registers; i++) {
        cs->registers[i] = 1;
    }
    cs->next_last_frames = NULL;
}
Example #6
0
File: string.c Project: richo/slash
SLVAL
sl_make_string(struct sl_vm* vm, uint8_t* buff, size_t buff_len)
{
    uint8_t* our_buff = sl_alloc_buffer(vm->arena, buff_len + 1);
    memcpy(our_buff, buff, buff_len);
    return sl_make_string_no_copy(vm, our_buff, buff_len);
}
Example #7
0
File: string.c Project: richo/slash
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);
}
Example #8
0
sl_token_t
sl_make_string_token(sl_lex_state_t* ls, sl_token_type_t type, char* buff, size_t len)
{
    sl_token_t token;
    size_t cap = len < 4 ? 4 : len;
    token.type = type;
    token.as.str.buff = sl_alloc_buffer(ls->vm->arena, cap);
    token.as.str.len = len;
    token.as.str.cap = cap;
    memcpy(token.as.str.buff, buff, len);
    return token;
}
Example #9
0
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);
}
Example #10
0
File: posix.c Project: Hmaal/slash
char*
sl_realpath(sl_vm_t* vm, char* path)
{
    char *cpath, *gcbuff;
    if(path[0] != '/') {
        gcbuff = sl_alloc_buffer(vm->arena, strlen(vm->cwd) + strlen(path) + 10);
        strcpy(gcbuff, vm->cwd);
        strcat(gcbuff, "/");
        strcat(gcbuff, path);
        path = gcbuff;
    }
    #ifdef PATH_MAX
        cpath = sl_alloc_buffer(vm->arena, PATH_MAX + 1);
        (void)realpath(path, cpath);
        return cpath;
    #else
        cpath = realpath(path, NULL);
        gcbuff = sl_alloc_buffer(vm->arena, strlen(cpath) + 1);
        strcpy(gcbuff, cpath);
        return gcbuff;
    #endif
}
Example #11
0
File: json.c Project: Hmaal/slash
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;
}
Example #12
0
char*
sl_realpath(sl_vm_t* vm, char* path)
{
    char *cpath, *gcbuff;
    if(!path[0] || path[1] != ':') {
        gcbuff = sl_alloc_buffer(vm->arena, strlen(vm->cwd) + strlen(path) + 10);
        strcpy(gcbuff, vm->cwd);
        strcat(gcbuff, "/");
        strcat(gcbuff, path);
        path = gcbuff;
    }

    #ifdef _MAX_PATH
        cpath = sl_alloc_buffer(vm->arena, _MAX_PATH + 1);
        cpath = _fullpath(cpath, path, _MAX_PATH);
        return cpath;
    #else
        cpath = _fullpath(NULL, path, 0);
        gcbuff = sl_alloc_buffer(vm->arena, strlen(cpath) + 1);
        strcpy(gcbuff, cpath);
        free(cpath);
        return gcbuff;
    #endif
}
Example #13
0
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);
}
Example #14
0
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);
}
Example #15
0
File: vm_exec.c Project: filp/slash
static SLVAL
vm_helper_build_string(sl_vm_t* vm, SLVAL* vals, size_t count)
{
    for(size_t i = 0; i < count; i++) {
        vals[i] = sl_to_s(vm, vals[i]);
    }
    size_t len = 0;
    for(size_t i = 0; i < count; i++) {
        len += ((sl_string_t*)sl_get_ptr(vals[i]))->buff_len;
    }
    uint8_t* buff = sl_alloc_buffer(vm->arena, len + 1);
    size_t j = 0;
    for(size_t i = 0; i < count; i++) {
        sl_string_t* str = (void*)sl_get_ptr(vals[i]);
        memcpy(buff + j, str->buff, str->buff_len);
        j += str->buff_len;
    }
    return sl_make_string_no_copy(vm, buff, len);
}
Example #16
0
SLVAL
sl_make_string(sl_vm_t* vm, uint8_t* buff, size_t buff_len)
{
    SLVAL vstr = sl_allocate(vm, vm->lib.String);
    sl_string_t* str = (sl_string_t*)sl_get_ptr(vstr);
    if(sl_is_valid_utf8(buff, buff_len)) {
        str->encoding = "UTF-8";
        str->char_len = sl_utf8_strlen(vm, buff, buff_len);
    } else {
        str->encoding = "CP1252";
        str->char_len = buff_len;
    }
    str->buff = sl_alloc_buffer(vm->arena, buff_len + 1);
    memcpy(str->buff, buff, buff_len);
    str->buff[buff_len] = 0;
    str->buff_len = buff_len;
    str->hash_set = 0;
    return vstr;
}
Example #17
0
int main(int argc, char** argv)
{
    sl_static_init();
    sl_vm_t* vm = sl_init("disasm");

    if(argc < 1) {
        fprintf(stderr, "Usage: slash-dis <source file>\n");
        exit(1);
    }

    FILE* f = fopen(argv[1], "r");
    if(!f) {
        fprintf(stderr, "Could not open %s for reading.\n", argv[1]);
        exit(1);
    }

    fseek(f, 0, SEEK_END);
    size_t size = ftell(f);
    fseek(f, 0, SEEK_SET);

    char* source = sl_alloc_buffer(vm->arena, size + 1);
    fread(source, size, 1, f);
    fclose(f);

    SLVAL err;
    sl_vm_frame_t frame;
    SL_TRY(frame, SL_UNWIND_ALL, {

        size_t token_count;
        sl_token_t* tokens = sl_lex(vm, (uint8_t*)argv[1], (uint8_t*)source, size, &token_count, 0);

        sl_node_base_t* ast = sl_parse(vm, tokens, token_count, (uint8_t*)argv[1]);

        sl_vm_section_t* section = sl_compile(vm, ast, (uint8_t*)argv[1]);

        disassemble(vm, section);
        while(section_j < section_i) {
            disassemble(vm, section_queue[++section_j]);
        }

    }, err, {
Example #18
0
SLVAL
sl_response_flush(sl_vm_t* vm)
{
    sl_response_internal_opts_t* resp = response(vm);
    size_t i, total_size = 0, offset = 0;
    char* output_buffer;
    sl_string_t* str;
    for(i = 0; i < resp->output_len; i++) {
        str = (sl_string_t*)sl_get_ptr(resp->output[i]);
        total_size += str->buff_len;
    }
    output_buffer = sl_alloc_buffer(vm->arena, total_size + 1);
    for(i = 0; i < resp->output_len; i++) {
        str = (sl_string_t*)sl_get_ptr(resp->output[i]);
        memcpy(output_buffer + offset, str->buff, str->buff_len);
        offset += str->buff_len;
    }
    resp->write(vm, output_buffer, total_size);
    resp->output_len = 0;
    return vm->lib.nil;
}
Example #19
0
File: string.c Project: richo/slash
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);
}
Example #20
0
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;
}
Example #21
0
File: mysql.c Project: Hmaal/slash
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;
}