Example #1
0
void CloneObjectsTest::testCloneMethod() {
    VMSymbol* methodSymbol = GetUniverse()->NewSymbol("myMethod");
    VMMethod* orig = GetUniverse()->NewMethod(methodSymbol, 0, 0);
    VMMethod* clone = orig->Clone();

    CPPUNIT_ASSERT((intptr_t)orig != (intptr_t)clone);
    CPPUNIT_ASSERT_EQUAL_MESSAGE("class differs!!", orig->clazz, clone->clazz);
    CPPUNIT_ASSERT_EQUAL_MESSAGE("objectSize differs!!", orig->objectSize, clone->objectSize);
    CPPUNIT_ASSERT_EQUAL_MESSAGE("numberOfFields differs!!", orig->numberOfFields, clone->numberOfFields);

    CPPUNIT_ASSERT_EQUAL_MESSAGE("numberOfLocals differs!!",
            INT_VAL(load_ptr(orig->numberOfLocals)),
            INT_VAL(load_ptr(clone->numberOfLocals)));
    CPPUNIT_ASSERT_EQUAL_MESSAGE("bcLength differs!!",
            INT_VAL(load_ptr(orig->bcLength)),
            INT_VAL(load_ptr(clone->bcLength)));
    CPPUNIT_ASSERT_EQUAL_MESSAGE("maximumNumberOfStackElements differs!!",
            INT_VAL(load_ptr(orig->maximumNumberOfStackElements)),
            INT_VAL(load_ptr(clone->maximumNumberOfStackElements)));
    CPPUNIT_ASSERT_EQUAL_MESSAGE("numberOfArguments differs!!",
            INT_VAL(load_ptr(orig->numberOfArguments)),
            INT_VAL(load_ptr(clone->numberOfArguments)));
    CPPUNIT_ASSERT_EQUAL_MESSAGE("numberOfConstants differs!!",
            INT_VAL(load_ptr(orig->numberOfConstants)),
            INT_VAL(load_ptr(clone->numberOfConstants)));

    CPPUNIT_ASSERT_EQUAL_MESSAGE("GetHolder() differs!!", orig->GetHolder(), clone->GetHolder());
    CPPUNIT_ASSERT_EQUAL_MESSAGE("GetSignature() differs!!", orig->GetSignature(), clone->GetSignature());
}
Example #2
0
void _System::Exit_(Interpreter*, VMFrame* frame) {
    vm_oop_t err = frame->Pop();

    long err_no = INT_VAL(err);
    if (err_no != ERR_SUCCESS)
        frame->PrintStackTrace();
    GetUniverse()->Quit(err_no);
}
Example #3
0
// Recursive print function - updates buf_index as appropriate
// during its traversal of c
static int print(cell c) {
    switch (TYPE(c)) {
    case PAIR:
        if (TYPE(car(c)) == PAIR) {
            catf("(");
            print(car(c));
            catf(")");
        } else
            print(car(c));
        if (!cdr(c)) return 0;

        catf(" ");
        if (TYPE(cdr(c)) != PAIR) catf(". ");
        return print(cdr(c));
    case S64:
    case S32:
        return catf("%ld", INT_VAL(c));
    case SYMBOL:
        return catf("%s", SYM_STR(c));
    case NATIVE_FN:
    case NATIVE_FN_TCO:
    case NATIVE_MACRO:
        return catf("NATIVE_FUNCTION<%p>", PTR(c));
    case FFI_SYM:
        return catf("FFI_SYM<%p>", PTR(c));
    case FFI_FN:
        return catf("FFI_FN<%p>", PTR(c));
    case FFI_LIBRARY:
        return catf("FFI_LIBRARY<%p>", PTR(c));
    case MACRO:
        catf("(macro (");
        goto print_args_body;
    case FN:
        catf("(lambda (");
    print_args_body:
        print(((fn_t*)PTR(c))->args);
        catf(") ");
        print(((fn_t*)PTR(c))->body);
        return catf(")");
    case CONS:
        return catf("CONS");
    case NIL:
        return catf("()");
    default:
        return catf("UNKNOWN<%p>", c);
    }
}
Example #4
0
File: eval.c Project: kototama/kml
sexpr_t* eval(sexpr_t* sexpr, sexpr_t** env, sexpr_list_t* roots, error_t** error)
{
    if(sexpr == NULL) {
        return interp.nil_sym;
    }

    /* printf("[eval]\n"); */
    /* print_sexpr(sexpr); */
    /* printf("\n"); */
    roots = cons_to_roots_list(roots, sexpr);
    gc_collect(roots);
    
    if(ATOM(sexpr)) {
        if(SYM(sexpr)) {
            if(interp.t_sym == sexpr) {
                return interp.t_sym;
            }
            if(interp.nil_sym == sexpr) {
                return interp.nil_sym;
            }
            sexpr_t* val = assoc(sexpr, *env);
            if(val == NULL) {
                *error = mk_error("Undefined symbol", SYM_VAL(sexpr));
            }

            return val;
        }
        if(INT(sexpr)) {
            return sexpr;
        }
    } else if(ATOM(CAR(sexpr))) {
        if(SYM(CAR(sexpr))) {
            // quote
            if(interp.quote_sym == CAR(sexpr)) {
                if(CDR(sexpr) == NULL) {
                    *error = mk_error("Missing quote argument", "");
                    return NULL;
                }
                if(CDR(CDR(sexpr)) != NULL) {
                    *error = mk_error("Too many arguments for quote", "");
                    return NULL;
                }
                return CAR(CDR(sexpr));
            }
            // atom
            if(interp.atom_sym == CAR(sexpr)) {
                if(ATOM(eval(CAR(CDR(sexpr)), env, roots, error))) {
                    return interp.t_sym;
                }
                return interp.nil_sym;
            }
            // eq
            if(interp.eq_sym == CAR(sexpr)) {
                // TODO check nb args
                sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }

                roots = cons_to_roots_list(roots, e1);
                sexpr_t* e2 = eval(CAR(CDR(CDR(sexpr))), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }
                if(INT(e1) && INT(e2)) {
                    if(INT_VAL(e1) == INT_VAL(e2)) {
                        return interp.t_sym;
                    }
                    return interp.nil_sym;
                }
                if(e1 == e2) {
                    return interp.t_sym;
                }
                return interp.nil_sym;
            }
            // if
            if(interp.if_sym == CAR(sexpr)) {
                sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }
                if(e1 == interp.nil_sym) {
                    return eval(CAR(CDR(CDR(CDR(sexpr)))), env, roots, error);
                } else {
                    return eval(CAR(CDR(CDR(sexpr))), env, roots, error);
                }
            }
            // car
            if(interp.car_sym == CAR(sexpr)) {
                sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }
                if(e1 == interp.nil_sym) {
                    return interp.nil_sym;
                }
                return CAR(e1);
            }
            // cdr
            if(interp.cdr_sym == CAR(sexpr)) {
                sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error);

                if(*error != NULL) {
                    return NULL;
                }
                if(e1 == interp.nil_sym) {
                    return interp.nil_sym;
                }
                sexpr_t *res = CDR(e1);
                if(res == NULL) {
                    return interp.nil_sym;
                }
                return res;
            }
            // +
            if(interp.plus_sym == CAR(sexpr)) {
                sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }

                roots = cons_to_roots_list(roots, e1); 
                sexpr_t* e2 = eval(CAR(CDR(CDR(sexpr))), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }
                if(INT(e1) && INT(e2)) {
                    return mk_int(INT_VAL(e1) + INT_VAL(e2));
                }

                *error = mk_error("Arguments for '+' are not integers", "");
                return NULL;
            }
            // -
            if(interp.minus_sym == CAR(sexpr)) {
                sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }
                roots = cons_to_roots_list(roots, e1);
                sexpr_t* e2 = eval(CAR(CDR(CDR(sexpr))), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }
                if(INT(e1) && INT(e2)) {
                    return mk_int(INT_VAL(e1) - INT_VAL(e2));
                }

                *error = mk_error("Arguments for '-' are not integers", "");
                return NULL;
            }
            if(interp.mul_sym == CAR(sexpr)) {
                sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }

                roots = cons_to_roots_list(roots, sexpr); 
                sexpr_t* e2 = eval(CAR(CDR(CDR(sexpr))), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }
                if(INT(e1) && INT(e2)) {
                    return mk_int(INT_VAL(e1) * INT_VAL(e2));
                }

                *error = mk_error("Arguments for '*' are not integers", "");
                return NULL;
            }
            // cons
            if(interp.cons_sym == CAR(sexpr)) {
                sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }
                roots = cons_to_roots_list(roots, e1);
                sexpr_t* e2 = eval(CAR(CDR(CDR(sexpr))), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }
                return mk_cons(e1 == interp.nil_sym ? NULL : e1, e2 == interp.nil_sym ? NULL : e2);
            }
            // def
            if(interp.def_sym == CAR(sexpr)) {
                sexpr_t* arg = CAR(CDR(CDR(sexpr)));
                roots = cons_to_roots_list(roots, arg);
                sexpr_t* val = eval(arg, env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }
                
                *env = mk_cons(mk_cons(intern(SYM_VAL(CAR(CDR(sexpr)))), val), *env);
                return val;
            }
            // print
            if(interp.print_sym == CAR(sexpr)) {
                sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }
                print_sexpr(e1);
                printf("\n");

                return e1;
            }
            // fn
            if(interp.fn_sym == CAR(sexpr)) {
                return mk_fn(sexpr, *env);
            }
            // macro
            if(interp.macro_sym == CAR(sexpr)) {
                return mk_macro(sexpr);
            }
            //eval
            if(interp.eval_sym == CAR(sexpr)) {
                sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }

                roots = cons_to_roots_list(roots, e1);
                return eval(e1, env, roots, error);
            }
            // else resolves first variable

            sexpr_t* fn = eval(CAR(sexpr), env, roots, error);
            if(*error != NULL) {
                return NULL;
            }

            // eval fn
            if(FN(fn)) {
                sexpr_t* fn_code = CAR(CDR(CDR(CAR(fn))));
                sexpr_t* captured_env = CDR(fn);
                sexpr_t* arguments = eval_list(CDR(sexpr), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }

                sexpr_t* pairs = pair(CAR(CDR(CAR(fn))), arguments);
                sexpr_t* eval_env = append(pairs, captured_env);

                // append the function itself to the env, roots, for recursive calls
                eval_env = mk_cons(mk_cons(CAR(sexpr), fn), eval_env);
                
                /* printf("fn code=\n"); */
                /* print_sexpr(fn_code); */
                /* printf("\n"); */
                roots = cons_to_roots_list(roots, eval_env);
                return eval(fn_code, &eval_env, roots, error);
            }

            // eval macro
            if(MACRO(fn)) {
                sexpr_t* macro_code = CAR(CDR(CDR(CAR(fn))));
                sexpr_t* pairs = pair(CAR(CDR(CAR(fn))), CDR(sexpr));
                sexpr_t* eval_env = append(pairs, *env);

                roots = cons_to_roots_list(roots, eval_env);
                sexpr_t* transformed_code = eval(macro_code, &eval_env, roots, error);

                if(*error != NULL) {
                    return NULL;
                }

                return eval(transformed_code, env, roots, error);
            }
            
            // else primitives
            sexpr_t* arguments = eval_list(CDR(sexpr), env, roots, error);
            if(*error != NULL) {
                return NULL;
            }
            sexpr_t* to_eval = mk_cons(fn, arguments);
            return eval(to_eval, env, roots, error);
        }
    } else if(CAR(CAR(sexpr)) == interp.fn_sym) {
        // executes an anonymous function

        sexpr_t* fn = CAR(sexpr);
        sexpr_t* fn_code = CAR(CDR(CDR(fn)));
        sexpr_t* arguments = eval_list(CDR(sexpr), env, roots, error);
        if(*error != NULL) {
            return NULL;
        }
        
        sexpr_t* l = pair(CAR(CDR(fn)), arguments);
        l = append(l, *env);

        roots = cons_to_roots_list(roots, l);
        return eval(fn_code, &l, roots, error);
    }

    print_sexpr(sexpr);
    printf("\n");
    *error = mk_error("Invalid expression", "");

    return NULL;
}
Example #5
0
static void integer_number(void)
{
	uint64_t number = parse_uint64(parser.previous.start, parser.previous.length);
	emit_constant(INT_VAL((int64_t)number));
}
Example #6
0
long VMMethod::GetNumberOfBytecodes() const {
    return INT_VAL(load_ptr(bcLength));
}
Example #7
0
long VMMethod::GetMaximumNumberOfStackElements() const {
    return INT_VAL(load_ptr(maximumNumberOfStackElements));
}
Example #8
0
object call_c(int func, object proc_ad, object arg_list)
/* Call a WIN32 or Linux C function in a DLL or shared library.
   Alternatively, call a machine-code routine at a given address. */
{
    volatile unsigned long arg;  // !!!! magic var to push values on the stack
    volatile int argsize;        // !!!! number of bytes to pop

    s1_ptr arg_list_ptr, arg_size_ptr;
    object_ptr next_arg_ptr, next_size_ptr;
    object next_arg, next_size;
    int iresult, i;
    double dbl_arg, dresult;
    float flt_arg, fresult;
    unsigned long size;
    int proc_index;
    int cdecl_call;
    int (*int_proc_address)();
    unsigned return_type;
    char NameBuff[100];

    // Setup and Check for Errors

    proc_index = get_pos_int("c_proc/c_func", proc_ad);
    if ((unsigned)proc_index >= c_routine_next) {
	sprintf(TempBuff, "c_proc/c_func: bad routine number (%d)", proc_index);
	RTFatal(TempBuff);
    }

    int_proc_address = c_routine[proc_index].address;
#if defined(EWINDOWS) && !defined(EWATCOM)
    cdecl_call = c_routine[proc_index].convention;
#endif
    if (IS_ATOM(arg_list)) {
	RTFatal("c_proc/c_func: argument list must be a sequence");
    }

    arg_list_ptr = SEQ_PTR(arg_list);
    next_arg_ptr = arg_list_ptr->base + arg_list_ptr->length;

    // only look at length of arg size sequence for now
    arg_size_ptr = c_routine[proc_index].arg_size;
    next_size_ptr = arg_size_ptr->base + arg_size_ptr->length;

    return_type = c_routine[proc_index].return_size; // will be INT

    if (func && return_type == 0 || !func && return_type != 0) {
	if (c_routine[proc_index].name->length < 100)
	    MakeCString(NameBuff, MAKE_SEQ(c_routine[proc_index].name));
	else
	    NameBuff[0] = '\0';
	sprintf(TempBuff, func ? "%s does not return a value" :
				 "%s returns a value",
				 NameBuff);
	RTFatal(TempBuff);
    }

    if (arg_list_ptr->length != arg_size_ptr->length) {
	if (c_routine[proc_index].name->length < 100)
	    MakeCString(NameBuff, MAKE_SEQ(c_routine[proc_index].name));
	else
	    NameBuff[0] = '\0';
	sprintf(TempBuff, "C routine %s() needs %d argument%s, not %d",
			  NameBuff,
			  arg_size_ptr->length,
			  (arg_size_ptr->length == 1) ? "" : "s",
			  arg_list_ptr->length);
	RTFatal(TempBuff);
    }

    argsize = arg_list_ptr->length << 2;


    // Push the Arguments

    for (i = 1; i <= arg_list_ptr->length; i++) {

	next_arg = *next_arg_ptr--;
	next_size = *next_size_ptr--;

	if (IS_ATOM_INT(next_size))
	    size = INT_VAL(next_size);
	else if (IS_ATOM(next_size))
	    size = (unsigned long)DBL_PTR(next_size)->dbl;
	else
	    RTFatal("This C routine was defined using an invalid argument type");

	if (size == C_DOUBLE || size == C_FLOAT) {
	    /* push 8-byte double or 4-byte float */
	    if (IS_ATOM_INT(next_arg))
		dbl_arg = (double)next_arg;
	    else if (IS_ATOM(next_arg))
		dbl_arg = DBL_PTR(next_arg)->dbl;
	    else {
		arg = arg+argsize+9999; // 9999 = 270f hex - just a marker for asm code
		RTFatal("arguments to C routines must be atoms");
	    }

	    if (size == C_DOUBLE) {
		arg = *(1+(unsigned long *)&dbl_arg);

		push();  // push high-order half first
		argsize += 4;
		arg = *(unsigned long *)&dbl_arg;
		push(); // don't combine this with the push() below - Lcc bug
	    }
	    else {
		/* C_FLOAT */
		flt_arg = (float)dbl_arg;
		arg = *(unsigned long *)&flt_arg;
		push();
	    }
	}
	else {
	    /* push 4-byte integer */
	    if (size >= E_INTEGER) {
		if (IS_ATOM_INT(next_arg)) {
		    if (size == E_SEQUENCE)
			RTFatal("passing an integer where a sequence is required");
		}
		else {
		    if (IS_SEQUENCE(next_arg)) {
			if (size != E_SEQUENCE && size != E_OBJECT)
			    RTFatal("passing a sequence where an atom is required");
		    }
		    else {
			if (size == E_SEQUENCE)
			    RTFatal("passing an atom where a sequence is required");
		    }
		    RefDS(next_arg);
		}
		arg = next_arg;
		push();
	    }
	    else if (IS_ATOM_INT(next_arg)) {
		arg = next_arg;
		push();
	    }
	    else if (IS_ATOM(next_arg)) {
		// atoms are rounded to integers

		arg = (unsigned long)DBL_PTR(next_arg)->dbl; //correct
		// if it's a -ve f.p. number, Watcom converts it to int and
		// then to unsigned int. This is exactly what we want.
		// Works with the others too.
		push();
	    }
	    else {
		arg = arg+argsize+9999; // just a marker for asm code
		RTFatal("arguments to C routines must be atoms");
	    }
	}
    }

    // Make the Call - The C compiler thinks it's a 0-argument call

    // might be VOID C routine, but shouldn't crash

    if (return_type == C_DOUBLE) {
	// expect double to be returned from C routine
#if defined(EWINDOWS) && !defined(EWATCOM)
	if (cdecl_call) {
	    dresult = (*((double (  __cdecl *)())int_proc_address))();
	    pop();
	}
	else
#endif
	    dresult = (*((double (__stdcall *)())int_proc_address))();

#ifdef ELINUX
	pop();
#endif
	return NewDouble(dresult);
    }

    else if (return_type == C_FLOAT) {
	// expect float to be returned from C routine
#if defined(EWINDOWS) && !defined(EWATCOM)
	if (cdecl_call) {
	    fresult = (*((float (  __cdecl *)())int_proc_address))();
	    pop();
	}
	else
#endif
	    fresult = (*((float (__stdcall *)())int_proc_address))();

#ifdef ELINUX
	pop();
#endif
	return NewDouble((double)fresult);
    }

    else {
	// expect integer to be returned
#if defined(EWINDOWS) && !defined(EWATCOM)
	if (cdecl_call) {
	    iresult = (*((int (  __cdecl *)())int_proc_address))();
	    pop();
	}
	else
#endif
	    iresult = (*((int (__stdcall *)())int_proc_address))();
#ifdef ELINUX
	pop();
#endif
	if ((return_type & 0x000000FF) == 04) {
	    /* 4-byte integer - usual case */
	    // check if unsigned result is required
	    if ((return_type & C_TYPE) == 0x02000000) {
		// unsigned integer result
		if ((unsigned)iresult <= (unsigned)MAXINT) {
		    return iresult;
		}
		else
		    return NewDouble((double)(unsigned)iresult);
	    }
	    else {
		// signed integer result
		if (return_type >= E_INTEGER ||
		    (iresult >= MININT && iresult <= MAXINT)) {
		    return iresult;
		}
		else
		    return NewDouble((double)iresult);
	    }
	}
	else if (return_type == 0) {
	    return 0; /* void - procedure */
	}
	/* less common cases */
	else if (return_type == C_UCHAR) {
	    return (unsigned char)iresult;
	}
	else if (return_type == C_CHAR) {
	    return (signed char)iresult;
	}
	else if (return_type == C_USHORT) {
	    return (unsigned short)iresult;
	}
	else if (return_type == C_SHORT) {
	    return (short)iresult;
	}
	else
	    return 0; // unknown function return type
    }
}
Example #9
0
/* this function is not thread safe */
char *kek_obj_print(kek_obj_t *kek_obj) {
	static char str[1024];

	if (kek_obj == (kek_obj_t *) 0xffffffffffffffff) {
		(void) snprintf(str, 1024, "kek_obj == 0xffffffffffffffff");
		assert(0);
		goto out;
	}

	if (kek_obj == NULL) {
		(void) snprintf(str, 1024, "kek_obj == NULL");
		goto out;
	}

	/* vm_debug(DBG_STACK | DBG_STACK_FULL, "kek_obj = %p\n", kek_obj); */
	if (!IS_PTR(kek_obj)) {
		if (IS_CHAR(kek_obj)) {
			(void) snprintf(str, 1024, "char -%c-", CHAR_VAL(kek_obj));
		} else if (IS_INT(kek_obj)) {
			(void) snprintf(str, 1024, "int -%d-", INT_VAL(kek_obj));
		}
	} else {

		vm_assert(TYPE_CHECK(kek_obj->h.t), //
				"kek_obj=%p, "//
				"type=%d, "//
				"state=%d, "//
				"is_const=%d, "//
				"fromspace=%d, "//
				"tospace=%d\n",//
				kek_obj,//
				kek_obj->h.t,//
				kek_obj->h.state,//
				vm_is_const(kek_obj),//
				gc_cheney_ptr_in_from_space(kek_obj, 1),//
				gc_cheney_ptr_in_to_space(kek_obj, 1));

		switch (kek_obj->h.t) {
		case KEK_INT:
			(void) snprintf(str, 1024, "int -%d-", INT_VAL(kek_obj));
			break;
		case KEK_STR:
			(void) snprintf(str, 1024, "str -%s-",
					((kek_string_t *) kek_obj)->string);
			break;
		case KEK_ARR:
			(void) snprintf(str, 1024, "arr -%p-", (void*) kek_obj);
			break;
		case KEK_SYM:
			(void) snprintf(str, 1024, "sym -%s-",
					((kek_symbol_t *) kek_obj)->symbol);
			break;
		case KEK_NIL:
			(void) snprintf(str, 1024, "nil");
			break;
		case KEK_UDO:
			(void) snprintf(str, 1024, "udo");
			break;
		case KEK_ARR_OBJS:
			(void) snprintf(str, 1024, "arr_objs");
			break;
		case KEK_EXINFO:
			(void) snprintf(str, 1024, "exinfo");
			break;
		case KEK_EXPT:
			(void) snprintf(str, 1024, "expt");
			break;
		case KEK_FILE:
			(void) snprintf(str, 1024, "file");
			break;
		case KEK_TERM:
			(void) snprintf(str, 1024, "term");
			break;
		case KEK_CLASS:
			(void) snprintf(str, 1024, "class");
			break;
		case KEK_STACK:
			(void) snprintf(str, 1024, "stack");
			break;
		case KEK_COPIED:
			(void) snprintf(str, 1024, "COPIED!");
			break;
		default:
			assert(0);
			break;
		}
	}

	out: /* */
	return ((char *) (&str));
}
Example #10
0
static inline kek_obj_t * bc_bop(op_t o, kek_obj_t *a, kek_obj_t *b) {
	char * str_a, *str_b;
	char chr_a[2], chr_b[2];
	chr_a[1] = chr_b[1] = '\0';

	if (IS_INT(a) && IS_INT(b)) {
		kek_int_t *res = NULL;

		vm_debug(DBG_BC, " - %d, %d\n", INT_VAL(a), INT_VAL(b));

		switch (o) {
		case Plus:
			res = make_integer(INT_VAL(a) + INT_VAL(b));
			break;
		case Minus:
			res = make_integer(INT_VAL(a) - INT_VAL(b));
			break;
		case Times:
			res = make_integer(INT_VAL(a) * INT_VAL(b));
			break;
		case Divide:
			res = make_integer(INT_VAL(a) / INT_VAL(b));
			break;
		case Modulo:
			res = make_integer(INT_VAL(a) % INT_VAL(b));
			break;
		case Eq:
			res = make_integer(INT_VAL(a) == INT_VAL(b));
			break;
		case NotEq:
			res = make_integer(INT_VAL(a) != INT_VAL(b));
			break;
		case Less:
			res = make_integer(INT_VAL(a) < INT_VAL(b));
			break;
		case Greater:
			res = make_integer(INT_VAL(a) > INT_VAL(b));
			break;
		case LessOrEq:
			res = make_integer(INT_VAL(a) <= INT_VAL(b));
			break;
		case GreaterOrEq:
			res = make_integer(INT_VAL(a) >= INT_VAL(b));
			break;
		case LogOr:
			res = make_integer(INT_VAL(a) || INT_VAL(b));
			break;
		case LogAnd:
			res = make_integer(INT_VAL(a) && INT_VAL(b));
			break;
		case BitOr:
			res = make_integer(INT_VAL(a) | INT_VAL(b));
			break;
		case BitAnd:
			res = make_integer(INT_VAL(a) & INT_VAL(b));
			break;
		case Xor:
			res = make_integer(INT_VAL(a) ^ INT_VAL(b));
			break;
		case Lsh:
			res = make_integer(INT_VAL(a) << INT_VAL(b));
			break;
		case Rsh:
			res = make_integer(INT_VAL(a) >> INT_VAL(b));
			break;
		default:
			vm_error("bc_bop: unsupported bop %d on integers\n", o);
			break;
		}
		vm_debug(DBG_BC, " = %d\n", INT_VAL((kek_obj_t* )res));
		return (kek_obj_t*) res;
	} else if (( // This is intentionally complicated :D