Пример #1
0
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]);
            });
Пример #2
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);
}
Пример #3
0
static OBJ TrArray_length(VM, OBJ self) {
  return TR_INT2FIX(TR_ARRAY_SIZE(self));
}
Пример #4
0
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;
}