Objects Initial
This commit is contained in:
parent
0f639ba3b1
commit
94057d2a66
76 changed files with 7895 additions and 17 deletions
40
Objects/private/interpreter/callstack.cpp
Normal file
40
Objects/private/interpreter/callstack.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
|
||||
#include "NewPlacement.hpp"
|
||||
|
||||
#include "interpreter/callstack.h"
|
||||
|
||||
#include "interpreter/bytecode.h"
|
||||
#include "primitives/methodobject.h"
|
||||
|
||||
using namespace obj;
|
||||
|
||||
void CallStack::enter(const CallStack::CallFrame& frame) {
|
||||
if (mStack.size()) {
|
||||
auto& last_frame = mStack.last();
|
||||
last_frame.mIp = last_frame.mMethod->mScript->mBytecode.mInstructionIdx;
|
||||
}
|
||||
|
||||
frame.mMethod->mScript->mBytecode.mArgumentsLoaded = 0;
|
||||
frame.mMethod->mScript->mBytecode.mInstructionIdx = 0;
|
||||
obj::NDO->refinc(frame.mMethod);
|
||||
mStack.append(frame);
|
||||
}
|
||||
|
||||
void CallStack::leave() {
|
||||
auto frame = mStack.last();
|
||||
obj::NDO->destroy(frame.mMethod);
|
||||
mStack.pop();
|
||||
|
||||
if (mStack.size()) {
|
||||
auto& last_frame = mStack.last();
|
||||
last_frame.mMethod->mScript->mBytecode.mInstructionIdx = last_frame.mIp;
|
||||
}
|
||||
}
|
||||
|
||||
ByteCode* CallStack::getBytecode() {
|
||||
return &mStack.last().mMethod->mScript->mBytecode;
|
||||
}
|
||||
|
||||
tp::halni CallStack::len() const {
|
||||
return mStack.size();
|
||||
}
|
||||
573
Objects/private/interpreter/interpreter.cpp
Normal file
573
Objects/private/interpreter/interpreter.cpp
Normal file
|
|
@ -0,0 +1,573 @@
|
|||
|
||||
#include "NewPlacement.hpp"
|
||||
|
||||
#include "interpreter/interpreter.h"
|
||||
|
||||
#include "primitives/primitives.h"
|
||||
|
||||
#include "Logging.hpp"
|
||||
|
||||
#include "Timing.hpp"
|
||||
|
||||
using namespace obj;
|
||||
|
||||
inline tp::uint1 read_byte(ByteCode* bytecode) {
|
||||
auto out = (tp::uint1)bytecode->mInstructions[bytecode->mInstructionIdx];
|
||||
bytecode->mInstructionIdx++;
|
||||
return out;
|
||||
}
|
||||
|
||||
// exeption for opcodes
|
||||
// reads 2 bytes from instructions in order to load constant onto operands stack
|
||||
tp::uint2 loadConstDataIdx(ByteCode* bytecode) {
|
||||
tp::uint2 out = 0;
|
||||
out |= ((tp::uint2) read_byte(bytecode));
|
||||
out |= ((tp::uint2) read_byte(bytecode) << 8);
|
||||
return out;
|
||||
}
|
||||
|
||||
// exeption for opcodes
|
||||
// reads 2 bytes from instructions in order to load constant onto operands stack
|
||||
void skip_param(ByteCode* bytecode) {
|
||||
bytecode->mInstructionIdx += 2;
|
||||
}
|
||||
|
||||
tp::uint2 param(ByteCode* bytecode) {
|
||||
return loadConstDataIdx(bytecode);
|
||||
}
|
||||
|
||||
void Interpreter::exec(obj::MethodObject* method, obj::ClassObject* self, obj::DictObject* globals, tp::init_list<GlobalDef> globals2) {
|
||||
if (!method->mScript->mBytecode.mInstructions.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mCallStack.enter({ NULL, method, 0 });
|
||||
mCallStack.mStack.last().mSelf = self;
|
||||
|
||||
stepBytecodeIn();
|
||||
|
||||
if (globals) {
|
||||
for (auto glb : globals->getItems()) {
|
||||
mScopeStack.addLocal(glb->val, glb->key);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto global_def : globals2) {
|
||||
mScopeStack.addLocal(global_def.obj, global_def.id);
|
||||
}
|
||||
}
|
||||
|
||||
bool Interpreter::finished() {
|
||||
return !mCallStack.len();
|
||||
}
|
||||
|
||||
void Interpreter::stepBytecode() {
|
||||
tp::halni call_depth = mCallStack.len();
|
||||
do {
|
||||
stepBytecodeIn();
|
||||
if (finished()) {
|
||||
return;
|
||||
}
|
||||
} while (call_depth != mCallStack.len());
|
||||
}
|
||||
|
||||
void Interpreter::stepBytecodeOut() {
|
||||
if (finished()) {
|
||||
return;
|
||||
}
|
||||
|
||||
tp::halni call_depth = mCallStack.len();
|
||||
if (!call_depth) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
stepBytecodeIn();
|
||||
if (finished()) {
|
||||
return;
|
||||
}
|
||||
} while (call_depth - 1 != mCallStack.len());
|
||||
}
|
||||
|
||||
void Interpreter::stepBytecodeIn() {
|
||||
using namespace obj;
|
||||
using namespace tp;
|
||||
|
||||
DEBUG_BREAK(finished());
|
||||
|
||||
auto bytecode = mCallStack.getBytecode();
|
||||
|
||||
if (bytecode->mInstructionIdx >= (tp::ualni) bytecode->mInstructions.size()) {
|
||||
// just return
|
||||
if (mScopeStack.mIdx) {
|
||||
mScopeStack.leaveScope();
|
||||
}
|
||||
|
||||
mCallStack.leave();
|
||||
|
||||
if (mCallStack.len()) {
|
||||
mOperandsStack.push(NDO_NULL_REF);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto opcode = bytecode->mInstructions[bytecode->mInstructionIdx];
|
||||
bytecode->mInstructionIdx++;
|
||||
|
||||
switch (opcode) {
|
||||
|
||||
case OpCode::NONE: {
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::HALT: {
|
||||
while (true) {
|
||||
tp::sleep(3);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::TERMINATE: {
|
||||
//tp::terminate(0);
|
||||
}
|
||||
|
||||
case OpCode::IGNORE: {
|
||||
NDO->destroy(mOperandsStack.getOperand());
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::LOAD_CONST: {
|
||||
auto idx = loadConstDataIdx(bytecode);
|
||||
auto const_obj = bytecode->mConstants[idx];
|
||||
mOperandsStack.push(const_obj);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::LOAD_LOCAL: {
|
||||
auto idx = loadConstDataIdx(bytecode);
|
||||
auto const_obj = bytecode->mConstants[idx];
|
||||
NDO_CASTV(StringObject, const_obj, local_id);
|
||||
ASSERT(local_id && "Invalid Object Type");
|
||||
auto local = mScopeStack.getLocal(local_id->val);
|
||||
mOperandsStack.push(local);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::SCOPE_IN: {
|
||||
mScopeStack.enterScope(true);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::JUMP: {
|
||||
bytecode->mInstructionIdx += param(bytecode);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::JUMP_IF: {
|
||||
auto cond = mOperandsStack.getOperand();
|
||||
if (NDO->toBool(cond)) {
|
||||
bytecode->mInstructionIdx += param(bytecode);
|
||||
} else {
|
||||
skip_param(bytecode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::JUMP_IF_NOT: {
|
||||
auto cond = mOperandsStack.getOperand();
|
||||
if (!NDO->toBool(cond)) {
|
||||
bytecode->mInstructionIdx += param(bytecode);
|
||||
} else {
|
||||
skip_param(bytecode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::JUMP_R: {
|
||||
bytecode->mInstructionIdx -= param(bytecode);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::JUMP_IF_R: {
|
||||
auto cond = mOperandsStack.getOperand();
|
||||
if (NDO->toBool(cond)) {
|
||||
bytecode->mInstructionIdx -= param(bytecode);
|
||||
} else {
|
||||
skip_param(bytecode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::JUMP_IF_NOT_R: {
|
||||
auto cond = mOperandsStack.getOperand();
|
||||
if (!NDO->toBool(cond)) {
|
||||
bytecode->mInstructionIdx -= param(bytecode);
|
||||
} else {
|
||||
skip_param(bytecode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::SCOPE_OUT: {
|
||||
mScopeStack.leaveScope();
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::PRINT: {
|
||||
auto obj = mOperandsStack.getOperand();
|
||||
if (obj->type->convesions && obj->type->convesions->to_string) {
|
||||
auto str = NDO->toString(obj);
|
||||
gLogger->write(str, true);
|
||||
} else {
|
||||
gLogger->write(String(obj->type->name), true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::OBJ_CREATE_LOCAL: {
|
||||
auto type = mOperandsStack.getOperand<StringObject>();
|
||||
auto id = mOperandsStack.getOperand<StringObject>();
|
||||
mScopeStack.addLocal(NDO->create(type->val), id->val);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::DEF_LOCAL: {
|
||||
auto id = mOperandsStack.getOperand<StringObject>();
|
||||
auto obj = mOperandsStack.getOperand();
|
||||
mScopeStack.addLocal(obj, id->val);
|
||||
NDO->refinc(obj);
|
||||
//mScopeStack.popTemp();
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::OBJ_CREATE: {
|
||||
auto type = mOperandsStack.getOperand<StringObject>();
|
||||
Object* new_obj = NULL;
|
||||
|
||||
// basic types
|
||||
auto idx = NDO->types.presents(type->val);
|
||||
if (idx) {
|
||||
auto new_obj = NDO->create(type->val);
|
||||
|
||||
mOperandsStack.push(new_obj);
|
||||
mScopeStack.addTemp(new_obj);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// class creation
|
||||
auto local_class = mScopeStack.getLocal(type->val);
|
||||
NDO_CASTV(MethodObject, local_class, method);
|
||||
ASSERT(method);
|
||||
|
||||
// class is a function - execute it as a constructor
|
||||
|
||||
// PUSH_ARGS protocol
|
||||
tp::uint2 len = 0;
|
||||
mOperandsStack.push((Object*)len);
|
||||
mOperandsStack.push(NULL);
|
||||
|
||||
// CALL protocol
|
||||
mScopeStack.enterScope(false);
|
||||
mCallStack.enter({ NULL, method, 0 });
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::CLASS_CONSTRUCT: {
|
||||
auto class_obj = (ClassObject*)NDO->create("class");
|
||||
|
||||
for (auto local : mScopeStack.getCurrentScope()->mLocals) {
|
||||
class_obj->addMember(local->val, local->key);
|
||||
}
|
||||
|
||||
mOperandsStack.push(class_obj);
|
||||
mScopeStack.addTempReturn(class_obj);
|
||||
|
||||
mScopeStack.leaveScope();
|
||||
mCallStack.leave();
|
||||
return;
|
||||
}
|
||||
|
||||
case OpCode::RETURN: {
|
||||
//mScopeStack.addTempReturn(NDO_NULL_REF);
|
||||
mScopeStack.leaveScope();
|
||||
mCallStack.leave();
|
||||
if (mCallStack.len()) {
|
||||
mOperandsStack.push(NDO_NULL_REF);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::PUSH_ARGS: {
|
||||
|
||||
// Layout of OperandsStack:
|
||||
// ....
|
||||
// +1) length : to chech number of args
|
||||
// +2) NULL : stop saving args
|
||||
// +3) object1
|
||||
// +4) object2
|
||||
// ...
|
||||
|
||||
tp::uint2 len = read_byte(bytecode);
|
||||
mOperandsStack.push((Object*) len);
|
||||
mOperandsStack.push(NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::SAVE_ARGS: {
|
||||
tp::uint2 args_len = read_byte(bytecode);
|
||||
auto argument = mOperandsStack.getOperand();
|
||||
|
||||
while (argument) {
|
||||
NDO->refinc(argument);
|
||||
|
||||
auto argument_id = bytecode->mConstants[loadConstDataIdx(bytecode)];
|
||||
NDO_CASTV(StringObject, argument_id, id);
|
||||
DEBUG_ASSERT(id);
|
||||
mScopeStack.addLocal(argument, id->val);
|
||||
bytecode->mArgumentsLoaded++;
|
||||
argument = mOperandsStack.getOperand();
|
||||
}
|
||||
|
||||
tp::uint2 saved_len = tp::uint2 (tp::ualni (mOperandsStack.getOperand()));
|
||||
ASSERT(args_len == saved_len && "invalid number of arguments passefd");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::RETURN_OBJ: {
|
||||
if (mCallStack.len() > 1) {
|
||||
auto ret = mOperandsStack.getOperand();
|
||||
mOperandsStack.push(ret);
|
||||
mScopeStack.addTempReturn(ret);
|
||||
}
|
||||
|
||||
mScopeStack.leaveScope();
|
||||
mCallStack.leave();
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::CALL: {
|
||||
auto obj = mOperandsStack.getOperand();
|
||||
|
||||
if (!mIsTypeMethod) {
|
||||
NDO_CASTV(MethodObject, obj, method);
|
||||
|
||||
mScopeStack.enterScope(false);
|
||||
mCallStack.enter({ NULL, method, 0 });
|
||||
|
||||
// push self
|
||||
mCallStack.mStack.last().mSelf = mLastParent;
|
||||
break;
|
||||
}
|
||||
|
||||
(*mTypeMethod)(this);
|
||||
mIsTypeMethod = false;
|
||||
mTypeMethod = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::OBJ_ADD: {
|
||||
auto left = mOperandsStack.getOperand();
|
||||
auto right = mOperandsStack.getOperand();
|
||||
|
||||
ASSERT(left->type == right->type && "addition of different types is not implemented");
|
||||
ASSERT(left->type->ariphmetics && left->type->ariphmetics->add && "cannot add object of this type");
|
||||
|
||||
auto res = NDO->instatiate(left);
|
||||
res->type->ariphmetics->add(res, right);
|
||||
|
||||
mScopeStack.addTemp(res);
|
||||
mOperandsStack.push(res);
|
||||
break;
|
||||
}
|
||||
case OpCode::OBJ_SUB: {
|
||||
auto left = mOperandsStack.getOperand();
|
||||
auto right = mOperandsStack.getOperand();
|
||||
|
||||
ASSERT(left->type == right->type && "addition of different types is not implemented");
|
||||
ASSERT(left->type->ariphmetics && left->type->ariphmetics->add && "cannot add object of this type");
|
||||
|
||||
auto res = NDO->instatiate(left);
|
||||
res->type->ariphmetics->sub(res, right);
|
||||
|
||||
mScopeStack.addTemp(res);
|
||||
mOperandsStack.push(res);
|
||||
break;
|
||||
}
|
||||
case OpCode::OBJ_MUL: {
|
||||
auto left = mOperandsStack.getOperand();
|
||||
auto right = mOperandsStack.getOperand();
|
||||
|
||||
ASSERT(left->type == right->type && "addition of different types is not implemented");
|
||||
ASSERT(left->type->ariphmetics && left->type->ariphmetics->add && "cannot add object of this type");
|
||||
|
||||
auto res = NDO->instatiate(left);
|
||||
res->type->ariphmetics->mul(res, right);
|
||||
|
||||
mScopeStack.addTemp(res);
|
||||
mOperandsStack.push(res);
|
||||
break;
|
||||
}
|
||||
case OpCode::OBJ_DIV: {
|
||||
auto left = mOperandsStack.getOperand();
|
||||
auto right = mOperandsStack.getOperand();
|
||||
|
||||
ASSERT(left->type == right->type && "addition of different types is not implemented");
|
||||
ASSERT(left->type->ariphmetics && left->type->ariphmetics->add && "cannot add object of this type");
|
||||
|
||||
auto res = NDO->instatiate(left);
|
||||
res->type->ariphmetics->div(res, right);
|
||||
|
||||
mScopeStack.addTemp(res);
|
||||
mOperandsStack.push(res);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::OBJ_COPY: {
|
||||
auto left = mOperandsStack.getOperand();
|
||||
auto right = mOperandsStack.getOperand();
|
||||
NDO->copy(left, right);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::CHILD: {
|
||||
auto child_id = mOperandsStack.getOperand<StringObject>();
|
||||
auto parent = mOperandsStack.getOperand();
|
||||
bool is_method = read_byte(bytecode);
|
||||
|
||||
Object* child = NULL;
|
||||
TypeMethods::LookupKey tm_key;
|
||||
|
||||
if (is_method) {
|
||||
tm_key = TypeMethods::presents(parent->type, child_id->val);
|
||||
}
|
||||
|
||||
if (tm_key) {
|
||||
mTypeMethod = TypeMethods::getMethod(parent->type, tm_key);
|
||||
mIsTypeMethod = true;
|
||||
|
||||
} else {
|
||||
NDO_CASTV(ClassObject, parent, class_obj);
|
||||
ASSERT(class_obj && "not a class object");
|
||||
auto idx = class_obj->members->presents(child_id->val);
|
||||
ASSERT(idx && "No child with such id");
|
||||
child = class_obj->members->getSlotVal(idx);
|
||||
}
|
||||
|
||||
//mScopeStack.addTemp(obj);
|
||||
mOperandsStack.push(child);
|
||||
mLastParent = parent;
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::SELF: {
|
||||
//mScopeStack.addTemp(obj);
|
||||
ASSERT(mCallStack.mStack.last().mSelf);
|
||||
mOperandsStack.push(mCallStack.mStack.last().mSelf);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::OBJ_LOAD: {
|
||||
auto path = mOperandsStack.getOperand<StringObject>();
|
||||
auto obj = NDO->load(path->val);
|
||||
mScopeStack.addTemp(obj);
|
||||
mOperandsStack.push(obj);
|
||||
break;
|
||||
}
|
||||
case OpCode::OBJ_SAVE: {
|
||||
auto path = mOperandsStack.getOperand<StringObject>();
|
||||
auto target = mOperandsStack.getOperand();
|
||||
NDO->save(target, path->val);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::AND: {
|
||||
auto left = NDO->toBool(mOperandsStack.getOperand());
|
||||
auto right = NDO->toBool(mOperandsStack.getOperand());
|
||||
auto out = BoolObject::create(left && right);
|
||||
mScopeStack.addTemp(out);
|
||||
mOperandsStack.push(out);
|
||||
break;
|
||||
}
|
||||
case OpCode::OR: {
|
||||
auto left = NDO->toBool(mOperandsStack.getOperand());
|
||||
auto right = NDO->toBool(mOperandsStack.getOperand());
|
||||
auto out = BoolObject::create(left || right);
|
||||
mScopeStack.addTemp(out);
|
||||
mOperandsStack.push(out);
|
||||
break;
|
||||
}
|
||||
case OpCode::NOT: {
|
||||
auto inv = NDO->toBool(mOperandsStack.getOperand());
|
||||
auto out = BoolObject::create(!inv);
|
||||
mScopeStack.addTemp(out);
|
||||
mOperandsStack.push(out);
|
||||
break;
|
||||
}
|
||||
case OpCode::NOT_EQUAL: {
|
||||
auto left = mOperandsStack.getOperand();
|
||||
auto right = mOperandsStack.getOperand();
|
||||
auto out = BoolObject::create(!NDO->compare(left, right));
|
||||
mScopeStack.addTemp(out);
|
||||
mOperandsStack.push(out);
|
||||
break;
|
||||
}
|
||||
case OpCode::EQUAL: {
|
||||
auto left = mOperandsStack.getOperand();
|
||||
auto right = mOperandsStack.getOperand();
|
||||
auto out = BoolObject::create(NDO->compare(left, right));
|
||||
mScopeStack.addTemp(out);
|
||||
mOperandsStack.push(out);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::MORE: {
|
||||
auto left = NDO->toFloat(mOperandsStack.getOperand());
|
||||
auto right = NDO->toFloat(mOperandsStack.getOperand());
|
||||
auto out = BoolObject::create(left > right);
|
||||
mScopeStack.addTemp(out);
|
||||
mOperandsStack.push(out);
|
||||
break;
|
||||
}
|
||||
case OpCode::LESS: {
|
||||
auto left = NDO->toFloat(mOperandsStack.getOperand());
|
||||
auto right = NDO->toFloat(mOperandsStack.getOperand());
|
||||
auto out = BoolObject::create(left < right);
|
||||
mScopeStack.addTemp(out);
|
||||
mOperandsStack.push(out);
|
||||
break;
|
||||
}
|
||||
case OpCode::EQUAL_OR_MORE: {
|
||||
auto left = NDO->toFloat(mOperandsStack.getOperand());
|
||||
auto right = NDO->toFloat(mOperandsStack.getOperand());
|
||||
auto out = BoolObject::create(left >= right);
|
||||
mScopeStack.addTemp(out);
|
||||
mOperandsStack.push(out);
|
||||
break;
|
||||
}
|
||||
case OpCode::EQUAL_OR_LESS: {
|
||||
auto left = NDO->toFloat(mOperandsStack.getOperand());
|
||||
auto right = NDO->toFloat(mOperandsStack.getOperand());
|
||||
auto out = BoolObject::create(left <= right);
|
||||
mScopeStack.addTemp(out);
|
||||
mOperandsStack.push(out);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
ASSERT("Invalid OpCode");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Interpreter::execAll(obj::MethodObject* method, obj::ClassObject* self, obj::DictObject* globals, tp::init_list<GlobalDef> globals2) {
|
||||
if (!method->mScript->mBytecode.mInstructions.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
exec(method, self, globals, globals2);
|
||||
while (!finished()) {
|
||||
stepBytecodeIn();
|
||||
}
|
||||
}
|
||||
384
Objects/private/interpreter/opcodes.cpp
Normal file
384
Objects/private/interpreter/opcodes.cpp
Normal file
|
|
@ -0,0 +1,384 @@
|
|||
|
||||
#include "Utils.hpp"
|
||||
|
||||
#include "interpreter/opcodes.h"
|
||||
|
||||
namespace obj {
|
||||
OpcodeInfos gOpcodeInfos;
|
||||
};
|
||||
|
||||
using namespace obj;
|
||||
|
||||
#define CONST_IDX_BYTES 2
|
||||
|
||||
#define OP(opcode, name, desc, ops, params) \
|
||||
add(opcode, { #name, #desc, ops, params } );
|
||||
|
||||
OpcodeInfos::OperandsInfo::OperandsInfo() {}
|
||||
OpcodeInfos::OperandsInfo::OperandsInfo(tp::init_list<Operand> list) {
|
||||
DEBUG_ASSERT(MAX_OPERANDS >= list.size());
|
||||
for (auto item : list) {
|
||||
buff[len] = item;
|
||||
len++;
|
||||
}
|
||||
}
|
||||
|
||||
OpcodeInfos::ParamsInfo::ParamsInfo() {}
|
||||
OpcodeInfos::ParamsInfo::ParamsInfo(tp::init_list<Param> list) {
|
||||
DEBUG_ASSERT(MAX_PARAMS >= list.size());
|
||||
for (auto item : list) {
|
||||
buff[len] = item;
|
||||
len++;
|
||||
}
|
||||
}
|
||||
|
||||
tp::uint1 OpcodeInfos::OpInfo::opsize() {
|
||||
tp::uint1 out = 1;
|
||||
for (auto i = 0; i < params.len; i++) {
|
||||
out += params.buff[i].bytes;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
OpcodeInfos::OpcodeInfos() {
|
||||
|
||||
add(OpCode::NONE, { "NONE", "Does Nothing" });
|
||||
add(OpCode::HALT, { "HALT", "Halts for 3 sec" });
|
||||
add(OpCode::TERMINATE, { "TERMINATE", "Terminates the process" });
|
||||
add(OpCode::DEF_LOCAL, {
|
||||
.name = "DEF LOCAL",
|
||||
.desc = "Adds object to the locals",
|
||||
.operands = {
|
||||
{ "str", "local id" },
|
||||
{ "any", "object to be local" }
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::LOAD_CONST, {
|
||||
.name = "LOAD CONST",
|
||||
.desc = "Loads const object from the const pool",
|
||||
.params = {
|
||||
{ "const obj idx", CONST_IDX_BYTES },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::LOAD_LOCAL, {
|
||||
.name = "LOAD LOCAL",
|
||||
.desc = "Loads local object from the locals",
|
||||
.params = {
|
||||
{ "idx of const StringObject - represents name id", CONST_IDX_BYTES },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::IGNORE, {
|
||||
.name = "IGNORE",
|
||||
.desc = "Ignores returned object by destroying it",
|
||||
}
|
||||
);
|
||||
add(OpCode::SCOPE_IN, {
|
||||
.name = "SCOPE IN",
|
||||
.desc = "Enters new scope",
|
||||
}
|
||||
);
|
||||
add(OpCode::SCOPE_OUT, {
|
||||
.name = "SCOPE OUT",
|
||||
.desc = "Leaves current scope",
|
||||
}
|
||||
);
|
||||
add(OpCode::CALL, {
|
||||
.name = "CALL",
|
||||
.desc = "Leaves current scope",
|
||||
.operands = {
|
||||
{ "method", "method object" },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::RETURN_OBJ, {
|
||||
.name = "RETURN OBJ",
|
||||
.desc = "Returns Operand",
|
||||
.operands = {
|
||||
{ "any", "object to be returned" },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::RETURN, {
|
||||
.name = "RETURN",
|
||||
.desc = "Returns Null Object",
|
||||
}
|
||||
);
|
||||
add(OpCode::CHILD, {
|
||||
.name = "CHILD",
|
||||
.desc = "Retrieves child from class",
|
||||
.operands = {
|
||||
{ "str", "child id" },
|
||||
{ "class", "parent class" },
|
||||
},
|
||||
.params = {
|
||||
{ "is method ?", 1 }
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::PUSH_ARGS, {
|
||||
.name = "PUSH ARGS",
|
||||
.desc = "Pushes Separator on the OperandsStack",
|
||||
.params = {
|
||||
{ "length to chech number of args", 1 }
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::SAVE_ARGS, {
|
||||
.name = "SAVE ARGS",
|
||||
.desc = "Pushes operands to locals",
|
||||
.params = {
|
||||
{ "number of arguments in function defenition", 1 }
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::OBJ_CREATE_LOCAL, {
|
||||
.name = "CREATE LOCAL OBJ",
|
||||
.desc = "creates object of given type and adds it to the locals",
|
||||
.operands = {
|
||||
{ "str", "types" },
|
||||
{ "str", "name id" },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::OBJ_CREATE, {
|
||||
.name = "CREATE OBJ",
|
||||
.desc = "creates object of given type",
|
||||
.operands = {
|
||||
{ "str", "types" },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::OBJ_COPY, {
|
||||
.name = "COPY",
|
||||
.desc = "Copies objects",
|
||||
.operands = {
|
||||
{ "any", "self" },
|
||||
{ "any", "target" },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::OBJ_SAVE, {
|
||||
.name = "SAVE",
|
||||
.desc = "Saves object to a file",
|
||||
.operands = {
|
||||
{ "str", "path" },
|
||||
{ "any", "self" },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::OBJ_LOAD, {
|
||||
.name = "LOAD",
|
||||
.desc = "loads object from a file",
|
||||
.operands = {
|
||||
{ "str", "path" },
|
||||
{ "any", "self" },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::OBJ_ADD, {
|
||||
.name = "ADD",
|
||||
.desc = "Adds objects of the same type that supports ariphmetics",
|
||||
.operands = {
|
||||
{ "any", "left" },
|
||||
{ "any", "right" },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::OBJ_SUB, {
|
||||
.name = "SUB",
|
||||
.desc = "Subtruts objects of the same type that supports ariphmetics",
|
||||
.operands = {
|
||||
{ "any", "left" },
|
||||
{ "any", "right" },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::OBJ_MUL, {
|
||||
.name = "MUL",
|
||||
.desc = "Multiplies objects of the same type that supports ariphmetics",
|
||||
.operands = {
|
||||
{ "any", "left" },
|
||||
{ "any", "right" },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::OBJ_DIV, {
|
||||
.name = "DIV",
|
||||
.desc = "Divides objects of the same type that supports ariphmetics",
|
||||
.operands = {
|
||||
{ "any", "left" },
|
||||
{ "any", "right" },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::AND, {
|
||||
.name = "AND",
|
||||
.desc = "Logical AND of objects of the same type that supports boolean ariphmetics",
|
||||
.operands = {
|
||||
{ "any", "left" },
|
||||
{ "any", "right" },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::OR, {
|
||||
.name = "OR",
|
||||
.desc = "Logical OR of objects of the same type that supports boolean ariphmetics",
|
||||
.operands = {
|
||||
{ "any", "left" },
|
||||
{ "any", "right" },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::EQUAL, {
|
||||
.name = "EQUAL",
|
||||
.desc = "Compares objects",
|
||||
.operands = {
|
||||
{ "any", "left" },
|
||||
{ "any", "right" },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::NOT_EQUAL, {
|
||||
.name = "NOT EQUAL",
|
||||
.desc = "Compares objects and inverts the resault",
|
||||
.operands = {
|
||||
{ "any", "left" },
|
||||
{ "any", "right" },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::MORE, {
|
||||
.name = "MORE",
|
||||
.desc = " > ",
|
||||
.operands = {
|
||||
{ "any", "left" },
|
||||
{ "any", "right" },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::LESS, {
|
||||
.name = "LESS",
|
||||
.desc = " < ",
|
||||
.operands = {
|
||||
{ "any", "left" },
|
||||
{ "any", "right" },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::EQUAL_OR_MORE, {
|
||||
.name = "GRATER OR EQUAL",
|
||||
.desc = " >= ",
|
||||
.operands = {
|
||||
{ "any", "left" },
|
||||
{ "any", "right" },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::EQUAL_OR_LESS, {
|
||||
.name = "LESS OR EQUAL",
|
||||
.desc = " <= ",
|
||||
.operands = {
|
||||
{ "any", "left" },
|
||||
{ "any", "right" },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::NOT, {
|
||||
.name = "NOT",
|
||||
.desc = "Inverts the object bolean representation",
|
||||
.operands = {
|
||||
{ "any", "self" },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::JUMP, {
|
||||
.name = "JUMP",
|
||||
.desc = "Offsets the instruction pointer",
|
||||
.params = {
|
||||
{ "ip offset unsigned", 2 },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::JUMP_R, {
|
||||
.name = "JUMP R",
|
||||
.desc = "Offsets the instruction pointer in reversed direction",
|
||||
.params = {
|
||||
{ "ip offset unsigned", 2 },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::JUMP_IF, {
|
||||
.name = "JUMP IF",
|
||||
.desc = "Offsets the instruction pointer if condition is met",
|
||||
.operands = {
|
||||
{ "any", "condition object" },
|
||||
},
|
||||
.params = {
|
||||
{ "ip offset unsigned", 2 },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::JUMP_IF_R, {
|
||||
.name = "JUMP IF R",
|
||||
.desc = "Offsets the instruction pointer in reversed direction if condition is met",
|
||||
.operands = {
|
||||
{ "any", "condition object" },
|
||||
},
|
||||
.params = {
|
||||
{ "ip offset unsigned", 2 },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::JUMP_IF_NOT, {
|
||||
.name = "JUMP IF R",
|
||||
.desc = "Offsets the instruction pointer if condition is NOT met",
|
||||
.operands = {
|
||||
{ "any", "condition object" },
|
||||
},
|
||||
.params = {
|
||||
{ "ip offset unsigned", 2 },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::JUMP_IF_NOT_R, {
|
||||
.name = "JUMP IF R",
|
||||
.desc = "Offsets the instruction pointer in reversed direction if condition is NOT met",
|
||||
.operands = {
|
||||
{ "any", "condition object" },
|
||||
},
|
||||
.params = {
|
||||
{ "ip offset unsigned", 2 },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::PRINT, {
|
||||
.name = "PRINT",
|
||||
.desc = "Prints the object string representation",
|
||||
.operands = {
|
||||
{ "any", "self" },
|
||||
}
|
||||
}
|
||||
);
|
||||
add(OpCode::CLASS_CONSTRUCT, {
|
||||
.name = "CLASS CONSTRUCT",
|
||||
.desc = "Creates class from the function execution state",
|
||||
}
|
||||
);
|
||||
add(OpCode::SELF, {
|
||||
.name = "SELF",
|
||||
.desc = "retrieves parent class of the current method",
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
OpcodeInfos::OpInfo OpcodeInfos::fetch(OpCode code) {
|
||||
DEBUG_ASSERT((tp::alni)code >= 0 && (tp::alni)code < (tp::alni)OpCode::END_OPCODES);
|
||||
return buff[(tp::alni)code];
|
||||
}
|
||||
|
||||
void OpcodeInfos::add(OpCode code, const OpInfo& info) {
|
||||
buff[(tp::alni)code] = info;
|
||||
}
|
||||
30
Objects/private/interpreter/operandsstack.cpp
Normal file
30
Objects/private/interpreter/operandsstack.cpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
#include "interpreter/operandsstack.h"
|
||||
|
||||
using namespace obj;
|
||||
|
||||
OperandStack::OperandStack() {
|
||||
mBuff = new Operand[MAX_STACK_SIZE];
|
||||
mIdx = 0;
|
||||
}
|
||||
|
||||
void OperandStack::push(Operand operand) {
|
||||
ASSERT(MAX_STACK_SIZE - 1 > mIdx && "stack overflow");
|
||||
mBuff[mIdx] = operand;
|
||||
mIdx++;
|
||||
}
|
||||
|
||||
void OperandStack::pop() {
|
||||
ASSERT(mIdx != NULL && "stack overflow");
|
||||
mIdx--;
|
||||
}
|
||||
|
||||
Operand OperandStack::getOperand() {
|
||||
auto ret = mBuff[mIdx - 1];
|
||||
mIdx--;
|
||||
return ret;
|
||||
}
|
||||
|
||||
OperandStack::~OperandStack() {
|
||||
delete[] mBuff;
|
||||
}
|
||||
90
Objects/private/interpreter/scopestack.cpp
Normal file
90
Objects/private/interpreter/scopestack.cpp
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
|
||||
#include "NewPlacement.hpp"
|
||||
|
||||
#include "interpreter/scopestack.h"
|
||||
|
||||
using namespace obj;
|
||||
|
||||
Scope::~Scope() {
|
||||
for (auto local : mLocals) {
|
||||
obj::NDO->destroy(local->val);
|
||||
}
|
||||
for (auto tmp : mTemps) {
|
||||
obj::NDO->destroy(tmp.data());
|
||||
}
|
||||
}
|
||||
|
||||
obj::Object* ScopeStack::getLocalUtil(Scope& scope, tp::String* id) {
|
||||
|
||||
auto idx = scope.mLocals.presents(*id);
|
||||
|
||||
if (idx) {
|
||||
return scope.mLocals.getSlotVal(idx);
|
||||
}
|
||||
else {
|
||||
mIterIdx--;
|
||||
Scope& parent_scope = mBuff[mIterIdx];
|
||||
ASSERT(parent_scope.mChildReachable && "Undefined Local Reference");
|
||||
return getLocalUtil(parent_scope, id);
|
||||
}
|
||||
}
|
||||
|
||||
ScopeStack::ScopeStack() {
|
||||
mBuff = (Scope*) tp::HeapAllocGlobal::allocate(sizeof(Scope) * MAX_STACK_SIZE);
|
||||
mIdx = 0;
|
||||
mIterIdx = 0;
|
||||
}
|
||||
|
||||
void ScopeStack::enterScope(bool aChildReachable) {
|
||||
ASSERT(MAX_STACK_SIZE - 1 > mIdx && "stack overflow");
|
||||
new (&mBuff[mIdx]) Scope();
|
||||
mBuff[mIdx].mChildReachable = aChildReachable;
|
||||
mIdx++;
|
||||
}
|
||||
|
||||
void ScopeStack::leaveScope() {
|
||||
ASSERT(mIdx != NULL && "stack overflow");
|
||||
mBuff[mIdx - 1].~Scope();
|
||||
mIdx--;
|
||||
}
|
||||
|
||||
void ScopeStack::addTemp(obj::Object* tmp) {
|
||||
obj::NDO->refinc(tmp);
|
||||
mBuff[mIdx - 1].mTemps.pushBack(tmp);
|
||||
}
|
||||
|
||||
void ScopeStack::popTemp() {
|
||||
obj::NDO->destroy(mBuff[mIdx - 1].mTemps.last()->data);
|
||||
mBuff[mIdx - 1].mTemps.popBack();
|
||||
}
|
||||
|
||||
void ScopeStack::addTempReturn(obj::Object* ret) {
|
||||
if (mIdx >= 2) {
|
||||
obj::NDO->refinc(ret);
|
||||
mBuff[mIdx - 2].mTemps.pushBack(ret);
|
||||
}
|
||||
}
|
||||
|
||||
void ScopeStack::addLocal(obj::Object* local, tp::String id) {
|
||||
DEBUG_ASSERT(mIdx != 0 && "No scope given");
|
||||
Scope::ObjDict& locals = mBuff[mIdx - 1].mLocals;
|
||||
auto idx = locals.presents(id);
|
||||
if (idx) {
|
||||
obj::NDO->destroy(locals.getSlotVal(idx));
|
||||
}
|
||||
obj::NDO->refinc(local);
|
||||
locals.put(id, local);
|
||||
}
|
||||
|
||||
obj::Object* ScopeStack::getLocal(tp::String& str) {
|
||||
mIterIdx = mIdx - 1;
|
||||
return getLocalUtil(mBuff[mIdx - 1], &str);
|
||||
}
|
||||
|
||||
Scope* ScopeStack::getCurrentScope() {
|
||||
return &mBuff[mIdx - 1];
|
||||
}
|
||||
|
||||
ScopeStack::~ScopeStack() {
|
||||
tp::HeapAllocGlobal::deallocate(mBuff);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue