}
}
+ def get_classmethod m {
+ &class_methods[m]
+ }
+
=> f {
if f == op::index {
- class_methods(op::index)
+ get_classmethod
} else {
=> method {
- instance_methods[method](f)
+ &(instance_methods[method](f))
}
}
}
sbBuffer_append(&cm->label_positions, &lp, sizeof(struct labelpos));
}
+/* things that implicitly dereference when used in a value context but
+ * can be assigned to on the left side of an = */
+flag is_implicit_ref(sbIrExpr *expr) {
+ return expr->type == IR_E_VAR || expr->type == IR_E_DOT || (expr->type == IR_E_OP && expr->op.type == AST_OP_INDEX);
+}
+
void compile_list(sbVmCompiler *cm, sbIrExpr *expr);
void compile_bind_list(sbVmCompiler *cm, sbIrBindList *list);
void compile_stmt(sbVmCompiler *cm, sbIrStmt *stmt) {
* The reason for this has to do with assigning through nested data structures.
* Doing it this way just makes the whole semantics feel more natural. It's similar
* to returning a reference from indexing in C++, I guess. */
- compile_ref(cm, stmt->assign.where->op.left, TRUE); /* thing we are indexing into */
+ if (is_implicit_ref(stmt->assign.where->op.left)) {
+ compile_ref(cm, stmt->assign.where->op.left, TRUE);
+ } else {
+ compile_expr(cm, stmt->assign.where->op.left);
+ }
compile_expr(cm, stmt->assign.where->op.right); /* index we are using */
- EMIT(BC_OP_INDEXLREF);
+ if (is_implicit_ref(stmt->assign.where->op.left)) {
+ EMIT(BC_OP_INDEXLREF_IND);
+ } else {
+ /* THE PROLIFERATION OF THESE!!!!!!!!!! I DO NOT LIKE!!!! */
+ EMIT(BC_OP_INDEXLREF);
+ }
EMIT(BC_REF_PUT);
} else if (stmt->assign.where->type == IR_E_DOT) {
/* same as op::index, essentially. the dot returns a reference to the inside of the
* thing, then we can assign to that reference */
- compile_expr(cm, stmt->assign.where->op.right);
+ compile_expr(cm, stmt->assign.where->dot.param);
EMIT(BC_LD_IMM);
EARG(1);
- compile_ref(cm, stmt->assign.where->op.left, TRUE);
- EMIT(BC_CALL_IND);
+ if (is_implicit_ref(stmt->assign.where->dot.target)) {
+ compile_ref(cm, stmt->assign.where->dot.target, TRUE);
+ EMIT(BC_DOT_IND);
+ } else {
+ compile_expr(cm, stmt->assign.where->dot.target);
+ EMIT(BC_DOT);
+ }
EMIT(BC_REF_PUT);
} else {
PANIC("This type of assignment operation is not supported!");
}
void compile_expr(sbVmCompiler *cm, sbIrExpr *expr) {
+ if (cm->debugmode) {
+ sbIr_print_expr(expr);
+ debug("\n");
+ }
+
switch(expr->type) {
case IR_E_OP:
if (expr->op.type == AST_OP_REF) {
case IR_E_CALL:
/* calling convention: store argument count on stack */
compile_list(cm, expr->call.param);
- if (expr->call.func->type == IR_E_DOT
- || (expr->call.func->type == IR_E_OP && expr->call.func->op.type == AST_OP_INDEX)) {
+ if (is_implicit_ref(expr->call.func)) {
/* for expressions with reference type, call 'through' the reference */
compile_ref(cm, expr->call.func, TRUE);
EMIT(BC_CALL_IND);
}
EARG(expr->var->slot_id);
} else if (expr->type == IR_E_OP && expr->op.type == AST_OP_INDEX) {
- compile_ref(cm, expr->op.left, is_lref); /* thing we are indexing into */
+ /* TODO: Oh my god, it's 90F with no air conditioning, but can we PLEASE figure out
+ * a better way to structure this??!!?!?!?! */
+ if (is_implicit_ref(expr->op.left)) {
+ compile_ref(cm, expr->op.left, is_lref); /* thing we are indexing into */
+ } else {
+ compile_expr(cm, expr->op.left); /* thing we are indexing into */
+ }
compile_expr(cm, expr->op.right); /* index we are using */
if (is_lref) {
/* a[0] = ? / a::b = ? */
- EMIT(BC_OP_INDEXLREF);
+ if (is_implicit_ref(expr->op.left)) {
+ /* THIS SUCKS!!! */
+ EMIT(BC_OP_INDEXLREF_IND);
+ } else {
+ EMIT(BC_OP_INDEXLREF);
+ }
} else {
/* &a[0] / &a::b */
- EMIT(BC_OP_INDEXRREF);
+ if (is_implicit_ref(expr->op.left)) {
+ EMIT(BC_OP_INDEXRREF_IND);
+ } else {
+ EMIT(BC_OP_INDEXRREF);
+ }
}
} else if (expr->type == IR_E_DOT) {
compile_expr(cm, expr->dot.param);
EMIT(BC_LD_IMM);
EARG(1);
- compile_ref(cm, expr->dot.target, is_lref);
- EMIT(BC_DOT);
+ if (is_implicit_ref(expr->dot.target)) {
+ compile_ref(cm, expr->dot.target, is_lref);
+ EMIT(BC_DOT_IND);
+ } else {
+ compile_expr(cm, expr->dot.target);
+ EMIT(BC_DOT);
+ }
} else {
- PANIC("cannot & non-variable-name! (todo)");
+ PANIC("This type of reference operation is not supported!");
}
}
debug(")");
break;
case IR_E_CALL:
- debug("CALL: ");
+ debug("(CALL: ");
print_expr(e->call.func);
- debug(" with params (");
+ debug(" with params ");
if (e->call.param) {
print_expr(e->call.param);
}
/* resolve_method should have set us up so we can just call in twice */
static sbCFuncStatus please_call_again(hVm vm, flag init) {
hVal *target = sbVm_pop(vm);
- if (target->type <= 0) {
+ if (init && target->type <= 0) {
PANIC("i have not implemented partial methods for builtin types yet! i'll get to it");
+ } else if (!init && target->type != IT_REF) {
+ PANIC("object illegally did not return a reference!");
}
if (init) {
/* first time around: call to dispatch method */
sbVm_call_func(vm, target);
- /* please call us again if you have any questions*/
+ /* please call us again if you have any questions */
return CFUNC_NEXT;
} else {
/* second time around: call method on its parameters */
- sbVm_transfer_to_func(vm, target);
+ hVal *bound_method_ptr = sbVar_get_value_ptr(sbVar_deref(target));
+ sbVm_transfer_to_func(vm, bound_method_ptr);
/* please forget we ever existed */
return CFUNC_TAILCALL;
hSymbol *keys;
union {
sbLibMethod *methods;
- hVal *values;
+ sbVar *values;
};
} sbLibTable;
*/
static void insert_method(hSymbol *keys, sbLibMethod *methods, usize capacity, hSymbol key, sbLibMethod *method);
-static void insert_value(hSymbol *keys, hVal *values, usize capacity, hSymbol key, hVal *value);
+static void insert_value(hSymbol *keys, sbVar *values, usize capacity, hSymbol key, hVal *value);
static void check_grow_table(hLibTable t);
void sbLibTable_initialize(hLibTable t, usize capacity, flag method_table) {
}
if (t->keys[index]) {
- return &t->values[index];
+ return sbVar_get_value_ptr(&t->values[index]);
} else {
return NULL;
}
}
+hVal sbLibTable_find_ref(hLibTable t, hSymbol key) {
+ if (t->method_table) CHECK("cannot find value in method table");
+
+ sbHashValue hash = sbHash_hash_bytes((const char*)&key, sizeof(hSymbol));
+ usize index = hash % t->capacity;
+ while (t->keys[index] && t->keys[index] != key) {
+ index ++;
+ index %= t->capacity;
+ }
+
+ if (t->keys[index]) {
+ /* lvalue ref always safe because these never get deallocated */
+ return sbVar_get_lvalue_ref(&t->values[index]);
+ } else {
+ return HVNIL;
+ }
+}
+
void sbLibTable_register_method_sym(hLibTable t, hSymbol key, sbLibMethod *method) {
if (!t->method_table) CHECK("cannot put method in non-method table");
methods[index] = *method;
}
-static void insert_value(hSymbol *keys, hVal *values, usize capacity, hSymbol key, hVal *value) {
+static void insert_value(hSymbol *keys, sbVar *values, usize capacity, hSymbol key, hVal *value) {
sbHashValue hash = sbHash_hash_bytes((const char*)&key, sizeof(hSymbol));
usize index = hash % capacity;
}
keys[index] = key;
- values[index] = *value;
+ sbVar_set_value(&values[index], value);
}
static void check_grow_table(hLibTable t) {
free(t->methods);
t->methods = new_methods;
} else {
- hVal *new_values = calloc(new_capacity, sizeof(hVal));
+ sbVar *new_values = calloc(new_capacity, sizeof(hVal));
for (usize i = 0; i < t->capacity; i++) {
if (t->keys[i] != 0) {
- insert_value(new_keys, new_values, new_capacity, t->keys[i], &t->values[i]);
+ insert_value(new_keys, new_values, new_capacity, t->keys[i], sbVar_get_value_ptr(&t->values[i]));
}
}
flag method_table;
union {
sbLibMethod *methods;
- hVal *values;
+ sbVar *values;
};
} sbLibTable;
hVal *sbLibTable_find_value(hLibTable t, hSymbol key);
+hVal sbLibTable_find_ref(hLibTable t, hSymbol key);
+
void sbLibTable_register_method(hLibTable t, const char *method_name, usize method_name_length, sbLibMethod *method);
void sbLibTable_register_method_sym(hLibTable t, hSymbol key, sbLibMethod *method);
BC_SWAP, // swap top two values on stack
BC_CALL, // push return address and jump to new block
BC_CALL_IND, // 'a->(...)' indirect call that can return a value
- BC_DOT, // 'a.b' indirect call that should return a reference
+ BC_DOT, // 'a.b' call that should return a reference
+ BC_DOT_IND, // 'a.b' indirect call that should return a reference
BC_RET, // return to calling block
BC_NUMARG, // check number of function arguments = this
BC_MINARG, // check number of function arguments > this
BC_OP_OR, // logical or
BC_OP_INDEXVAL, // a[...]
BC_OP_INDEXLREF, // a[...] = ...
+ BC_OP_INDEXLREF_IND, // a[...] = ...
BC_OP_INDEXRREF, // &a[...]
+ BC_OP_INDEXRREF_IND, // &a[...]
BC_OP_RANGEINDEX, // index [a..b]
BC_ALLOC_VARS, // create space in rstack for local variables
BC_CLOSURE, // create closure from top elements of stack
swap_stack_top(vm);
break;
case BC_CALL:
+ case BC_DOT:
v = pop_stack(vm);
sbVm_call_func(vm, v);
break;
- case BC_DOT:
+ case BC_DOT_IND:
case BC_CALL_IND:
v = pop_stack(vm);
- if (v->type != IT_REF) {
+ if (v->type == IT_REF) {
+ vars = sbVar_deref(v);
+ w = sbVar_get_value_ptr(vars);
+ sbVm_call_func(vm, w);
+ } else if (v->type & IT_FLAG_BOUND_METHOD) {
+ sbVm_call_func(vm, v);
+ } else {
PANIC("object illegally returned non-reference value");
}
- vars = sbVar_deref(v);
- sbVm_call_func(vm, sbVar_get_value_ptr(vars));
break;
case BC_SEND:
sbLib_resolve_method(vm);
sbV_index_value(vm);
break;
case BC_OP_INDEXLREF:
- sbV_index_lref(vm);
+ sbV_index_ref(vm, TRUE, FALSE);
+ break;
+ case BC_OP_INDEXLREF_IND:
+ sbV_index_ref(vm, TRUE, TRUE);
break;
case BC_OP_INDEXRREF:
- sbV_index_rref(vm);
+ sbV_index_ref(vm, FALSE, FALSE);
+ break;
+ case BC_OP_INDEXRREF_IND:
+ sbV_index_ref(vm, FALSE, TRUE);
break;
case BC_OP_RANGEINDEX:
v = peek_stack(vm, 2);
}
}
-void sbV_index_lref(hVm vm) {
+void sbV_index_ref(hVm vm, flag is_lref, flag is_indirect) {
hVal *a = sbVm_peek(vm, 1);
hVal *b = sbVm_peek(vm, 0);
- if (a->type != IT_REF) {
- PANIC("Object illegally returned non-reference!");
+
+ if (is_indirect) {
+ if (a->type != IT_REF) {
+ PANIC("Object illegally returned non-reference!");
+ }
+ a = sbVar_get_value_ptr(sbVar_deref(a));
}
- a = sbVar_get_value_ptr(sbVar_deref(a));
if (a->type == IT_LIST && b->type == IT_INTEGER) {
sbVm_npop(vm, 2);
- hVal result = sbList_index_lvalue_ref(a->list, b->integer);
+ hVal result;
+ if (is_lref) {
+ result = sbList_index_lvalue_ref(a->list, b->integer);
+ } else {
+ result = sbList_index_rvalue_ref(a->list, b->integer);
+ }
sbVm_push(vm, &result);
} else if (a->type == IT_HASH) {
sbVm_npop(vm, 2);
- hVal result = sbHash_find_lvalue_ref(a->hash, b);
+ hVal result;
+ if (is_lref) {
+ result = sbHash_find_lvalue_ref(a->hash, b);
+ } else {
+ result = sbHash_find_rvalue_ref(a->hash, b);
+ }
sbVm_push(vm, &result);
} else if (a->type == IT_MODULE && b->type == IT_SYMBOL) {
- PANIC("TODO");
- } else {
- sbVm_swap(vm); /* b a */
- sbVm_push_immediate(vm, &HVSYM(S_OP_INDEX)); /* b a op::index */
- sbVm_swap(vm); /* b op::index a */
- sbVm_push_immediate(vm, &HVINT(2)); /* b op::index a 2 */
- sbVm_swap(vm); /* b op::index 2 a */
- sbLib_resolve_method(vm);
- }
-}
-
-void sbV_index_rref(hVm vm) {
- hVal *a = sbVm_peek(vm, 1);
- hVal *b = sbVm_peek(vm, 0);
- if (a->type != IT_REF) {
- PANIC("Object illegally returned non-reference!");
- }
- a = sbVar_get_value_ptr(sbVar_deref(a));
-
- if (a->type == IT_LIST && b->type == IT_INTEGER) {
- sbVm_npop(vm, 2);
- hVal result = sbList_index_rvalue_ref(a->list, b->integer);
- sbVm_push(vm, &result);
- } else if (a->type == IT_HASH) {
sbVm_npop(vm, 2);
- hVal result = sbHash_find_rvalue_ref(a->hash, b);
+ hVal result = sbLibTable_find_ref(a->module, b->symbol);
sbVm_push(vm, &result);
- } else if (a->type == IT_MODULE && b->type == IT_SYMBOL) {
- PANIC("TODO");
} else {
sbVm_swap(vm); /* b a */
sbVm_push_immediate(vm, &HVSYM(S_OP_INDEX)); /* b a op::index */
void sbV_index_value(hVm vm);
-void sbV_index_lref(hVm vm);
-
-void sbV_index_rref(hVm vm);
+void sbV_index_ref(hVm vm, flag is_lref, flag is_indirect);
hVal sbV_rangeindex(hVal *a, hVal *b, hVal *c);