示例#1
0
static void ffi_ptr_dereference_assign(VMState *state, CallInfo *info) {
  VM_ASSERT(info->args_len == 3, "wrong arity: expected 2, got %i", info->args_len);
  Object *root = state->root;
  Object *pointer_base = state->shared->vcache.pointer_base;

  FFIObject *ffi = (FFIObject*) AS_OBJ(OBJECT_LOOKUP(root, ffi));
  Object *ffi_type = AS_OBJ(OBJECT_LOOKUP((Object*) ffi, type));

  Object *thisptr = AS_OBJ(load_arg(state->frame, info->this_arg));
  VM_ASSERT(thisptr->parent == pointer_base, "internal error");
  PointerObject *thisptr_obj = (PointerObject*) thisptr;

  Object *ffi_type_obj = obj_instance_of(OBJ_OR_NULL(load_arg(state->frame, INFO_ARGS_PTR(info)[0])), ffi_type);
  Value offs_val = load_arg(state->frame, INFO_ARGS_PTR(info)[1]);
  VM_ASSERT(IS_INT(offs_val), "offset must be integer");
  int offs = AS_INT(offs_val);
  VM_ASSERT(ffi_type_obj, "type is not a FFI type");
  char *offset_ptr = (char*) thisptr_obj->ptr + offs;

  Value value = load_arg(state->frame, INFO_ARGS_PTR(info)[2]);

  (void) offset_ptr; (void) value;
  if (ffi_type_obj == ffi->long_obj) {
    VM_ASSERT(IS_INT(value), "can only assign integer to long");
    *(long*) offset_ptr = AS_INT(value);
  } else {
    fprintf(stderr, "TODO\n");
    abort();
  }
}
示例#2
0
cullResult_t r_cull_bbox(ac_vec4_t bounds[2]) {
	ac_vec4_t v;
	int i, x, y, z;
	bool intersect = false;

	for (i = 0; i < 6; i++) {
		// floating point magic! extract the sign bits
#define AS_INT(f)		(*(int *)(&(f)))
		x = (AS_INT(r_frustum[i].f[0]) & 0x80000000) >> 31;
		y = (AS_INT(r_frustum[i].f[1]) & 0x80000000) >> 31;
		z = (AS_INT(r_frustum[i].f[2]) & 0x80000000) >> 31;
#undef AS_INT
		// test the negative far point against the plane
		v = ac_vec_set(
				bounds[1 - x].f[0],
				bounds[1 - y].f[1],
				bounds[1 - z].f[2],
				0);
		if (ac_vec_dot(v, r_frustum[i]) < r_frustum[i].f[3])
			// negative far point behind plane -> box outside frustum
			return CR_OUTSIDE;
		// test the positive far point against the plane
		v = ac_vec_set(
				bounds[x].f[0],
				bounds[y].f[1],
				bounds[z].f[2],
				0);
		if (ac_vec_dot(v, r_frustum[i]) < r_frustum[i].f[3])
			intersect = true;
	}
	return intersect ? CR_INTERSECT : CR_INSIDE;
}
示例#3
0
/**
 * Finds the minimum value in a list.
 *
 * @param args list of args
 * @param c number of args
 * @returns min number in list
 */
