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); } }
static SLVAL sl_gcrypt_algorithm_inspect(sl_vm_t* vm, SLVAL self) { gcrypt_algorithm_t* algo = get_algo(vm, self); SLVAL str = sl_make_cstring(vm, "#<GCrypt::Algorithm: "); str = sl_string_concat(vm, str, algo->name); str = sl_string_concat(vm, str, sl_make_cstring(vm, ">")); return str; }
static void unexpected(sl_parse_state_t* ps, sl_token_t* tok) { SLVAL err; if(tok->type != SL_TOK_END) { err = sl_make_cstring(ps->vm, "Unexpected '"); err = sl_string_concat(ps->vm, err, tok->str); err = sl_string_concat(ps->vm, err, sl_make_cstring(ps->vm, "'")); } else { err = sl_make_cstring(ps->vm, "Unexpected end of file"); } error(ps, err, tok); }
static SLVAL response_set_cookie(sl_vm_t* vm, SLVAL self, SLVAL name, SLVAL value) { SLVAL header; sl_expect(vm, name, vm->lib.String); sl_expect(vm, value, vm->lib.String); name = sl_string_url_encode(vm, name); value = sl_string_url_encode(vm, value); header = name; header = sl_string_concat(vm, header, sl_make_cstring(vm, "=")); header = sl_string_concat(vm, header, value); return response_set_header(vm, self, sl_make_cstring(vm, "Set-Cookie"), header); }
static SLVAL sl_class_to_s(sl_vm_t* vm, SLVAL self) { sl_class_t* klass = get_class(vm, self); sl_class_t* object = (sl_class_t*)sl_get_ptr(vm->lib.Object); if(klass == object || sl_get_ptr(klass->in) == (sl_object_t*)object) { return get_class(vm, self)->name; } else { return sl_string_concat(vm, sl_class_to_s(vm, klass->in), sl_string_concat(vm, sl_make_cstring(vm, "::"), klass->name)); } }
SLVAL sl_do_file(sl_vm_t* vm, char* filename) { filename = sl_realpath(vm, filename); FILE* f = fopen(filename, "rb"); uint8_t* src; size_t file_size; SLVAL err; if(!f) { err = sl_make_cstring(vm, "Could not load file: "); err = sl_string_concat(vm, err, sl_make_cstring(vm, filename)); err = sl_string_concat(vm, err, sl_make_cstring(vm, " - ")); err = sl_string_concat(vm, err, sl_make_cstring(vm, strerror(errno))); sl_throw(vm, sl_make_error2(vm, vm->lib.Error, err)); } fseek(f, 0, SEEK_END); file_size = ftell(f); fseek(f, 0, SEEK_SET); src = sl_alloc(vm->arena, file_size); if(file_size && !fread(src, file_size, 1, f)) { fclose(f); err = sl_make_cstring(vm, "Could not load file: "); err = sl_string_concat(vm, err, sl_make_cstring(vm, filename)); err = sl_string_concat(vm, err, sl_make_cstring(vm, " - ")); err = sl_string_concat(vm, err, sl_make_cstring(vm, strerror(errno))); sl_throw(vm, sl_make_error2(vm, vm->lib.Error, err)); } fclose(f); return sl_do_string(vm, src, file_size, filename, 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); }
SLVAL sl_enumerable_join(sl_vm_t* vm, SLVAL self, size_t argc, SLVAL* argv) { SLVAL enumerator = sl_send(vm, self, "enumerate", 0); SLVAL joiner, val, str; if(argc) { joiner = sl_to_s(vm, argv[0]); } else { joiner = sl_make_cstring(vm, ""); } if(!sl_is_truthy(sl_send(vm, enumerator, "next", 0))) { return sl_make_cstring(vm, ""); } str = sl_to_s(vm, sl_send(vm, enumerator, "current", 0)); while(sl_is_truthy(sl_send(vm, enumerator, "next", 0))) { val = sl_send(vm, enumerator, "current", 0); val = sl_to_s(vm, val); str = sl_string_concat(vm, str, joiner); str = sl_string_concat(vm, str, val); } return str; }
static SLID def_expression_method_name(sl_parse_state_t* ps) { switch(peek_token(ps)->type) { case SL_TOK_IDENTIFIER: return sl_intern2(ps->vm, next_token(ps)->str); /* operators: */ case SL_TOK_SHIFT_LEFT: case SL_TOK_SHIFT_RIGHT: case SL_TOK_DBL_EQUALS: case SL_TOK_NOT_EQUALS: case SL_TOK_SPACESHIP: case SL_TOK_LTE: case SL_TOK_LT: case SL_TOK_GTE: case SL_TOK_GT: case SL_TOK_PLUS: case SL_TOK_POW: case SL_TOK_TIMES: case SL_TOK_DIVIDE: case SL_TOK_MOD: case SL_TOK_CARET: case SL_TOK_AMP: case SL_TOK_PIPE: return sl_intern2(ps->vm, next_token(ps)->str); /* operators that can also be unary: */ case SL_TOK_MINUS: case SL_TOK_TILDE: { sl_token_t* tok = next_token(ps); if(peek_token(ps)->type == SL_TOK_SELF) { return sl_intern2(ps->vm, sl_string_concat(ps->vm, tok->str, next_token(ps)->str)); } else { return sl_intern2(ps->vm, tok->str); } break; } /* keywords: */ case SL_TOK_LAST: case SL_TOK_NEXT: return sl_intern2(ps->vm, next_token(ps)->str); case SL_TOK_OPEN_BRACKET: next_token(ps); expect_token(ps, SL_TOK_CLOSE_BRACKET); return sl_intern(ps->vm, "[]"); default: unexpected(ps, next_token(ps)); SLID dummy; return dummy; /* never reached */ } }
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 void emit_assignment(sl_compile_state_t* cs, sl_node_base_t* lval, size_t reg) { sl_node_assign_var_t a_var; sl_node_send_t send; size_t dest_reg = reg_alloc(cs); sl_node__register_t node; sl_node__register_t* node_p = &node; node.base.type = SL_NODE__REGISTER; node.base.line = 0; node.reg = reg; switch(lval->type) { case SL_NODE_VAR: a_var.base.type = SL_NODE_ASSIGN_VAR; break; case SL_NODE_IVAR: a_var.base.type = SL_NODE_ASSIGN_IVAR; break; case SL_NODE_CVAR: a_var.base.type = SL_NODE_ASSIGN_CVAR; break; case SL_NODE_CONST: a_var.base.type = SL_NODE_ASSIGN_CONST; break; case SL_NODE_ARRAY: a_var.base.type = SL_NODE_ASSIGN_ARRAY; break; case SL_NODE_SEND: /* special case that turns a.b = 1 into a.send("b=", 1) */ /* this is separate to the other method of handling send assignments which also handles compound assignments. */ memcpy(&send, lval, sizeof(sl_node_send_t)); send.id = sl_string_concat(cs->vm, send.id, sl_make_cstring(cs->vm, "=")); send.arg_count = 1; send.args = (sl_node_base_t**)&node_p; compile_node(cs, (sl_node_base_t*)&send, dest_reg); reg_free(cs, dest_reg); return; default: { SLVAL err = sl_make_cstring(cs->vm, "Invalid lval in assignment"); err = sl_make_error2(cs->vm, cs->vm->lib.SyntaxError, 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, lval->line)); sl_throw(cs->vm, err); } } a_var.base.line = 0; a_var.lval = (void*)lval; a_var.rval = (sl_node_base_t*)&node; compile_node(cs, (sl_node_base_t*)&a_var, dest_reg); reg_free(cs, dest_reg); }
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); }
void sl_render_error_page(sl_vm_t* vm, SLVAL err) { sl_vm_frame_t frame; sl_response_internal_opts_t* resp = response(vm); resp->status = 500; SLVAL caught_error; if(resp->descriptive_error_pages) { SL_TRY(frame, SL_UNWIND_EXCEPTION, { SLVAL error_lambda = sl_do_string(vm, (uint8_t*)sl__src_lib_error_page_sl, strlen(sl__src_lib_error_page_sl), "(error-page)", 0); sl_lambda_call(vm, error_lambda, 1, &err); }, caught_error, { sl_response_write(vm, sl_string_concat(vm, sl_make_cstring(vm, "<h1>Internal Server Error</h1><pre>"), sl_string_concat(vm, sl_string_html_escape(vm, sl_to_s_no_throw(vm, caught_error)), sl_make_cstring(vm, "</pre>")))); }); } else { sl_response_write(vm, sl_make_cstring(vm, "<h1>Internal Server Error</h1>")); } } void sl_init_response(sl_vm_t* vm) { SLVAL Response = sl_new(vm, vm->lib.Object, 0, NULL); sl_vm_store_put(vm, &Response_, Response); sl_define_singleton_method(vm, Response, "write", -2, sl_response_write);
static SLVAL bignum_ordinalize(sl_vm_t* vm, SLVAL self) { long rem = sl_bignum_get_long(vm, sl_bignum_mod(vm, self, sl_make_int(vm, 10))); return sl_string_concat(vm, sl_to_s(vm, self), ordinalize(vm, rem % 10)); }
static SLVAL int_ordinalize(sl_vm_t* vm, SLVAL self) { int i = sl_get_int(self); return sl_string_concat(vm, sl_to_s(vm, self), ordinalize(vm, i % 10)); }