Exemple #1
0
static SLID
sl_intern2_no_check(sl_vm_t* vm, SLVAL str)
{
    SLID id;

    if(sl_st_lookup(vm->intern.name_to_id, (sl_st_data_t)sl_get_ptr(str), (sl_st_data_t*)&id)) {
        return id;
    }

    id.id = vm->intern.id_to_name_size++;
    sl_st_insert(vm->intern.name_to_id, (sl_st_data_t)sl_get_ptr(str), (sl_st_data_t)id.id);
    if(vm->intern.id_to_name_size >= vm->intern.id_to_name_cap) {
        vm->intern.id_to_name_cap *= 2;
        vm->intern.id_to_name = sl_realloc(vm->arena, vm->intern.id_to_name, sizeof(SLVAL) * vm->intern.id_to_name_cap);
    }
    vm->intern.id_to_name[id.id] = str;

    return id;
}
Exemple #2
0
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);
}
Exemple #3
0
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]);
}
Exemple #4
0
static sl_regexp_match_t*
get_regexp_match(sl_vm_t* vm, SLVAL matchv)
{
    sl_regexp_match_t* match;
    sl_expect(vm, matchv, vm->lib.Regexp_Match);
    match = (sl_regexp_match_t*)sl_get_ptr(matchv);
    if(!match->re) {
        sl_throw_message2(vm, vm->lib.TypeError, "Invalid Regexp::Match");
    }
    return match;
}
Exemple #5
0
static SLVAL
method_inspect(sl_vm_t* vm, SLVAL method)
{
    sl_method_t* methp = (sl_method_t*)sl_get_ptr(method);
    if(!(methp->base.user_flags & SL_FLAG_METHOD_INITIALIZED)) {
        return sl_object_inspect(vm, method);
    }

    return sl_make_formatted_string(vm, "#<Method: %V#%I(%d)>",
        methp->extra->klass, methp->extra->name, methp->arity);
}
Exemple #6
0
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);
}
Exemple #7
0
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);
}
Exemple #8
0
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);
}
Exemple #9
0
SLVAL
sl_string_eq(sl_vm_t* vm, SLVAL self, SLVAL other)
{
    if(!sl_is_a(vm, other, vm->lib.String)) {
        return vm->lib._false;
    }
    sl_string_t* a = sl_get_string(vm, self);
    sl_string_t* b = sl_get_string(vm, other);
    if(a->encoding == b->encoding) {
        if(str_cmp((sl_string_t*)sl_get_ptr(self), (sl_string_t*)sl_get_ptr(other)) == 0) {
            return vm->lib._true;
        } else {
            return vm->lib._false;
        }
    }
    sl_vm_frame_t frame;
    SLVAL err;
    volatile SLVAL retn;
    SL_TRY(frame, SL_UNWIND_EXCEPTION, {
        retn = sl_string_eq(vm, self, sl_string_encode(vm, other, a->encoding));
    }, err, {
Exemple #10
0
static SLVAL
sl_class_own_instance_method(sl_vm_t* vm, SLVAL self, SLVAL method_name)
{
    sl_class_t* klass = get_class(vm, self);
    SLVAL method;
    method_name = sl_to_s(vm, method_name);
    if(st_lookup(klass->instance_methods, (st_data_t)sl_get_ptr(method_name), (st_data_t*)&method)) {
        return method;
    } else {
        return vm->lib.nil;
    }
}
Exemple #11
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;
}
Exemple #12
0
SLVAL
sl_make_c_func(sl_vm_t* vm, SLVAL klass, SLID name, int arity, SLVAL(*c_func)())
{
    SLVAL method = sl_allocate(vm, vm->lib.Method);
    sl_method_t* methp = (sl_method_t*)sl_get_ptr(method);
    methp->extra->name = name;
    methp->arity = arity;
    methp->extra->klass = sl_expect(vm, klass, vm->lib.Class);
    methp->as.c.func = c_func;
    methp->base.user_flags |= SL_FLAG_METHOD_INITIALIZED
                            | SL_FLAG_METHOD_IS_C_FUNC;
    return method;
}
Exemple #13
0
SLVAL
sl_make_c_func(sl_vm_t* vm, SLVAL klass, SLID name, int arity, SLVAL(*c_func)())
{
    SLVAL method = sl_allocate(vm, vm->lib.Method);
    sl_method_t* methp = (sl_method_t*)sl_get_ptr(method);
    methp->name = name;
    methp->is_c_func = 1;
    methp->arity = arity;
    methp->klass = sl_expect(vm, klass, vm->lib.Class);
    methp->as.c.func = c_func;
    methp->initialized = 1;
    return method;
}
Exemple #14
0
SLVAL
sl_make_string_no_copy(sl_vm_t* vm, uint8_t* buff, size_t buff_len)
{
    ensure_utf8(vm, buff, buff_len);

    SLVAL vstr = sl_allocate(vm, vm->lib.String);
    sl_string_t* str = (sl_string_t*)sl_get_ptr(vstr);
    str->char_len = sl_utf8_strlen(vm, buff, buff_len);
    str->buff = buff;
    str->buff_len = buff_len;
    str->hash_set = 0;
    return vstr;
}
Exemple #15
0
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;
    method_name = sl_to_s(vm, method_name);
    if(st_lookup(klass->instance_methods, (st_data_t)sl_get_ptr(method_name), (st_data_t*)&method)) {
        return method;
    } else if(sl_get_primitive_type(klass->super) == SL_T_CLASS) {
        return sl_class_instance_method(vm, klass->super, method_name);
    }
    return vm->lib.nil;
}
Exemple #16
0
void
sl_init_nil(sl_vm_t* vm)
{
    sl_object_t* nil = sl_get_ptr(vm->lib.nil);
    vm->lib.Nil = sl_define_class(vm, "Nil", vm->lib.Object);
    sl_class_set_allocator(vm, vm->lib.Nil, allocate_nil);
    nil->klass = vm->lib.Nil;
    nil->primitive_type = SL_T_NIL;
    nil->instance_variables = NULL;

    sl_define_method(vm, vm->lib.Nil, "to_s", 0, nil_to_s);
    sl_define_method(vm, vm->lib.Nil, "inspect", 0, nil_inspect);
    sl_define_method(vm, vm->lib.Nil, "==", 1, nil_eq);
}
Exemple #17
0
static sl_method_t*
lookup_method_rec(sl_vm_t* vm, SLVAL klass, SLID id)
{
    sl_class_t* klassp = (sl_class_t*)sl_get_ptr(klass);
    if(klassp->base.primitive_type == SL_T_NIL) {
        return NULL;
    }

    sl_method_t* method;
    if(sl_st_lookup(klassp->instance_methods, (sl_st_data_t)id.id, (sl_st_data_t*)&method)) {
        return method;
    }

    return lookup_method_rec(vm, klassp->super, id);
}
Exemple #18
0
SLVAL
sl_make_method(sl_vm_t* vm, SLVAL klass, SLID name, sl_vm_section_t* section, sl_vm_exec_ctx_t* parent_ctx)
{
    SLVAL method = sl_allocate(vm, vm->lib.Method);
    sl_method_t* methp = (sl_method_t*)sl_get_ptr(method);
    methp->name = name;
    methp->is_c_func = 0;
    if(section->req_registers < section->arg_registers) {
        methp->arity = -section->req_registers - 1;
    } else {
        methp->arity = (int)section->arg_registers;
    }
    methp->klass = sl_expect(vm, klass, vm->lib.Class);
    methp->as.sl.section = section;
    methp->as.sl.parent_ctx = parent_ctx;
    methp->initialized = 1;
    return method;
}
Exemple #19
0
SLVAL
sl_make_method(sl_vm_t* vm, SLVAL klass, SLID name, sl_vm_section_t* section, sl_vm_exec_ctx_t* parent_ctx)
{
    SLVAL method = sl_allocate(vm, vm->lib.Method);
    sl_method_t* methp = (sl_method_t*)sl_get_ptr(method);
    methp->extra->name = name;
    if(section->req_registers < section->arg_registers) {
        methp->arity = -section->req_registers - 1;
    } else if(section->has_extra_rest_arg) {
        methp->arity = -(int)section->req_registers - 1;
    } else {
        methp->arity = (int)section->req_registers;
    }
    methp->extra->klass = sl_expect(vm, klass, vm->lib.Class);
    methp->as.sl.section = section;
    methp->as.sl.parent_ctx = parent_ctx;
    methp->base.user_flags |= SL_FLAG_METHOD_INITIALIZED;
    return method;
}
Exemple #20
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;
}
Exemple #21
0
SLVAL
sl_imc_setup_call(sl_vm_t* vm, sl_vm_inline_method_cache_t* imc, SLVAL recv, SLVAL* argv)
{
    SLVAL klass = SL_IS_INT(recv) ? vm->lib.Int : sl_get_ptr(recv)->klass;
    sl_method_t* method = lookup_method_rec(vm, klass, imc->id);
    if(method) {
        imc->state = vm->state_method;
        imc->klass = klass;
        imc->method = method;
        if(method->base.user_flags & SL_FLAG_METHOD_IS_C_FUNC) {
            if(method->arity < 0) {
                if(sl_likely(-imc->argc - 1 <= method->arity)) {
                    imc->call = dispatch_c_call_variadic;
                } else {
                    imc->call = sl_imc_cached_call; // cop out
                }
            } else {
                if(sl_likely(imc->argc == method->arity)) {
                    switch(method->arity) {
                        case 0: imc->call = dispatch_c_call_0; break;
                        case 1: imc->call = dispatch_c_call_1; break;
                        case 2: imc->call = dispatch_c_call_2; break;
                        case 3: imc->call = dispatch_c_call_3; break;
                        case 4: imc->call = dispatch_c_call_4; break;
                        default:
                            sl_throw_message(vm, "Too many arguments for C function");
                    }
                } else {
                    imc->call = sl_imc_cached_call; // cop out
                }
            }
        } else {
            if(method->arity >= 0 && imc->argc >= method->arity && method->as.sl.section->can_stack_alloc_frame && !method->as.sl.section->opt_skip) {
                imc->call = dispatch_slash_call_stack_regs;
            } else {
                imc->call = sl_imc_cached_call; // cop out
            }
        }
        return imc->call(vm, imc, recv, argv);
    } else {
        return sl_send_missing(vm, recv, imc->id, imc->argc, argv);
    }
}
Exemple #22
0
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));
}
Exemple #23
0
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);
}
Exemple #24
0
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;
}
Exemple #25
0
static SLVAL
response_write(sl_vm_t* vm, SLVAL self, size_t argc, SLVAL* argv)
{
    sl_response_internal_opts_t* resp = response(vm);
    size_t i;
    sl_string_t* str;
    (void)self;
    if(resp->buffered) {
        for(i = 0; i < argc; i++) {
            if(resp->output_len >= resp->output_cap) {
                resp->output_cap *= 2;
                resp->output = sl_realloc(vm->arena, resp->output, sizeof(SLVAL) * resp->output_cap);
            }
            resp->output[resp->output_len++] = sl_to_s(vm, argv[i]);
        }
    } else {
        for(i = 0; i < argc; i++) {
            str = (sl_string_t*)sl_get_ptr(sl_to_s(vm, argv[i]));
            resp->write(vm, (char*)str->buff, str->buff_len);
        }
    }
    return vm->lib.nil;
}
Exemple #26
0
static sl_range_enumerator_t*
get_range_enumerator(sl_vm_t* vm, SLVAL obj)
{
    sl_expect(vm, obj, vm->lib.Range_Enumerator);
    return (sl_range_enumerator_t*)sl_get_ptr(obj);
}
Exemple #27
0
static sl_range_t*
get_range(sl_vm_t* vm, SLVAL obj)
{
    sl_expect(vm, obj, vm->lib.Range);
    return (sl_range_t*)sl_get_ptr(obj);
}
Exemple #28
0
static sl_float_t*
get_float(sl_vm_t* vm, SLVAL val)
{
    sl_expect(vm, val, vm->lib.Float);
    return (sl_float_t*)sl_get_ptr(val);
}
Exemple #29
0
static sl_class_t*
get_class(sl_vm_t* vm, SLVAL klass)
{
    sl_expect(vm, klass, vm->lib.Class);
    return (sl_class_t*)sl_get_ptr(klass);
}
Exemple #30
0
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);
}