LuciObject *luci_min(LuciObject **args, unsigned int c)
{
    if (c < 1) {
        LUCI_DIE("%s", "Missing parameter to min()\n");
    }

    LuciObject *list = args[0];

    if (!list || (!ISTYPE(list, obj_list_t))) {
        LUCI_DIE("%s", "Must specify a list to calculate min\n");
    }

    LuciObject *item;
    double min = 0;
    unsigned int i, found_float = 0;

    for (i = 0; i < AS_LIST(list)->count; i ++) {
        item = AS_LIST(list)->items[i];
        if (!item) {
            LUCI_DIE("%s", "Can't calulate max of list containing NULL value\n");
        }
        if (ISTYPE(item, obj_int_t)) {
            if (i == 0) {
                min = (double)AS_INT(item)->i;
            }
            else if ( (double)AS_INT(item)->i < min) {
                min = (double)AS_INT(item)->i;
            }
        } else if (ISTYPE(item, obj_float_t)) {
            found_float = 1;
            if (i == 0) {
                min = AS_FLOAT(item)->f;
            }
            else if (AS_FLOAT(item)->f < min) {
                min = AS_FLOAT(item)->f;
            }
        } else {
            LUCI_DIE("Can't find min of list containing an object of type %s\n",
                    item->type->type_name);
        }
    }

    LuciObject *ret;
    if (!found_float) {
        ret = LuciInt_new((long)min);
    }
    else {
        ret = LuciFloat_new(min);
    }

    return ret;
}
示例#4
0
bool condition_op_const::eval(record_type& rt, record& r){
	if (offset==-1){
		offset = offset_of_column(rt, lhs_table_name, lhs_column_name);
		if (offset==-1) throw string("Undefined column");
	}
	if (index==-1){
		index = index_of_column(rt, lhs_table_name, lhs_column_name);
		if (index==-1) throw string("Undefined column");
	}

	if (rt[index].type == column_type::INT){

		if (op=="<"){
			return AS_INT(r[offset]) < value.vInt;
		} else if (op=="="){
			return AS_INT(r[offset]) == value.vInt;
		} else if (op==">"){
			return AS_INT(r[offset]) > value.vInt;
		}

		throw string("unimplemented operators in condition_op_const");
	}
	else if(rt[index].type == column_type::FLOAT){

		if (op=="<"){
			return AS_FLOAT(r[offset]) < value.vFloat;
		} else if (op=="="){
			return AS_FLOAT(r[offset]) == value.vFloat;
		} else if (op==">"){
			return AS_FLOAT(r[offset]) > value.vFloat;
		}
		throw string("unimplemented operators in condition_op_const");
	}
	else if(rt[index].type == column_type::STRING){

		if (op=="<"){
			return (strncmp(AS_STRING(r[offset]), value.vString, 500) < 0);
		} else if (op=="="){
			return (strncmp(AS_STRING(r[offset]), value.vString, 500) == 0);
		} else if (op==">"){
			return (strncmp(AS_STRING(r[offset]), value.vString, 500) > 0);
		}

		throw string("unimplemented operators in condition_op_const");
	}
	//throw string("unimplemented datatypes in condition_op_const");

}
示例#5
0
/**
 * Casts a LuciObject to a LuciFloatObj if possible, then returns
 * the new object.
 *
 * @param args list of args
 * @param c number of args
 * @returns LuciFloatObj cast of the first arg
 */
LuciObject *luci_cast_float(LuciObject **args, unsigned int c)
{
    LuciObject *ret = LuciNilObj;
    if (c < 1) {
        LUCI_DIE("%s", "Missing parameter to int()\n");
    }
    LuciObject *item = args[0];

    if (!item) {
        LUCI_DIE("%s", "Can't cast NULL to int\n");
    }

    if (ISTYPE(item, obj_int_t)) {
        ret = LuciFloat_new((double)AS_INT(item)->i);
    } else if (ISTYPE(item, obj_float_t)) {
        ret = LuciFloat_new(AS_FLOAT(item)->f);
    } else if (ISTYPE(item, obj_string_t)) {
        double f;
        int scanned = sscanf(AS_STRING(item)->s, "%f", (float *)&f);
        if (scanned <= 0 || scanned == EOF) {
            LUCI_DIE("%s", "Could not cast to float\n");
        }
        ret = LuciFloat_new(f);
    } else {
        LUCI_DIE("Cannot cast type %s to type float\n", item->type->type_name);
    }

    return ret;
}
示例#6
0
/**
 * Asserts that a given LuciObject is equivalent to a boolean True
 *
 * Currently uses C @code assert @endcode , which will exit a program
 * mid-execution if the assertion fails.
 *
 * @param args list of args
 * @param c number of args
 * @returns LuciNilObj
 */
