void Vm::execCode(const SCodeObject &c) { Vm::pushCodeObject(c); // TODO, if coStack_ is empty, push a NIL object // This is in case the user tries to assign a value to a void function call while (!coStack_.empty()) { if (*opId_ >= static_cast<int>(vecOp_->size())) { popCodeObject(); continue; } SObject i; SObject j; Op op = (*vecOp_)[*opId_]; Opc opc = op.opc_; switch (opc) { case Opc::ADD: DEBUG("OP::ADD"); BIN_OP(+); break; case Opc::SUB: DEBUG("OP::SUB"); BIN_OP(-); break; case Opc::UNARY_SUB: DEBUG("OP::UNARY_SUB"); i = VM_POP(); j = std::make_shared<IntegerObject>(0); VM_PUSH(*j - i); break; case Opc::MOD: DEBUG("OP::MOD"); BIN_OP(% ); break; case Opc::LT: DEBUG("OP::LT"); BIN_OP(< ); break; case Opc::GT: DEBUG("OP::GT"); BIN_OP(> ); break; case Opc::LEQ: DEBUG("OP::LEQ"); BIN_OP(<= ); break; case Opc::GEQ: DEBUG("OP::GEQ"); BIN_OP(>= ); break; case Opc::EQ: DEBUG("OP::EQ"); BIN_OP(== ); break; case Opc::AND: DEBUG("OP::AND"); BIN_OP(&&); break; case Opc::OR: DEBUG("OP::OR"); BIN_OP(|| ); break; case Opc::NEQ: DEBUG("OP::NEQ"); BIN_OP(!= ); break; case Opc::MULT: DEBUG("OP::MULT"); BIN_OP(*); break; case Opc::DIV: DEBUG("OP::DIV"); BIN_OP(/ ); break; case Opc::POWER: DEBUG("OP::POWER"); j = VM_POP(); i = VM_POP(); VM_PUSH(std::make_shared<DoubleObject>(pow(i->getDouble(), j->getDouble()))); break; case Opc::WHILE: { DEBUG("OP::WHILE"); assert(op.hasArgA()); SCodeObject co = codeObject_->getChild(op.getArgA()); co->setParent(codeObject_); pushCodeObject(co); continue; } /*TODO, Better to not have BREAK and CONTINUE in the vm. */ case Opc::BREAK: DEBUG("OP::BREAK") while (codeObject_->getBlockType() != BlockType::WHILE) { popCodeObject(); } popCodeObject(); break; case Opc::CONTINUE: DEBUG("OP::CONTINUE") while (codeObject_->getBlockType() != BlockType::WHILE) { popCodeObject(); } opId_ = 0; continue; case Opc::LOAD_CONSTANT: DEBUG("OP::PUSH_CONSTANT"); assert(op.hasArgA()); i = codeObject_->getConst(op.getArgA()); VM_PUSH(i); break; case Opc::LOAD_VALUE: DEBUG("OP::LOAD_VALUE"); assert(op.hasStr()); i = codeObject_->getValue(op.getStr()); assert(i != nullptr); VM_PUSH(i); break; case Opc::STORE_VALUE: DEBUG("OP::STORE_VALUE"); assert(op.hasStr()); i = VM_POP(); codeObject_->storeValue(op.getStr(), i); break; case Opc::JMP_IF_ELSE: { DEBUG("OP::JMP_IF_ELSE"); INCR_OP(); assert(op.hasArgA()); auto v = VM_POP(); if (v->isTrue()) { SCodeObject ic = codeObject_->getChild(op.getArgA()); ic->setParent(codeObject_); pushCodeObject(ic); } else { if (op.hasArgB()) { SCodeObject ec = codeObject_->getChild(op.getArgB()); ec->setParent(codeObject_); pushCodeObject(ec); } } continue; } case Opc::INIT_INSTANCE: { auto classCo = codeObject_->getParent(); auto classO = std::make_shared<ClassObject>(classCo); VM_PUSH(classO); INCR_OP(); continue; } case Opc::CALL_METHOD: { DEBUG("OP::CALL_METHOD"); INCR_OP(); auto method = VM_POP(); auto instance = VM_POP(); Vm::callMethod(instance, method); continue; } case Opc::DOT: { DEBUG("OP::DOT"); i = VM_POP(); j = VM_POP(); Vm::getMethodProp(j, i); break; } case Opc::CALL: { DEBUG("OP::CALL"); assert(op.hasStr()); auto fnob = codeObject_->getValue(op.getStr()); assert(fnob != nullptr); INCR_OP(); Vm::callFunc(fnob); continue; } case Opc::RETURN: { // TODO, clean the stack assert(op.hasArgA()); DEBUG("OP::RETURN"); while (codeObject_->getBlockType() != BlockType::FUNCTION) { popCodeObject(); } popCodeObject(); continue; } default: assert(false && "Not Implemented Yet!"); break; } INCR_OP(); // increment the op } // end switch, end for }
SObject IntegerObject::operator/(const SObject &rhs) { return std::make_shared<DoubleObject>(getInt() / rhs->getDouble()); }