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 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 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 */ } }
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_MINUS: case SL_TOK_POW: case SL_TOK_TIMES: case SL_TOK_DIVIDE: case SL_TOK_MOD: case SL_TOK_CARET: case SL_TOK_TILDE: case SL_TOK_AMP: case SL_TOK_PIPE: return sl_intern2(ps->vm, next_token(ps)->str); /* keywords: */ case SL_TOK_LAST: case SL_TOK_NEXT: return sl_intern2(ps->vm, next_token(ps)->str); case SL_TOK_OPEN_BRACKET: if(peek_token_n(ps, 2)->type == SL_TOK_CLOSE_BRACKET) { next_token(ps); next_token(ps); return sl_intern(ps->vm, "[]"); } default: unexpected(ps, next_token(ps)); SLID dummy; return dummy; /* never reached */ } }
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; SLID mid = sl_intern2(vm, method_name); if(sl_st_lookup(klass->instance_methods, (sl_st_data_t)mid.id, (sl_st_data_t*)&method)) { return method; } return vm->lib.nil; }
static sl_node_base_t* power_expression(sl_parse_state_t* ps) { sl_node_base_t* left = inc_dec_expression(ps); sl_node_base_t* right; sl_token_t* tok; if(peek_token(ps)->type == SL_TOK_POW) { tok = next_token(ps); right = power_expression(ps); left = sl_make_send_node(ps, left, sl_intern2(ps->vm, tok->str), 1, &right); } return left; }
static sl_node_base_t* add_expression(sl_parse_state_t* ps) { sl_node_base_t* left = mul_expression(ps); sl_node_base_t* right; sl_token_t* tok; while(peek_token(ps)->type == SL_TOK_PLUS || peek_token(ps)->type == SL_TOK_MINUS) { tok = next_token(ps); right = mul_expression(ps); left = sl_make_send_node(ps, left, sl_intern2(ps->vm, tok->str), 1, &right); } return left; }
static sl_node_base_t* shift_expression(sl_parse_state_t* ps) { sl_node_base_t* left = add_expression(ps); sl_node_base_t* right; sl_token_t* tok; while(peek_token(ps)->type == SL_TOK_SHIFT_LEFT || peek_token(ps)->type == SL_TOK_SHIFT_RIGHT) { tok = next_token(ps); right = add_expression(ps); left = sl_make_send_node(ps, left, sl_intern2(ps->vm, tok->str), 1, &right); } return left; }
static sl_node_base_t* mul_expression(sl_parse_state_t* ps) { sl_node_base_t* left = unary_expression(ps); sl_node_base_t* right; sl_token_t* tok; while(peek_token(ps)->type == SL_TOK_TIMES || peek_token(ps)->type == SL_TOK_DIVIDE || peek_token(ps)->type == SL_TOK_MOD) { tok = next_token(ps); right = unary_expression(ps); left = sl_make_send_node(ps, left, sl_intern2(ps->vm, tok->str), 1, &right, false); } return left; }
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; 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) { return method; } } return vm->lib.nil; }
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)) { 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; }
static sl_node_base_t* class_expression(sl_parse_state_t* ps) { expect_token(ps, SL_TOK_CLASS); 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, extends, body); }
static sl_node_base_t* unary_expression(sl_parse_state_t* ps) { sl_node_base_t* expr; sl_token_t* tok; switch(peek_token(ps)->type) { case SL_TOK_MINUS: tok = next_token(ps); expr = unary_expression(ps); return sl_make_send_node(ps, expr, sl_intern(ps->vm, "negate"), 0, NULL); case SL_TOK_TILDE: tok = next_token(ps); expr = unary_expression(ps); return sl_make_send_node(ps, expr, sl_intern2(ps->vm, tok->str), 0, NULL); case SL_TOK_NOT: next_token(ps); expr = unary_expression(ps); return sl_make_unary_node(ps, expr, SL_NODE_NOT); case SL_TOK_RETURN: tok = next_token(ps); if(!(ps->scope->flags & SL_PF_CAN_RETURN)) { error(ps, sl_make_cstring(ps->vm, "Can't return outside of a method or lambda"), tok); } switch(peek_token(ps)->type) { case SL_TOK_SEMICOLON: case SL_TOK_CLOSE_BRACE: case SL_TOK_CLOSE_TAG: /* in these case we want to allow for postfix control structures: */ case SL_TOK_IF: case SL_TOK_UNLESS: return sl_make_unary_node(ps, sl_make_immediate_node(ps, ps->vm->lib.nil), SL_NODE_RETURN); default: return sl_make_unary_node(ps, low_precedence_logical_expression(ps), SL_NODE_RETURN); } break; case SL_TOK_THROW: next_token(ps); return sl_make_unary_node(ps, low_precedence_logical_expression(ps), SL_NODE_THROW); case SL_TOK_USE: return use_expression(ps); default: return power_expression(ps); } }
static sl_node_base_t* bitwise_expression(sl_parse_state_t* ps) { sl_node_base_t* left = shift_expression(ps); sl_node_base_t* right; sl_token_t* tok; while(1) { switch(peek_token(ps)->type) { case SL_TOK_PIPE: case SL_TOK_AMP: case SL_TOK_CARET: tok = next_token(ps); right = shift_expression(ps); left = sl_make_send_node(ps, left, sl_intern2(ps->vm, tok->str), 1, &right); break; default: return left; } } }
static sl_node_base_t* relational_expression(sl_parse_state_t* ps) { sl_node_base_t* left = bitwise_expression(ps); sl_token_t* tok; sl_node_base_t* right; switch(peek_token(ps)->type) { case SL_TOK_DBL_EQUALS: case SL_TOK_NOT_EQUALS: case SL_TOK_LT: case SL_TOK_GT: case SL_TOK_LTE: case SL_TOK_GTE: case SL_TOK_SPACESHIP: tok = next_token(ps); right = bitwise_expression(ps); return sl_make_send_node(ps, left, sl_intern2(ps->vm, tok->str), 1, &right); default: return left; } }
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; }
NODE(sl_node_var_t, cvar) { SLID id = sl_intern2(cs->vm, sl_make_ptr((sl_object_t*)node->name)); op_get_cvar(cs, id, dest); }
SLID sl_intern(sl_vm_t* vm, char* cstr) { return sl_intern2(vm, sl_make_cstring(vm, cstr)); }
SLID sl_id_make_setter(sl_vm_t* vm, SLID id) { SLVAL str = sl_make_formatted_string(vm, "%I=", id); return sl_intern2(vm, str); }
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); }
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; } }