LuciObject *luci_assert(LuciObject **args, unsigned int c)
{
    if (c < 1) {
        LUCI_DIE("%s", "Missing condition parameter to assert()\n");
    }

    LuciObject *item = args[0];

    if (ISTYPE(item, obj_int_t) && !AS_INT(item)->i) {
        LUCI_DIE("%s\n", "Assertion failed");
    } else if (ISTYPE(item, obj_float_t) && !((long)AS_FLOAT(item)->f)) {
        LUCI_DIE("%s\n", "Float assertion failed");
    } else if (ISTYPE(item, obj_string_t)) {
        if (strcmp("", AS_STRING(item)->s) == 0) {
            LUCI_DIE("%s\n", "String assertion failed");
        }
    } else if (ISTYPE(item, obj_list_t) && (AS_LIST(item)->count == 0)) {
        LUCI_DIE("%s\n", "List assertion failed");
    } else if (ISTYPE(item, obj_map_t) && (AS_MAP(item)->count == 0)) {
        LUCI_DIE("%s\n", "Map assertion failed");
    } else if (ISTYPE(item, obj_file_t) && (AS_FILE(item)->ptr)) {
        LUCI_DIE("%s\n", "File assertion failed");
    }
    return LuciNilObj;
}
示例#7
0
static void ffi_ptr_dereference(VMState *state, CallInfo *info) {
  VM_ASSERT(info->args_len == 2, "wrong arity: expected 2, got %i", info->args_len);
  Object *root = state->root;
  Object *pointer_base = state->shared->vcache.pointer_base;

  FFIObject *ffi = (FFIObject*) AS_OBJ(OBJECT_LOOKUP(root, ffi));
  Object *ffi_type = AS_OBJ(OBJECT_LOOKUP((Object*) ffi, type));

  Object *thisptr = AS_OBJ(load_arg(state->frame, info->this_arg));
  VM_ASSERT(thisptr->parent == pointer_base, "internal error");
  PointerObject *thisptr_obj = (PointerObject*) thisptr;

  Object *ffi_type_obj = obj_instance_of(OBJ_OR_NULL(load_arg(state->frame, INFO_ARGS_PTR(info)[0])), ffi_type);
  Value offs_val = load_arg(state->frame, INFO_ARGS_PTR(info)[1]);
  VM_ASSERT(IS_INT(offs_val), "offset must be integer");
  int offs = AS_INT(offs_val);
  VM_ASSERT(ffi_type_obj, "type is not a FFI type");
  char *offset_ptr = (char*) thisptr_obj->ptr + offs;
  if (ffi_type_obj == ffi->short_obj) {
    short s = *(short*) offset_ptr;
    vm_return(state, info, INT2VAL(s));
  } else if (ffi_type_obj == ffi->ushort_obj) {
    unsigned short us = *(unsigned short*) offset_ptr;
    vm_return(state, info, INT2VAL(us));
  } else if (ffi_type_obj == ffi->int_obj) {
    int i = *(int*) offset_ptr;
    vm_return(state, info, INT2VAL(i));
  } else if (ffi_type_obj == ffi->uint_obj) {
    unsigned int u = *(unsigned int*) offset_ptr;
    vm_return(state, info, INT2VAL(u));
  } else if (ffi_type_obj == ffi->int8_obj) {
    int8_t i8 = *(int8_t*) offset_ptr;
    vm_return(state, info, INT2VAL(i8));
  } else if (ffi_type_obj == ffi->uint8_obj) {
    uint8_t u8 = *(uint8_t*) offset_ptr;
    vm_return(state, info, INT2VAL(u8));
  } else if (ffi_type_obj == ffi->int32_obj) {
    int32_t i32 = *(int32_t*) offset_ptr;
    vm_return(state, info, INT2VAL(i32));
  } else if (ffi_type_obj == ffi->uint32_obj) {
    uint32_t u32 = *(uint32_t*) offset_ptr;
    vm_return(state, info, INT2VAL(u32));
  } else if (ffi_type_obj == ffi->pointer_obj) {
    void *ptr = *(void**) offset_ptr;
    vm_return(state, info, make_ffi_pointer(state, ptr));
  } else if (ffi_type_obj == ffi->char_pointer_obj) {
    char *ptr = *(char**) offset_ptr;
    vm_return(state, info, make_string_static(state, ptr));
  } else if (ffi_type_obj == ffi->long_obj) {
    long l = *(long*) offset_ptr;
    if (l < INT_MIN || l > INT_MAX) {
      VM_ASSERT(false, "value exceeds bounds of my int type");
    }
    vm_return(state, info, INT2VAL((int) l));
  } else { fprintf(stderr, "TODO\n"); abort(); }
}
示例#8
0
/**
 * Returns the next LuciObject in a container.
 *
 * @param iterator from which to compute next object
 * @returns next object in iterator's sequence or NULL if finished iterating
 */
LuciObject *iterator_next_object(LuciObject *iterator)
{
    if (!iterator || (!ISTYPE(iterator, obj_iterator_t))) {
        LUCI_DIE("%s", "Can't get next from non-iterator object\n");
    }

    LuciIteratorObj *iter = (LuciIteratorObj *)iterator;
    LuciObject *container = iter->container;

    LuciObject *next = container->type->next(container, iter->idx);
    AS_INT(iter->idx)->i += iter->step;
    return next;
}
示例#9
0
static void ffi_ptr_index_assign_fn(VMState *state, CallInfo *info) {
  VM_ASSERT(info->args_len == 2, "wrong arity: expected 2, got %i", info->args_len);
  Object *pointer_base = state->shared->vcache.pointer_base;
  Object *thisptr = OBJ_OR_NULL(load_arg(state->frame, info->this_arg));

  VM_ASSERT(thisptr && thisptr->parent == pointer_base, "invalid pointer index write on non-pointer object");
  PointerObject *thisptr_obj = (PointerObject*) thisptr;

  Object *ffi_type_obj = AS_OBJ(OBJECT_LOOKUP(thisptr, target_type));
  VM_ASSERT(ffi_type_obj, "cannot assign index on untyped pointer!");

  Value offs_val = load_arg(state->frame, INFO_ARGS_PTR(info)[0]);
  VM_ASSERT(IS_INT(offs_val), "offset must be integer");
  int offs = AS_INT(offs_val);

  Value sizeof_val = OBJECT_LOOKUP(ffi_type_obj, sizeof);
  VM_ASSERT(IS_INT(sizeof_val), "internal error: sizeof wrong type or undefined");
  int elemsize = AS_INT(sizeof_val);

  char *offset_ptr = (char*) thisptr_obj->ptr + elemsize * offs;

  bool res = ffi_pointer_write(state, ffi_type_obj, (void*) offset_ptr, load_arg(state->frame, INFO_ARGS_PTR(info)[1]));
  if (!res) return;
}
示例#10
0
/**
 * Returns a hex string representation of an integer
 *
 * @param args list of args
 * @param c number of args
 * @returns LuciStringObj representation of an integer
 */
