OBJ TrCompiler_compile_node(VM, TrCompiler *c, TrBlock *b, TrNode *n, int reg) { if (!n) return TR_NIL; int start_reg = reg; REG(reg); b->line = n->line; /* TODO this shit is very repetitive, need to refactor */ switch (n->ntype) { case NODE_ROOT: case NODE_BLOCK: COMPILE_NODES(b, n->args[0], i, reg, 0); break; case NODE_VALUE: { int i = TrBlock_push_value(b, n->args[0]); PUSH_OP_ABx(b, LOADK, reg, i); } break; case NODE_STRING: { int i = TrBlock_push_string(b, TR_STR_PTR(n->args[0])); PUSH_OP_ABx(b, STRING, reg, i); } break; case NODE_ARRAY: { size_t size = 0; if (n->args[0]) { size = TR_ARRAY_SIZE(n->args[0]); /* compile args */ COMPILE_NODES(b, n->args[0], i, reg, i+1); ASSERT_NO_LOCAL_IN(Array); } PUSH_OP_AB(b, NEWARRAY, reg, size); } break; case NODE_HASH: { size_t size = 0; if (n->args[0]) { size = TR_ARRAY_SIZE(n->args[0]); /* compile args */ COMPILE_NODES(b, n->args[0], i, reg, i+1); ASSERT_NO_LOCAL_IN(Hash); } PUSH_OP_AB(b, NEWHASH, reg, size/2); } break; case NODE_RANGE: { COMPILE_NODE(b, n->args[0], reg); COMPILE_NODE(b, n->args[1], reg+1); REG(reg+1); ASSERT_NO_LOCAL_IN(Range); PUSH_OP_ABC(b, NEWRANGE, reg, reg+1, n->args[2]); } break; case NODE_ASSIGN: { OBJ name = n->args[0]; COMPILE_NODE(b, n->args[1], reg); if (TrBlock_find_upval_in_scope(b, name) != -1) { /* upval */ int i = TrBlock_push_upval(b, name); PUSH_OP_AB(b, SETUPVAL, reg, i); } else { /* local */ int i = TrBlock_push_local(b, name); TrInst *last_inst = &kv_A(b->code, kv_size(b->code) - 1); switch (GET_OPCODE(*last_inst)) { case TR_OP_ADD: /* Those instructions can load direcly into a local */ case TR_OP_SUB: case TR_OP_LT: case TR_OP_NEG: case TR_OP_NOT: SETARG_A(*last_inst, i); break; default: if (i != reg) PUSH_OP_AB(b, MOVE, i, reg); } } } break; case NODE_SETIVAR: COMPILE_NODE(b, n->args[1], reg); PUSH_OP_ABx(b, SETIVAR, reg, TrBlock_push_value(b, n->args[0])); break; case NODE_GETIVAR: PUSH_OP_ABx(b, GETIVAR, reg, TrBlock_push_value(b, n->args[0])); break; case NODE_SETCVAR: COMPILE_NODE(b, n->args[1], reg); PUSH_OP_ABx(b, SETCVAR, reg, TrBlock_push_value(b, n->args[0])); break; case NODE_GETCVAR: PUSH_OP_ABx(b, GETCVAR, reg, TrBlock_push_value(b, n->args[0])); break; case NODE_SETGLOBAL: COMPILE_NODE(b, n->args[1], reg); PUSH_OP_ABx(b, SETGLOBAL, reg, TrBlock_push_value(b, n->args[0])); break; case NODE_GETGLOBAL: PUSH_OP_ABx(b, GETGLOBAL, reg, TrBlock_push_value(b, n->args[0])); break; case NODE_SEND: /* can also be a variable access */ { TrNode *msg = (TrNode *)n->args[1]; OBJ name = msg->args[0]; assert(msg->ntype == NODE_MSG); int i; /* local */ if ((i = TrBlock_find_local(b, name)) != -1) { if (reg != i) PUSH_OP_AB(b, MOVE, reg, i); /* upval */ } else if (TrBlock_find_upval_in_scope(b, name) != -1) { i = TrBlock_push_upval(b, name); PUSH_OP_AB(b, GETUPVAL, reg, i); /* method call */ } else { /* receiver */ if (n->args[0]) COMPILE_NODE(b, n->args[0], reg); else PUSH_OP_A(b, SELF, reg); i = TrBlock_push_value(b, name); /* args */ size_t argc = 0; if (msg->args[1]) { argc = TR_ARRAY_SIZE(msg->args[1]) << 1; TR_ARRAY_EACH(msg->args[1], i, v, { TrNode *arg = (TrNode *)v; assert(arg->ntype == NODE_ARG); reg += COMPILE_NODE(b, arg->args[0], reg+i+2); if (arg->args[1]) argc |= 1; /* splat */ }); ASSERT_NO_LOCAL_IN(arguments); } /* block */ size_t blki = 0; TrBlock *blk = 0; if (n->args[2]) { blk = TrBlock_new(c, b); TrNode *blkn = (TrNode *)n->args[2]; blki = kv_size(b->blocks) + 1; blk->argc = 0; if (blkn->args[1]) { blk->argc = TR_ARRAY_SIZE(blkn->args[1]); /* add parameters as locals in block context */ TR_ARRAY_EACH(blkn->args[1], i, v, { TrNode *param = (TrNode *)v; TrBlock_push_local(blk, param->args[0]); });
static OBJ TrArray_at(VM, OBJ self, OBJ at) { int i = TrArray_at2index(vm, self, at); if (i < 0 || i >= TR_ARRAY_SIZE(self)) return TR_NIL; return TR_ARRAY_AT(self, i); }
static OBJ TrArray_length(VM, OBJ self) { return TR_INT2FIX(TR_ARRAY_SIZE(self)); }
static inline int TrArray_at2index(VM, OBJ self, OBJ at) { int i = TR_FIX2INT(at); if (i < 0) i = TR_ARRAY_SIZE(self) + i; return i; }