static int on_start_array(void* ctx) { json_parse_t* json = ctx; SLVAL a = sl_make_array(json->vm, 0, NULL); JSON_PUSH_CONTAINER(a, JSON_TYPE_ARRAY); return 1; }
static SLVAL enumerable_to_a(sl_vm_t* vm, SLVAL self) { SLVAL array = sl_make_array(vm, 0, NULL); SLVAL enumerator = sl_send(vm, self, "enumerate", 0); SLVAL val; while(sl_is_truthy(sl_send(vm, enumerator, "next", 0))) { val = sl_send(vm, enumerator, "current", 0); sl_array_push(vm, array, 1, &val); } return array; }
static SLVAL call_sl_func(sl_vm_t* vm, SLVAL recv, sl_method_t* method, int argc, SLVAL* argv) { sl_vm_exec_ctx_t stack_ctx; sl_vm_exec_ctx_t* ctx; if(sl_likely(method->as.sl.section->can_stack_alloc_frame)) { ctx = &stack_ctx; memset(ctx, 0, sizeof(*ctx)); } else { ctx = sl_alloc(vm->arena, sizeof(sl_vm_exec_ctx_t)); } ctx->vm = vm; ctx->section = method->as.sl.section; if(method->as.sl.section->can_stack_alloc_frame) { ctx->registers = alloca(sizeof(SLVAL) * ctx->section->max_registers); } else { ctx->registers = sl_alloc(vm->arena, sizeof(SLVAL) * ctx->section->max_registers); } ctx->self = recv; ctx->parent = method->as.sl.parent_ctx; memcpy(ctx->registers + 1, argv, sizeof(SLVAL) * ctx->section->arg_registers); if(ctx->section->has_extra_rest_arg) { if(argc > ctx->section->arg_registers) { size_t extra_len = argc - ctx->section->arg_registers; ctx->registers[ctx->section->arg_registers + 1] = sl_make_array(vm, extra_len, argv + ctx->section->arg_registers); } else { ctx->registers[ctx->section->arg_registers + 1] = sl_make_array(vm, 0, NULL); } } if(argc > ctx->section->arg_registers) { argc = ctx->section->arg_registers; } if(ctx->section->opt_skip) { return sl_vm_exec(ctx, ctx->section->opt_skip[argc - ctx->section->req_registers]); } else { return sl_vm_exec(ctx, 0); } }
static void process_arguments(sl_vm_t* vm, int argc, char** argv) { int i = 1; for(; i < argc; i++) { if(strcmp(argv[i], "-I") == 0) { if(i + 1 == argc) { fprintf(stderr, "Expected <path> after -I\n"); shutdown_vm(vm, 1); } sl_require_path_prepend(vm, argv[++i]); continue; } if(strcmp(argv[i], "-i") == 0) { opt_interactive = true; continue; } if(strcmp(argv[i], "-h") == 0) { print_help(argv[0]); shutdown_vm(vm, 0); } if(strcmp(argv[i], "--") == 0) { i++; break; } if(argv[i][0] == '-') { fprintf(stderr, "Unknown option '%s'\n", argv[i]); shutdown_vm(vm, 1); } break; } if(!opt_interactive) { if(i == argc || strcmp(argv[i], "-") == 0) { opt_source_file = stdin; opt_source_file_name = "(stdin)"; } else { opt_source_file = fopen(argv[i], "rb"); opt_source_file_name = argv[i]; if(!opt_source_file) { perror("Could not open source file"); shutdown_vm(vm, 1); } } i++; } SLVAL vargv = sl_make_array(vm, 0, NULL); for(; i < argc; i++) { SLVAL varg = sl_make_cstring(vm, argv[i]); sl_array_push(vm, vargv, 1, &varg); } sl_class_set_const(vm, vm->lib.Object, "ARGV", vargv); }
SLVAL sl_regexp_match_capture(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; } int start = sl_string_index_for_byte_offset(vm, match->match_string, match->captures[index]); int end = sl_string_index_for_byte_offset(vm, match->match_string, match->captures[index + 1]); SLVAL off_len[] = { sl_make_int(vm, start), sl_make_int(vm, end - start) }; return sl_make_array(vm, 2, off_len); }
static SLVAL enumerable_reject(sl_vm_t* vm, SLVAL self, SLVAL f) { SLVAL val, truthy, ary = sl_make_array(vm, 0, NULL); SLVAL enumerator = sl_send(vm, self, "enumerate", 0); while(sl_is_truthy(sl_send(vm, enumerator, "next", 0))) { val = sl_send(vm, enumerator, "current", 0); truthy = sl_send(vm, f, "call", 1, val); if(!sl_is_truthy(truthy)) { sl_array_push(vm, ary, 1, &val); } } return ary; }
static void load_cgi_options(sl_vm_t* vm, cgi_options* options) { int i = 0; for(; options->incpaths && i < options->incpaths_count; i++) { sl_require_path_prepend(vm, options->incpaths[i]); } SLVAL vargv = sl_make_array(vm, 0, NULL); for(i = 0; i < options->arg_script_options_count; i++) { SLVAL varg = sl_make_cstring(vm, options->arg_script_options[i]); sl_array_push(vm, vargv, 1, &varg); } sl_class_set_const(vm, vm->lib.Object, "ARGV", vargv); }
static SLVAL enumerable_take(sl_vm_t* vm, SLVAL self, SLVAL countv) { SLVAL ary = sl_make_array(vm, 0, NULL); SLVAL enumerator = sl_send(vm, self, "enumerate", 0); for(int count = sl_get_int(countv); count > 0; count--) { if(!sl_is_truthy(sl_send(vm, enumerator, "next", 0))) { return ary; } SLVAL elem = sl_send(vm, enumerator, "current", 0); sl_array_push(vm, ary, 1, &elem); } return ary; }
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 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 int own_instance_methods_iter(sl_vm_t* vm, SLID name, SLVAL method, SLVAL ary) { SLVAL namev = sl_id_to_string(vm, name); sl_array_push(vm, ary, 1, &namev); return SL_ST_CONTINUE; (void)method; } SLVAL sl_class_own_instance_methods(sl_vm_t* vm, SLVAL klass) { sl_class_t* class = get_class(vm, klass); SLVAL ary = sl_make_array(vm, 0, NULL); sl_st_foreach(class->instance_methods, own_instance_methods_iter, (sl_st_data_t)ary.i); return ary; } SLVAL sl_class_instance_methods(sl_vm_t* vm, SLVAL klass) { sl_class_t* class = get_class(vm, klass); SLVAL ary = sl_class_own_instance_methods(vm, klass); while(sl_get_primitive_type(class->super) == SL_T_CLASS) { ary = sl_array_concat(vm, ary, sl_class_own_instance_methods(vm, class->super)); class = (sl_class_t*)sl_get_ptr(class->super); } return ary; }
// somewhat similar to sprintf // // Valid formats: // // %V - Slash value, converted to string first with #to_s // %I - Slash ID // %s - C string // %d - integer // %% - literal '%' sign // // You may add the 'Q' modifier to a format specifier to quote it in double // quotes. For example "%QV" would quote the value when interpolating it into // the string SLVAL sl_make_formatted_string_va(struct sl_vm* vm, const char* format, va_list va) { SLVAL strings = sl_make_array(vm, 0, NULL); const char *current_ptr = format, *next_ptr; SLVAL quote = vm->lib.nil; while((next_ptr = strchr(current_ptr, '%'))) { if(next_ptr != current_ptr) { SLVAL literal = sl_make_string(vm, (uint8_t*)current_ptr, (size_t)(next_ptr - current_ptr)); sl_array_push(vm, strings, 1, &literal); } SLVAL element = vm->lib.nil; bool quoted = false; again: switch(next_ptr[1]) { case 'Q': { if(sl_get_primitive_type(quote) == SL_T_NIL) { quote = sl_make_cstring(vm, "\""); } sl_array_push(vm, strings, 1, "e); next_ptr++; quoted = true; goto again; } case 'V': { element = va_arg(va, SLVAL); break; } case 'X': { element = va_arg(va, SLVAL); element = sl_inspect(vm, element); break; } case 'I': { SLID id = va_arg(va, SLID); element = sl_id_to_string(vm, id); break; } case 's': { char* cstr = va_arg(va, char*); element = sl_make_cstring(vm, cstr); break; } case 'd': { char buff[32]; int num = va_arg(va, int); sprintf(buff, "%d", num); element = sl_make_cstring(vm, buff); break; } case 'p': { char buff[32]; void* ptr = va_arg(va, void*); sprintf(buff, "%p", ptr); element = sl_make_cstring(vm, buff); break; } case 0: { return vm->lib.nil; } default: { element = sl_make_string(vm, (uint8_t*)(next_ptr + 1), 1); break; } } sl_array_push(vm, strings, 1, &element); if(quoted) { sl_array_push(vm, strings, 1, "e); quoted = false; } current_ptr = next_ptr + 2; } if(current_ptr[0]) { SLVAL element = sl_make_cstring(vm, current_ptr); sl_array_push(vm, strings, 1, &element); } return sl_array_join(vm, strings, 0, NULL); }
SLVAL sl_string_split(sl_vm_t* vm, SLVAL self, size_t argc, SLVAL* argv) { SLVAL substr = argv[0]; sl_string_t* haystack = sl_get_string(vm, self); sl_string_t* needle = sl_get_string(vm, substr); SLVAL ret = sl_make_array(vm, 0, NULL), piece; uint8_t* haystack_buff = haystack->buff; uint8_t* start_ptr = haystack_buff; size_t haystack_len = haystack->buff_len; uint8_t buff[12]; size_t buff_len; uint32_t c; long limit = 0; if(argc > 1) { limit = sl_get_int(sl_expect(vm, argv[1], vm->lib.Int)); if(limit < 0) { limit = 0; } } long length = 0; if(needle->buff_len == 0) { while(haystack_len) { length++; if(limit && length == limit) { SLVAL rest = sl_make_string(vm, haystack_buff, haystack_len); sl_array_push(vm, ret, 1, &rest); break; } c = sl_utf8_each_char(vm, &haystack_buff, &haystack_len); buff_len = sl_utf32_char_to_utf8(vm, c, buff); piece = sl_make_string(vm, buff, buff_len); sl_array_push(vm, ret, 1, &piece); } return ret; } else { if(limit == 1) { return sl_make_array(vm, 1, &self); } while(haystack_len >= needle->buff_len) { if(memcmp(haystack_buff, needle->buff, needle->buff_len) == 0) { piece = sl_make_string(vm, start_ptr, haystack_buff - start_ptr); sl_array_push(vm, ret, 1, &piece); haystack_buff += needle->buff_len; haystack_len -= needle->buff_len; length++; if(limit && length + 1 == limit) { SLVAL rest = sl_make_string(vm, haystack_buff, haystack_len); sl_array_push(vm, ret, 1, &rest); return ret; } start_ptr = haystack_buff; continue; } haystack_buff++; haystack_len--; } piece = sl_make_string(vm, start_ptr, haystack_buff - start_ptr + haystack_len); sl_array_push(vm, ret, 1, &piece); return ret; } return vm->lib.nil; }