LuciObject *luci_hex(LuciObject **args, unsigned int c)
{
    if (c < 1) {
        LUCI_DIE("%s\n", "Missing param to hex()");
    }
    LuciObject *hexint = args[0];

    if (!ISTYPE(hexint, obj_int_t)) {
        LUCI_DIE("Cannot get hex representation of an object of type %s\n",
                hexint->type->type_name);
    }

    char *s = alloc(MAX_INT_DIGITS + 2);
    snprintf(s, MAX_INT_DIGITS, "0x%lX", AS_INT(hexint)->i);
    return LuciString_new(s);
}
示例#11
0
static void ffi_ptr_add(VMState *state, CallInfo *info) {
  VM_ASSERT(info->args_len == 1, "wrong arity: expected 1, got %i", info->args_len);
  Object *pointer_base = state->shared->vcache.pointer_base;
  Object *thisptr = OBJ_OR_NULL(load_arg(state->frame, info->this_arg));

  VM_ASSERT(thisptr && thisptr->parent == pointer_base, "internal error");
  PointerObject *thisptr_obj = (PointerObject*) thisptr;
  void *ptr = (void*) thisptr_obj->ptr;

  int elemsize = 1;
  Value target_type = OBJECT_LOOKUP(thisptr, target_type);
  if (!IS_NULL(target_type)) {
    VM_ASSERT(IS_OBJ(target_type), "target type must be ffi type");

    Value sizeof_val = OBJECT_LOOKUP(AS_OBJ(target_type), sizeof);
    VM_ASSERT(IS_INT(sizeof_val), "internal error: sizeof wrong type or undefined");
    elemsize = AS_INT(sizeof_val);
  }
示例#12
0
bool ffi_pointer_write(VMState *state, Object *type, void *ptr, Value val) {
  ValueCache *vcache = &state->shared->vcache;
  Object *string_base = vcache->string_base;
  FFIObject *ffi = (FFIObject*) vcache->ffi_obj;
  if (type == ffi->float_obj) {
    if (IS_FLOAT(val)) *(float*) ptr = AS_FLOAT(val);
    else if (IS_INT(val)) *(float*) ptr = AS_INT(val);
    else {
      VM_ASSERT(false, "invalid value for float type") false;
    }
    return true;
  } else {
    Object *c_type_obj = AS_OBJ(OBJECT_LOOKUP(type, c_type));
    StringObject *c_type = (StringObject*) obj_instance_of(c_type_obj, string_base);
    assert(c_type);
    VM_ASSERT(false, "unhandled pointer write type: %s", c_type->value) false;
  }
}
示例#13
0
/**
 * Returns a boolean representation of a LuciIteratorObj
 *
 * @param o LuciIteratorObj
 * @returns true if the iterator can continue to iterate
 */
LuciObject* LuciIterator_asbool(LuciObject *o)
{
    LuciObject *res = LuciNilObj;

    LuciObject *container = AS_ITERATOR(o)->container;
    unsigned int len = 0;
    if (ISTYPE(container, obj_list_t)) {
        len = AS_LIST(container)->count;
    } else if (ISTYPE(container, obj_map_t)) {
        len = AS_LIST(container)->size;
    }

    if (AS_INT(AS_ITERATOR(o)->idx)->i < len) {
        res = LuciInt_new(true);
    } else {
        res = LuciInt_new(false);
    }
    return res;
}
示例#14
0
/**
 * Computes the sum of a range of numbers.
 *
 * @param args list of args
 * @param c number of args
 * @returns sum of numbers
 */
LuciObject * luci_sum(LuciObject **args, unsigned int c)
{
    if (c < 1) {
        LUCI_DIE("%s", "Missing parameter to sum()\n");
    }

    LuciObject *list = args[0];

    if (!list || (!ISTYPE(list, obj_list_t))) {
        LUCI_DIE("%s", "Must specify a list to calculate sum\n");
    }

    LuciObject *item;
    double sum = 0;
    unsigned int i, found_float = 0;
    for (i = 0; i < AS_LIST(list)->count; i++) {
        item = AS_LIST(list)->items[i];
        if (!item) {
            LUCI_DIE("%s", "Can't calulate sum of list containing NULL value\n");
        }

        if (ISTYPE(item, obj_int_t)) {
            sum += (double)AS_INT(item)->i;
        } else if (ISTYPE(item, obj_float_t)) {
            found_float = 1;
            sum += AS_FLOAT(item)->f;
        } else {
            LUCI_DIE("%s", "Can't calculate sum of list containing non-numeric value\n");
        }
    }

    LuciObject *ret;
    if (!found_float) {
        ret = LuciInt_new((long)sum);
    }
    else {
        ret = LuciFloat_new(sum);
    }

    return ret;
}
示例#15
0
  PointerObject *thisptr_obj = (PointerObject*) thisptr;
  void *ptr = (void*) thisptr_obj->ptr;

  int elemsize = 1;
  Value target_type = OBJECT_LOOKUP(thisptr, target_type);
  if (!IS_NULL(target_type)) {
    VM_ASSERT(IS_OBJ(target_type), "target type must be ffi type");

    Value sizeof_val = OBJECT_LOOKUP(AS_OBJ(target_type), sizeof);
    VM_ASSERT(IS_INT(sizeof_val), "internal error: sizeof wrong type or undefined");
    elemsize = AS_INT(sizeof_val);
  }

  Value offset_val = load_arg(state->frame, INFO_ARGS_PTR(info)[0]);
  VM_ASSERT(IS_INT(offset_val), "offset must be integer");
  int offset = AS_INT(offset_val);

  vm_return(state, info, make_ffi_pointer(state, (void*) ((char*)ptr + offset * elemsize)));
}

