|
6 | 6 | #include <string.h> |
7 | 7 |
|
8 | 8 | #include "agent.h" |
| 9 | +#include "builtin_modules.h" |
9 | 10 | #include "cbcvm.h" |
10 | 11 | #include "cb_util.h" |
11 | 12 | #include "compiler.h" |
@@ -296,6 +297,70 @@ static void debug_state(size_t sp, size_t pc, struct cb_frame *frame) |
296 | 297 | } |
297 | 298 | #endif |
298 | 299 |
|
| 300 | +/* FIXME: hacky as */ |
| 301 | +static int method_caller(size_t argc, struct cb_value *argv, |
| 302 | + struct cb_value *result) |
| 303 | +{ |
| 304 | + struct cb_value receiver, func; |
| 305 | + struct cb_frame *frame, new_frame; |
| 306 | + struct cb_user_function *ufunc; |
| 307 | + struct cb_code *code; |
| 308 | + |
| 309 | + receiver = cb_cfunc_load_upvalue(0); |
| 310 | + func = cb_cfunc_load_upvalue(1); |
| 311 | + assert(func.val.as_function->type == CB_FUNCTION_USER); |
| 312 | + ufunc = &func.val.as_function->value.as_user; |
| 313 | + code = ufunc->code; |
| 314 | + |
| 315 | + frame = cb_vm_state.frame; |
| 316 | + ensure_stack(code->stack_size + 1, *frame->sp - cb_vm_state.stack); |
| 317 | + memmove(argv, argv + 1, argc); |
| 318 | + |
| 319 | + cb_vm_state.stack[frame->bp] = receiver; |
| 320 | + cb_vm_state.stack[frame->bp + 1] = func; |
| 321 | + |
| 322 | + new_frame.parent = frame; |
| 323 | + new_frame.module_id = cb_modspec_id(code->modspec); |
| 324 | + new_frame.is_function = 1; |
| 325 | + new_frame.is_native = 0; |
| 326 | + new_frame.num_args = argc; |
| 327 | + new_frame.code = code; |
| 328 | + new_frame.bp = frame->bp + 1; |
| 329 | + |
| 330 | + int failed = cb_eval(&new_frame); |
| 331 | + cb_vm_state.frame = frame; |
| 332 | + *result = cb_vm_state.stack[new_frame.bp]; |
| 333 | + return failed; |
| 334 | +} |
| 335 | + |
| 336 | +static void set_upvalue(struct cb_upvalue **uv, struct cb_value value) |
| 337 | +{ |
| 338 | + (*uv) = malloc(sizeof(struct cb_upvalue)); |
| 339 | + (*uv)->refcount = 1; |
| 340 | + (*uv)->is_closed = 1; |
| 341 | + (*uv)->v.value = value; |
| 342 | +} |
| 343 | + |
| 344 | +static struct cb_value make_method_caller(struct cb_value receiver, |
| 345 | + struct cb_function *method) |
| 346 | +{ |
| 347 | + struct cb_value bound_method = cb_cfunc_new(method->name, method->arity, |
| 348 | + method_caller); |
| 349 | + const int num_upvalues = 2; |
| 350 | + struct cb_upvalue **method_upvalues = malloc( |
| 351 | + num_upvalues * sizeof(struct cb_upvalue *)); |
| 352 | + bound_method.val.as_function->nupvalues = num_upvalues; |
| 353 | + bound_method.val.as_function->upvalues = method_upvalues; |
| 354 | + |
| 355 | + set_upvalue(&method_upvalues[0], receiver); |
| 356 | + set_upvalue(&method_upvalues[1], (struct cb_value) { |
| 357 | + .type = CB_VALUE_FUNCTION, |
| 358 | + .val = { .as_function = method }, |
| 359 | + }); |
| 360 | + |
| 361 | + return bound_method; |
| 362 | +} |
| 363 | + |
299 | 364 | int eval_depth = 0; |
300 | 365 |
|
301 | 366 | static int cb_eval(struct cb_frame *frame) |
@@ -1085,20 +1150,28 @@ DO_OP_LOAD_STRUCT: { |
1085 | 1150 | } |
1086 | 1151 | ssize_t idx; |
1087 | 1152 | val = cb_struct_get_field(s, fname, &idx); |
1088 | | - if (!val) { |
1089 | | - cb_str fname_str, specname_str; |
1090 | | - |
1091 | | - fname_str = cb_agent_get_string(fname); |
1092 | | - specname_str = cb_agent_get_string(s->spec->name); |
1093 | | - ERROR("No such field '%s' on struct '%s'", |
1094 | | - cb_strptr(&fname_str), |
1095 | | - cb_strptr(&specname_str)); |
| 1153 | + struct cb_value result; |
| 1154 | + if (val) { |
| 1155 | + result = *val; |
| 1156 | + } else { |
| 1157 | + struct cb_function *method = |
| 1158 | + cb_struct_spec_get_method(s->spec, fname); |
| 1159 | + if (method == NULL) { |
| 1160 | + cb_str fname_str, specname_str; |
| 1161 | + |
| 1162 | + fname_str = cb_agent_get_string(fname); |
| 1163 | + specname_str = cb_agent_get_string(s->spec->name); |
| 1164 | + ERROR("No such field '%s' on struct '%s'", |
| 1165 | + cb_strptr(&fname_str), |
| 1166 | + cb_strptr(&specname_str)); |
| 1167 | + } |
| 1168 | + result = make_method_caller(recv, method); |
1096 | 1169 | } |
1097 | 1170 | if (ic->index != -1) { |
1098 | 1171 | ic->spec = s->spec; |
1099 | 1172 | ic->index = idx; |
1100 | 1173 | } |
1101 | | - PUSH(*val); |
| 1174 | + PUSH(result); |
1102 | 1175 | DISPATCH(); |
1103 | 1176 | } |
1104 | 1177 |
|
|
0 commit comments