static Value make_ffi_pointer(VMState *state, void *ptr) {
  Object *ptr_obj = AS_OBJ(make_ptr(state, ptr));
  OBJECT_SET(state, ptr_obj, dereference, make_fn(state, ffi_ptr_dereference));
  OBJECT_SET(state, ptr_obj, dereference_assign, make_fn(state, ffi_ptr_dereference_assign));
  OBJECT_SET(state, ptr_obj, __add, make_fn(state, ffi_ptr_add));
  OBJECT_SET(state, ptr_obj, target_type, VNULL);
  OBJECT_SET(state, ptr_obj, __slice, make_fn(state, ffi_ptr_index_fn));
  OBJECT_SET(state, ptr_obj, __slice_assign, make_fn(state, ffi_ptr_index_assign_fn));
  return OBJ2VAL(ptr_obj);
}
示例#16
0
文件: vm.c 项目: kwiskia/chinnu
void execute_function(VM *vm) {
restart: {
    Frame *frame = vm->current;
    Closure *closure = frame->closure;
    Chunk *chunk = closure->chunk;
    StackObject *registers = frame->registers;

    while (frame->pc < chunk->numinstructions) {
        int instruction = chunk->instructions[frame->pc];

        OpCode o = GET_O(instruction);
        int a = GET_A(instruction);
        int b = GET_B(instruction);
        int c = GET_C(instruction);

        switch (o) {
            case OP_MOVE:
            {
                if (b < 256) {
                    copy_object(&registers[a], &registers[b]);
                } else {
                    copy_constant(vm, &registers[a], chunk->constants[b - 256]);
                }
            } break;

            case OP_GETUPVAR:
            {
                Upval *upval = closure->upvals[b];

                if (!upval->open) {
                    // upval is closed
                    copy_object(&registers[a], upval->data.o);
                } else {
                    // still on stack
                    copy_object(&registers[a], &upval->data.ref.frame->registers[upval->data.ref.slot]);
                }
            } break;

            case OP_SETUPVAR:
            {
                Upval *upval = closure->upvals[b];

                if (!upval->open) {
                    // upval is closed
                    copy_object(upval->data.o, &registers[a]);
                } else {
                    // still on stack
                    copy_object(&upval->data.ref.frame->registers[upval->data.ref.slot], &registers[a]);
                }
            } break;

            case OP_ADD:
            {
                // TODO - make string coercion better
                // TODO - make string type with special operators

                if (IS_STR(b) || IS_STR(c)) {
                    char *arg1 = TO_STR(b);
                    char *arg2 = TO_STR(c);

                    char *arg3 = malloc((strlen(arg1) + strlen(arg2) + 1) + sizeof *arg3);

                    strcpy(arg3, arg1);
                    strcat(arg3, arg2);

                    registers[a].value.o = make_string_ref(vm, arg3);
                    registers[a].type = OBJECT_REFERENCE; // put this after

                    free(arg1);
                    free(arg2);
                } else {
                    if (!(IS_INT(b) || IS_REAL(b)) || !(IS_INT(c) || IS_REAL(c))) {
                        fatal("Cannot add types.");
                    }

                    if (IS_INT(b) && IS_INT(c)) {
                        int arg1 = AS_INT(b);
                        int arg2 = AS_INT(c);

                        registers[a].type = OBJECT_INT;
                        registers[a].value.i = arg1 + arg2;
                    } else {
                        double arg1 = IS_INT(b) ? (double) AS_INT(b) : AS_REAL(b);
                        double arg2 = IS_INT(c) ? (double) AS_INT(c) : AS_REAL(c);

                        registers[a].type = OBJECT_REAL;
                        registers[a].value.d = arg1 + arg2;
                    }
                }
            } break;

            case OP_SUB:
            {
                if (!(IS_INT(b) || IS_REAL(b)) || !(IS_INT(c) || IS_REAL(c))) {
                    fatal("Tried to sub non-numbers.");
                }

                if (IS_INT(b) && IS_INT(c)) {
                    int arg1 = AS_INT(b);
                    int arg2 = AS_INT(c);

                    registers[a].type = OBJECT_INT;
                    registers[a].value.i = arg1 - arg2;
                } else {
                    double arg1 = IS_INT(b) ? (double) AS_INT(b) : AS_REAL(b);
                    double arg2 = IS_INT(c) ? (double) AS_INT(c) : AS_REAL(c);

                    registers[a].type = OBJECT_REAL;
                    registers[a].value.d = arg1 - arg2;
                }
            } break;

            case OP_MUL:
            {
                if (!(IS_INT(b) || IS_REAL(b)) || !(IS_INT(c) || IS_REAL(c))) {
                    fatal("Tried to mul non-numbers.");
                }

                if (IS_INT(b) && IS_INT(c)) {
                    int arg1 = AS_INT(b);
                    int arg2 = AS_INT(c);

                    registers[a].type = OBJECT_INT;
                    registers[a].value.i = arg1 * arg2;
                } else {
                    double arg1 = IS_INT(b) ? (double) AS_INT(b) : AS_REAL(b);
                    double arg2 = IS_INT(c) ? (double) AS_INT(c) : AS_REAL(c);

                    registers[a].type = OBJECT_REAL;
                    registers[a].value.d = arg1 * arg2;
                }
            } break;

            case OP_DIV:
            {
                if (!(IS_INT(b) || IS_REAL(b)) || !(IS_INT(c) || IS_REAL(c))) {
                    fatal("Tried to div non-numbers.");
                }

                if ((IS_INT(c) && AS_INT(c) == 0) || (IS_REAL(c) && AS_REAL(c) == 0)) {
                    fatal("Div by 0.");
                }

                if (IS_INT(b) && IS_INT(c)) {
                    int arg1 = AS_INT(b);
                    int arg2 = AS_INT(c);

                    registers[a].type = OBJECT_INT;
                    registers[a].value.i = arg1 / arg2;
                } else {
                    double arg1 = IS_INT(b) ? (double) AS_INT(b) : AS_REAL(b);
                    double arg2 = IS_INT(c) ? (double) AS_INT(c) : AS_REAL(c);

                    registers[a].type = OBJECT_REAL;
                    registers[a].value.d = arg1 / arg2;
                }
            } break;

            case OP_MOD:
            {
                if (!(IS_INT(b) || IS_REAL(b)) || !(IS_INT(c) || IS_REAL(c))) {
                    fatal("Tried to div non-numbers.");
                }

                if ((IS_INT(c) && AS_INT(c) == 0) || (IS_REAL(c) && AS_REAL(c) == 0)) {
                    fatal("Mod by 0.");
                }

                if (IS_INT(b) && IS_INT(c)) {
                    int arg1 = AS_INT(b);
                    int arg2 = AS_INT(c);

                    registers[a].type = OBJECT_INT;
                    registers[a].value.i = arg1 % arg2;
                } else {
                    double arg1 = IS_INT(b) ? (double) AS_INT(b) : AS_REAL(b);
                    double arg2 = IS_INT(c) ? (double) AS_INT(c) : AS_REAL(c);

                    registers[a].type = OBJECT_REAL;
                    registers[a].value.i = fmod(arg1, arg2);
                }
            } break;

            case OP_POW:
            {
                if (!(IS_INT(b) || IS_REAL(b)) || !(IS_INT(c) || IS_REAL(c))) {
                    fatal("Tried to div non-numbers.");
                }

                if (IS_INT(b) && IS_INT(c)) {
                    int arg1 = AS_INT(b);
                    int arg2 = AS_INT(c);

                    registers[a].type = OBJECT_INT;
                    registers[a].value.i = (int) pow(arg1, arg2);
                } else {
                    double arg1 = IS_INT(b) ? (double) AS_INT(b) : AS_REAL(b);
                    double arg2 = IS_INT(c) ? (double) AS_INT(c) : AS_REAL(c);

                    registers[a].type = OBJECT_REAL;
                    registers[a].value.d = pow(arg1, arg2);
                }
            } break;

            case OP_NEG:
            {
                if (IS_INT(b)) {
                    registers[a].type = OBJECT_INT;
                    registers[a].value.i = -AS_INT(b);
                } else if (IS_REAL(b)) {
                    registers[a].type = OBJECT_INT;
                    registers[a].value.i = -AS_REAL(b);
                } else {
                    fatal("Tried to negate non-numeric type.");
                }
            } break;

            case OP_NOT:
            {
                if (registers[a].type != OBJECT_BOOL) {
                    fatal("Expected boolean type, not %d.", registers[a].type);
                }

                registers[a].value.i = registers[a].value.i == 1 ? 0 : 1;
            } break;

            case OP_EQ:
            {
                if ((IS_INT(b) || IS_REAL(b)) && (IS_INT(c) || IS_REAL(c))) {
                    double arg1 = IS_INT(b) ? (double) AS_INT(b) : AS_REAL(b);
                    double arg2 = IS_INT(c) ? (double) AS_INT(c) : AS_REAL(c);

                    registers[a].type = OBJECT_BOOL;
                    registers[a].value.i = arg1 == arg2;
                } else {
                    fatal("Comparison of reference types not yet supported.");
                }
            } break;

            case OP_LT:
            {
                if (!(IS_INT(b) || IS_REAL(b)) || !(IS_INT(c) || IS_REAL(c))) {
                    fatal("Tried to compare non-numbers.");
                }

                double arg1 = IS_INT(b) ? (double) AS_INT(b) : AS_REAL(b);
                double arg2 = IS_INT(c) ? (double) AS_INT(c) : AS_REAL(c);

                registers[a].type = OBJECT_BOOL;
                registers[a].value.i = arg1 < arg2;
            } break;

            case OP_LE:
            {
                if (!(IS_INT(b) || IS_REAL(b)) || !(IS_INT(c) || IS_REAL(c))) {
                    fatal("Tried to compare non-numbers.");
                }

                double arg1 = IS_INT(b) ? (double) AS_INT(b) : AS_REAL(b);
                double arg2 = IS_INT(c) ? (double) AS_INT(c) : AS_REAL(c);

                registers[a].type = OBJECT_BOOL;
                registers[a].value.i = arg1 <= arg2;
            } break;

            case OP_CLOSURE:
            {
                Closure *child = make_closure(chunk->children[b]);

                int i;
                for (i = 0; i < chunk->children[b]->numupvars; i++) {
                    int inst = chunk->instructions[++frame->pc];

                    OpCode oc = GET_O(inst);
                    int ac = GET_A(inst);
                    int bc = GET_B(inst);
                    int cc = GET_C(inst);

                    if (oc == OP_MOVE) {
                        // first upval for this variable
                        child->upvals[ac] = make_upval(vm, bc);
                    } else {
                        // share upval
                        child->upvals[ac] = closure->upvals[bc];
                        child->upvals[ac]->refcount++;
                    }
                }

                registers[a].value.o = make_closure_ref(vm, child);
                registers[a].type = OBJECT_REFERENCE; // put this after
            } break;

            case OP_CALL:
            {
                if (registers[b].type != OBJECT_REFERENCE || registers[b].value.o->type != OBJECT_CLOSURE) {
                    fatal("Tried to call non-closure.");
                }

                // TODO - safety issue (see compile.c for notes)

                Closure *child = registers[b].value.o->value.c;
                Frame *subframe = make_frame(frame, child);

                int i;
                for (i = 0; i < child->chunk->numparams; i++) {
                    copy_object(&subframe->registers[i + 1], &registers[c + i]);
                }

                vm->current = subframe;
                goto restart;
            } break;

            case OP_RETURN:
            {
                UpvalNode *head;
                for (head = vm->open; head != NULL; ) {
                    Upval *u = head->upval;

                    if (u->data.ref.frame == frame) {
                        StackObject *o = malloc(sizeof *o);

                        if (!o) {
                            fatal("Out of memory.");
                        }

                        u->open = 0;
                        copy_object(o, &registers[u->data.ref.slot]);
                        u->data.o = o;

                        if (vm->open == head) {
                            vm->open = head->next;
                        } else {
                            head->next->prev = head->prev;
                            head->prev->next = head->next;
                        }

                        UpvalNode *temp = head;
                        head = head->next;
                        free(temp);
                    } else {
                        head = head->next;
                    }
                }

                if (vm->current->parent != NULL) {
                    Frame *p = vm->current->parent;
                    StackObject *target = &p->registers[GET_A(p->closure->chunk->instructions[p->pc++])];

                    if (b < 256) {
                        // debug
                        char *d = obj_to_str(&registers[b]);
                        printf("Return value: %s\n", d);
                        free(d);

                        copy_object(target, &registers[b]);
                    } else {
                        copy_constant(vm, target, chunk->constants[b - 256]);
                    }

                    free_frame(frame);

                    vm->current = p;
                    goto restart;
                } else {
                    // debug
                    char *d = obj_to_str(&registers[b]);
                    printf("Return value: %s\n", d);
                    free(d);

                    free_frame(frame);
                    vm->current = NULL;
                    return;
                }
            } break;

            case OP_JUMP:
                frame->pc += c ? -b : b;
                break;

            case OP_JUMP_TRUE:
            {
                if (registers[a].type != OBJECT_BOOL) {
                    fatal("Expected boolean type, not %d.", registers[a].type);
                }

                if (registers[a].value.i == 1) {
                    frame->pc += c ? -b : b;
                }
            } break;

            case OP_JUMP_FALSE:
            {
                if (registers[a].type != OBJECT_BOOL) {
                    fatal("Expected boolean type, not %d.", registers[a].type);
                }

                if (registers[a].value.i == 0) {
                    frame->pc += c ? -b : b;
                }
            } break;

            case OP_ENTER_TRY:
            {
                vm->catchframe = make_catch_frame(frame, vm->catchframe, frame->pc + b);
            } break;

            case OP_LEAVE_TRY:
            {
                CatchFrame *temp = vm->catchframe;
                vm->catchframe = vm->catchframe->parent;
                free_catch_frame(temp);
            } break;

            case OP_THROW:
            {
                // TODO - replace unwinding of stack with an exceptions
                // table per-chunk. It will have an instructions range,
                // the starting instruction of a handler, and the type of
                // exception that it may handle.

                // Exception table:
                // From    To      Target      Type
                // 0       4       5           Class TestExc1
                // 0       12      12          Class TestExc2

                // TODO - implement a way to expect an exception
                // of a given type instead of a generic catch-all.

                char *s = obj_to_str(&registers[a]);
                printf("Exception value: %s!\n", s);
                free(s);

                // TODO - this is probably wrong. Not sure how complicated
                // it will be to handle upvalues and frame destruction here,
                // so we're just doing it a shitty way for now :D [GO LAZE].

                if (!vm->catchframe) {
                    // TODO - print a stack trace [ requires debug symbols :( ]
                    fatal("Exception thrown outside of handler.");
                }

                while (vm->current != vm->catchframe->frame) {
                    // TODO - destruct frame
                    vm->current = vm->current->parent;
                }

                vm->current->pc = vm->catchframe->target;

                CatchFrame *temp = vm->catchframe;
                vm->catchframe = vm->catchframe->parent;
                free_catch_frame(temp);

                goto restart;
            } break;
        }

        frame->pc++;
    }

    fatal("VM left instruction-space.");
}
}
示例#17
0
/**
 * Creates a LuciListObj containing a range of numbers.
 *
 * @param args list of args
 * @param c number of args
 * @returns list of numbers
 */
LuciObject * luci_range(LuciObject **args, unsigned int c)
{
    long start, end, incr;
    LuciObject *first, *second, *third;

    if (c < 1) {
        LUCI_DIE("%s", "Missing parameter to range()\n");
    }

    first = args[0];
    if (!ISTYPE(first, obj_int_t)) {
        LUCI_DIE("%s", "First parameter to range must be integer\n");
    }

    if (c > 1) {
        second = args[1];
        if (!ISTYPE(second, obj_int_t)) {
            LUCI_DIE("%s", "Second parameter to range must be integer\n");
        }
        start = AS_INT(first)->i;
        end = AS_INT(second)->i;

        if (c > 2) {
            /* Ternary range(X, Y, Z) call */
            third = args[2];
            if (!ISTYPE(third, obj_int_t)) {
                LUCI_DIE("%s", "Third parameter to range must be integer\n");
            }
            incr = AS_INT(third)->i;
        }
        else {
            incr = 1;
        }
    }
    else {
        /* Basic range(X) call, increment by 1 starting from 0 */
        start = 0;
        end = AS_INT(first)->i;
        incr = 1;
    }

    /* Build a list of integers from start to end, incrementing by incr */
    LuciObject *item, *list = LuciList_new();
    long i;
    if (incr < 0) {
        if (start <= end) {
            /* return empty list if idiotically requested */
            return list;
        }

        for (i = start; i > end; i += incr) {
            item = LuciInt_new(i);
            LuciList_append(list, item);
        }
    }
    else {
        if (start >= end) {
            /* return empty list if idiotically requested */
            return list;
        }

        for (i = start; i < end; i += incr) {
            item = LuciInt_new(i);
            LuciList_append(list, item);
        }
    }

    return list;
}