Objects Initial
This commit is contained in:
parent
0f639ba3b1
commit
94057d2a66
76 changed files with 7895 additions and 17 deletions
148
Objects/private/compiler/constants.cpp
Normal file
148
Objects/private/compiler/constants.cpp
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
#include "NewPlacement.hpp"
|
||||
#include "compiler/constants.h"
|
||||
#include "primitives/primitives.h"
|
||||
#include "primitives/methodobject.h"
|
||||
|
||||
using namespace obj;
|
||||
using namespace tp;
|
||||
using namespace BCgen;
|
||||
|
||||
ConstObject::ConstObject() {}
|
||||
ConstObject::ConstObject(obj::Object* mObj) : mObj(mObj) {}
|
||||
|
||||
ConstObjectsPool::~ConstObjectsPool() {
|
||||
if (mDelete) {
|
||||
for (auto obj : mStrings) {
|
||||
obj::NDO->destroy(obj->val->mObj);
|
||||
}
|
||||
for (auto obj : mIntegers) {
|
||||
obj::NDO->destroy(obj->val->mObj);
|
||||
}
|
||||
for (auto obj : mFloats) {
|
||||
obj::NDO->destroy(obj->val->mObj);
|
||||
}
|
||||
for (auto obj : mMethods) {
|
||||
obj::NDO->destroy(obj->val->mObj);
|
||||
}
|
||||
if (mBoolFalse.mObj) {
|
||||
obj::NDO->destroy(mBoolFalse.mObj);
|
||||
}
|
||||
if (mBoolTrue.mObj) {
|
||||
obj::NDO->destroy(mBoolTrue.mObj);
|
||||
}
|
||||
}
|
||||
for (auto obj : mStrings) {
|
||||
delete obj->val;
|
||||
}
|
||||
for (auto obj : mIntegers) {
|
||||
delete obj->val;
|
||||
}
|
||||
for (auto obj : mFloats) {
|
||||
delete obj->val;
|
||||
}
|
||||
}
|
||||
|
||||
ConstObject* ConstObjectsPool::registerObject(obj::Object* obj) {
|
||||
ConstObject* out = new ConstObject(obj);
|
||||
mTotalObjects++;
|
||||
return out;
|
||||
}
|
||||
|
||||
ConstObject* ConstObjectsPool::get(tp::alni val) {
|
||||
auto idx = mIntegers.presents(val);
|
||||
ConstObject* const_obj = NULL;
|
||||
if (idx) {
|
||||
const_obj = mIntegers.getSlotVal(idx);
|
||||
}
|
||||
else {
|
||||
const_obj = registerObject(IntObject::create(val));
|
||||
mIntegers.put(val, const_obj);
|
||||
}
|
||||
return const_obj;
|
||||
}
|
||||
|
||||
ConstObject* ConstObjectsPool::get(tp::String val) {
|
||||
auto idx = mStrings.presents(val);
|
||||
ConstObject* const_obj = NULL;
|
||||
if (idx) {
|
||||
const_obj = mStrings.getSlotVal(idx);
|
||||
}
|
||||
else {
|
||||
const_obj = registerObject(StringObject::create(val));
|
||||
mStrings.put(val, const_obj);
|
||||
}
|
||||
return const_obj;
|
||||
}
|
||||
|
||||
ConstObject* ConstObjectsPool::get(tp::alnf val) {
|
||||
auto idx = mFloats.presents(val);
|
||||
ConstObject* const_obj = NULL;
|
||||
if (idx) {
|
||||
const_obj = mFloats.getSlotVal(idx);
|
||||
}
|
||||
else {
|
||||
const_obj = registerObject(FloatObject::create(val));
|
||||
mFloats.put(val, const_obj);
|
||||
}
|
||||
return const_obj;
|
||||
}
|
||||
|
||||
ConstObject* ConstObjectsPool::get(bool val) {
|
||||
if (val) {
|
||||
if (!mBoolTrue.mObj) {
|
||||
mBoolTrue.mObj = BoolObject::create(val);
|
||||
mTotalObjects++;
|
||||
}
|
||||
return &mBoolTrue;
|
||||
}
|
||||
else {
|
||||
if (!mBoolFalse.mObj) {
|
||||
mBoolFalse.mObj = BoolObject::create(val);
|
||||
mTotalObjects++;
|
||||
}
|
||||
return &mBoolFalse;
|
||||
}
|
||||
}
|
||||
|
||||
ConstObject* ConstObjectsPool::addMethod(tp::String method_id, obj::Object* method) {
|
||||
ASSERT(NDO_CAST(MethodObject, method) && "Object is not a method object");
|
||||
ASSERT(!mMethods.presents(method_id) && "Method Redefinition");
|
||||
auto out = registerObject(method);
|
||||
mMethods.put(method_id, out);
|
||||
return out;
|
||||
}
|
||||
|
||||
void ConstObjectsPool::save(tp::Buffer<ConstData>& out) {
|
||||
out.reserve(mTotalObjects);
|
||||
tp::alni data_idx = 0;
|
||||
for (auto obj : mMethods) {
|
||||
out[data_idx] = obj->val->mObj;
|
||||
obj->val->mConstIdx = data_idx;
|
||||
data_idx++;
|
||||
}
|
||||
for (auto obj : mStrings) {
|
||||
out[data_idx] = obj->val->mObj;
|
||||
obj->val->mConstIdx = data_idx;
|
||||
data_idx++;
|
||||
}
|
||||
for (auto obj : mIntegers) {
|
||||
out[data_idx] = obj->val->mObj;
|
||||
obj->val->mConstIdx = data_idx;
|
||||
data_idx++;
|
||||
}
|
||||
for (auto obj : mFloats) {
|
||||
out[data_idx] = obj->val->mObj;
|
||||
obj->val->mConstIdx = data_idx;
|
||||
data_idx++;
|
||||
}
|
||||
if (mBoolFalse.mObj) {
|
||||
out[data_idx] = mBoolFalse.mObj;
|
||||
mBoolFalse.mConstIdx = data_idx;
|
||||
data_idx++;
|
||||
}
|
||||
if (mBoolTrue.mObj) {
|
||||
out[data_idx] = mBoolTrue.mObj;
|
||||
mBoolTrue.mConstIdx = data_idx;
|
||||
}
|
||||
mDelete = false;
|
||||
}
|
||||
70
Objects/private/compiler/expression.cpp
Normal file
70
Objects/private/compiler/expression.cpp
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
#include "NewPlacement.hpp"
|
||||
#include "compiler/expression.h"
|
||||
|
||||
using namespace obj;
|
||||
using namespace BCgen;
|
||||
|
||||
Expression::Expression() {}
|
||||
Expression::Expression(Type type) : mType(type) {}
|
||||
|
||||
ExpressionChild* Expression::ExprChild(tp::String id) {
|
||||
return new ExpressionChild(this, id);
|
||||
}
|
||||
|
||||
ExpressionCall* Expression::ExprCall(tp::init_list<Expression*> args) {
|
||||
return new ExpressionCall(this, args);
|
||||
}
|
||||
|
||||
ExpressionLocal* obj::BCgen::ExprLocal(tp::String id) {
|
||||
return new ExpressionLocal(id);
|
||||
}
|
||||
|
||||
ExpressionSelf* obj::BCgen::ExprSelf() {
|
||||
return new ExpressionSelf();
|
||||
}
|
||||
|
||||
ExpressionNew* obj::BCgen::ExprNew(tp::String type) {
|
||||
return new ExpressionNew(type);
|
||||
}
|
||||
|
||||
ExpressionAriphm* obj::BCgen::ExprAriphm(Expression* left, Expression* right, OpCode type) {
|
||||
return new ExpressionAriphm(left, right, type);
|
||||
}
|
||||
|
||||
ExpressionFunc* obj::BCgen::ExprFunc(tp::String id) {
|
||||
return new ExpressionFunc(id);
|
||||
}
|
||||
|
||||
ExpressionBoolean* obj::BCgen::ExprBool(Expression* left, Expression* right, obj::OpCode type) {
|
||||
return new ExpressionBoolean(left, right, ExpressionBoolean::BoolType(type));
|
||||
}
|
||||
|
||||
ExpressionBoolean* obj::BCgen::ExprBoolNot(Expression* invert) {
|
||||
return new ExpressionBoolean(invert);
|
||||
}
|
||||
|
||||
ExpressionBoolean::ExpressionBoolean(Expression* left, Expression* right, BoolType type)
|
||||
: Expression(Type::BOOLEAN), mLeft(left), mRight(right), mBoolType(type) {
|
||||
}
|
||||
|
||||
ExpressionBoolean::ExpressionBoolean(Expression* invert)
|
||||
: Expression(Type::BOOLEAN), mLeft(invert), mBoolType(BoolType::NOT){
|
||||
}
|
||||
|
||||
ExpressionCall::ExpressionCall(Expression * mParent, tp::init_list<Expression*> args) : Expression(Type::CALL), mParent(mParent) {
|
||||
mArgs = args;
|
||||
}
|
||||
|
||||
ExpressionNew::ExpressionNew(tp::String type) : Expression(Type::NEW), mNewType(type) {}
|
||||
ExpressionLocal::ExpressionLocal(tp::String id) : Expression(Type::LOCAL), mLocalId(id) {}
|
||||
ExpressionSelf::ExpressionSelf() : Expression(Type::SELF) {}
|
||||
ExpressionChild::ExpressionChild(Expression* mParent, tp::String id) : Expression(Type::CHILD), mParent(mParent), mLocalId(id) {}
|
||||
ExpressionAriphm::ExpressionAriphm(Expression* left, Expression* right, OpCode type) : Expression(Type::ARIPHM), mLeft(left), mRight(right), mOpType(type) {}
|
||||
ExpressionFunc::ExpressionFunc(tp::String id) : Expression(Type::FUNC), mFuncId(id) {}
|
||||
ExpressionConst::ExpressionConst(tp::String val) : Expression(Type::CONST), mConstType(STR), str(val) {}
|
||||
ExpressionConst::ExpressionConst(const char* val) : Expression(Type::CONST), mConstType(STR), str(val) {}
|
||||
ExpressionConst::ExpressionConst(tp::int4 val) : Expression(Type::CONST), mConstType(INT), integer(val) {}
|
||||
ExpressionConst::ExpressionConst(tp::flt4 val) : Expression(Type::CONST), mConstType(FLT), floating(val) {}
|
||||
ExpressionConst::ExpressionConst(tp::alni val) : Expression(Type::CONST), mConstType(INT), integer(val) {}
|
||||
ExpressionConst::ExpressionConst(tp::alnf val) : Expression(Type::CONST), mConstType(FLT), floating(val) {}
|
||||
ExpressionConst::ExpressionConst(bool val) : Expression(Type::CONST), mConstType(BOOL), boolean(val) {}
|
||||
556
Objects/private/compiler/function.cpp
Normal file
556
Objects/private/compiler/function.cpp
Normal file
|
|
@ -0,0 +1,556 @@
|
|||
|
||||
#include "NewPlacement.hpp"
|
||||
|
||||
#include "compiler/function.h"
|
||||
|
||||
#include "primitives/primitives.h"
|
||||
#include "primitives/methodobject.h"
|
||||
|
||||
#include "Logging.hpp"
|
||||
|
||||
#include "parser/parser.h"
|
||||
|
||||
using namespace obj;
|
||||
using namespace tp;
|
||||
using namespace obj;
|
||||
using namespace BCgen;
|
||||
|
||||
void obj::BCgen::Genereate(ByteCode& out, StatementScope* body) {
|
||||
auto root = FunctionDefinition();
|
||||
|
||||
root.inst(Instruction(OpCode::SCOPE_IN));
|
||||
|
||||
for (auto child_stm : body->mStatements) {
|
||||
root.EvalStatement(child_stm.data());
|
||||
}
|
||||
|
||||
root.inst(Instruction(OpCode::SCOPE_OUT));
|
||||
|
||||
root.generateByteCode(out);
|
||||
}
|
||||
|
||||
ConstObject* FunctionDefinition::defineLocal(tp::String id) {
|
||||
auto idx = mLocals.presents(id);
|
||||
//RelAssert(!idx && "Local Redefinition");
|
||||
auto const_str_id = mConstants.get(id);
|
||||
mLocals.put(id, const_str_id);
|
||||
return const_str_id;
|
||||
}
|
||||
|
||||
FunctionDefinition::FunctionDefinition(tp::String function_id, tp::Buffer<tp::String> args, FunctionDefinition* prnt) {
|
||||
mFunctionId = function_id;
|
||||
inst(Instruction(OpCode::SAVE_ARGS, args.size(), 1));
|
||||
for (auto id : args) {
|
||||
ASSERT(!mLocals.presents(id.data()) && "Argument Redefinition");
|
||||
auto const_data = mConstants.get(id.data());
|
||||
mArgsOrder.pushBack(const_data);
|
||||
mLocals.put(id.data(), const_data);
|
||||
inst(Instruction(const_data));
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionDefinition::EvalStatement(Statement* stm) {
|
||||
switch (stm->mType) {
|
||||
case Statement::Type::IGNORE: {
|
||||
auto stm_ignore = (StatementIgnore*)stm;
|
||||
EvalExpr(stm_ignore->mExpr);
|
||||
inst(OpCode::IGNORE);
|
||||
break;
|
||||
}
|
||||
case Statement::Type::WHILE: {
|
||||
auto stm_while = (StatementWhile*)stm;
|
||||
|
||||
auto check_mark = inst(Instruction());
|
||||
|
||||
EvalExpr(stm_while->mCondition);
|
||||
|
||||
auto jump_if_inst = inst(Instruction(NULL, Instruction::InstType::JUMP_IF_NOT));
|
||||
|
||||
if (stm_while->mScope) {
|
||||
EvalStatement(stm_while->mScope);
|
||||
}
|
||||
|
||||
auto jump_inst = inst(Instruction(NULL, Instruction::InstType::JUMP));
|
||||
auto end_mark = inst(Instruction());
|
||||
|
||||
jump_if_inst->data.mInstTarget = end_mark;
|
||||
jump_inst->data.mInstTarget = check_mark;
|
||||
|
||||
break;
|
||||
}
|
||||
case Statement::Type::IF: {
|
||||
auto stm_if = (StatementIf*)stm;
|
||||
|
||||
EvalExpr(stm_if->mCondition);
|
||||
|
||||
auto jump_if_inst = inst(Instruction(NULL, Instruction::InstType::JUMP_IF_NOT));
|
||||
|
||||
if (stm_if->mOnTrue) {
|
||||
EvalStatement(stm_if->mOnTrue);
|
||||
}
|
||||
|
||||
auto jump_inst = inst(Instruction(NULL, Instruction::InstType::JUMP));
|
||||
auto else_mark = inst(Instruction());
|
||||
|
||||
if (stm_if->mOnFalse) {
|
||||
EvalStatement(stm_if->mOnFalse);
|
||||
}
|
||||
|
||||
auto end_mark = inst(Instruction());
|
||||
|
||||
jump_if_inst->data.mInstTarget = else_mark;
|
||||
jump_inst->data.mInstTarget = end_mark;
|
||||
|
||||
break;
|
||||
}
|
||||
case Statement::Type::SCOPE: {
|
||||
auto stm_scope = (StatementScope*)stm;
|
||||
if (stm_scope->mPushToScopeStack) {
|
||||
inst(Instruction(OpCode::SCOPE_IN));
|
||||
}
|
||||
for (auto child_stm : stm_scope->mStatements) {
|
||||
EvalStatement(child_stm.data());
|
||||
}
|
||||
if (stm_scope->mPushToScopeStack) {
|
||||
inst(Instruction(OpCode::SCOPE_OUT));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Statement::Type::DEF_FUNC: {
|
||||
auto stm_func_def = (StatementFuncDef*) stm;
|
||||
|
||||
FunctionDefinition func(stm_func_def->mFunctionId, stm_func_def->mArgs, this);
|
||||
|
||||
// define method as local
|
||||
auto idx = mLocals.presents(func.mFunctionId);
|
||||
ASSERT(!idx && "Local Redefinition with function name");
|
||||
mLocals.put(func.mFunctionId, mConstants.get(func.mFunctionId));
|
||||
|
||||
// create and register const func object
|
||||
auto function_obj = NDO_CAST(MethodObject, NDO->create("method"));
|
||||
auto method_const_obj = mConstants.addMethod(func.mFunctionId, function_obj);
|
||||
|
||||
for (auto child_stm : stm_func_def->mStatements) {
|
||||
func.EvalStatement(child_stm.data());
|
||||
}
|
||||
|
||||
func.generateByteCode(function_obj->mScript->mBytecode);
|
||||
|
||||
inst(Instruction(OpCode::LOAD_CONST, method_const_obj));
|
||||
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(func.mFunctionId)));
|
||||
inst(Instruction(OpCode::DEF_LOCAL));
|
||||
break;
|
||||
}
|
||||
case Statement::Type::CLASS_DEF: {
|
||||
|
||||
// do the function definition
|
||||
auto stm_class_def = (StatementClassDef*)stm;
|
||||
|
||||
FunctionDefinition func(stm_class_def->mClassId, {}, this);
|
||||
|
||||
// define method as local
|
||||
auto idx = mLocals.presents(func.mFunctionId);
|
||||
ASSERT(!idx && "Local Redefinition with function name");
|
||||
mLocals.put(func.mFunctionId, mConstants.get(func.mFunctionId));
|
||||
|
||||
// create and register const func object
|
||||
auto function_obj = NDO_CAST(MethodObject, NDO->create("method"));
|
||||
auto method_const_obj = mConstants.addMethod(func.mFunctionId, function_obj);
|
||||
|
||||
// compile function
|
||||
for (auto child_stm : stm_class_def->mScope->mStatements) {
|
||||
// check for return statements
|
||||
ASSERT(child_stm.data()->mType != Statement::Type::RET && "return statements are not allowed in class definition");
|
||||
func.EvalStatement(child_stm.data());
|
||||
}
|
||||
// create one last instruction - constructing class from function execution state
|
||||
func.inst(Instruction(OpCode::CLASS_CONSTRUCT));
|
||||
func.generateByteCode(function_obj->mScript->mBytecode);
|
||||
|
||||
inst(Instruction(OpCode::LOAD_CONST, method_const_obj));
|
||||
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(func.mFunctionId)));
|
||||
inst(Instruction(OpCode::DEF_LOCAL));
|
||||
break;
|
||||
}
|
||||
case Statement::Type::DEF_LOCAL: {
|
||||
auto stm_local_def = (StatementLocalDef*)stm;
|
||||
|
||||
if (!stm_local_def->mIsConstExpr) {
|
||||
auto const_id = defineLocal(stm_local_def->mLocalId);
|
||||
EvalExpr(stm_local_def->mNewExpr);
|
||||
inst(Instruction(OpCode::LOAD_CONST, const_id));
|
||||
inst(Instruction(OpCode::DEF_LOCAL));
|
||||
|
||||
} else {
|
||||
|
||||
tp::String type;
|
||||
switch (stm_local_def->mConstExpr->mConstType) {
|
||||
case ExpressionConst::BOOL: {
|
||||
type = "bool";
|
||||
break;
|
||||
}
|
||||
case ExpressionConst::INT: {
|
||||
type = "int";
|
||||
break;
|
||||
}
|
||||
case ExpressionConst::FLT: {
|
||||
type = "float";
|
||||
break;
|
||||
}
|
||||
case ExpressionConst::STR: {
|
||||
type = "str";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ASSERT(0 && "Cantbe");
|
||||
}
|
||||
}
|
||||
|
||||
auto new_expr = new ExpressionNew(type);
|
||||
|
||||
EvalStatement(StmDefLocal(stm_local_def->mLocalId, new_expr));
|
||||
EvalExpr(stm_local_def->mConstExpr);
|
||||
inst(Instruction(OpCode::LOAD_LOCAL, mConstants.get(stm_local_def->mLocalId)));
|
||||
inst(Instruction(OpCode::OBJ_COPY));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Statement::Type::COPY: {
|
||||
auto stm_cp = (StatementCopy*)stm;
|
||||
EvalExpr(stm_cp->mRight);
|
||||
EvalExpr(stm_cp->mLeft);
|
||||
inst(Instruction(OpCode::OBJ_COPY));
|
||||
break;
|
||||
}
|
||||
case Statement::Type::PRINT: {
|
||||
auto stm_prnt = (StatementPrint*)stm;
|
||||
EvalExpr(stm_prnt->mTarget);
|
||||
inst(Instruction(OpCode::PRINT));
|
||||
break;
|
||||
}
|
||||
case Statement::Type::RET: {
|
||||
auto stm_ret = (StatementReturn*)stm;
|
||||
if (stm_ret->mRet) {
|
||||
EvalExpr(stm_ret->mRet);
|
||||
inst(Instruction(OpCode::RETURN_OBJ));
|
||||
} else {
|
||||
inst(Instruction(OpCode::RETURN));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ASSERT(0)
|
||||
}
|
||||
|
||||
delete stm;
|
||||
}
|
||||
|
||||
|
||||
void FunctionDefinition::EvalExpr(Expression* expr) {
|
||||
switch (expr->mType) {
|
||||
case Expression::Type::BOOLEAN: {
|
||||
auto boolean = (ExpressionBoolean*)expr;
|
||||
if (boolean->mBoolType == ExpressionBoolean::BoolType::NOT) {
|
||||
EvalExpr(boolean->mLeft);
|
||||
inst(OpCode::NOT);
|
||||
} else {
|
||||
EvalExpr(boolean->mRight);
|
||||
EvalExpr(boolean->mLeft);
|
||||
inst(OpCode(boolean->mBoolType));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Expression::Type::FUNC: {
|
||||
auto func = (ExpressionFunc*)expr;
|
||||
|
||||
//RelAssert(mConstants.mMethods.presents(func->mFuncId) && "No such function");
|
||||
inst(Instruction(OpCode::LOAD_LOCAL, mConstants.get(func->mFuncId)));
|
||||
break;
|
||||
}
|
||||
case Expression::Type::ARIPHM: {
|
||||
auto ariphm = (ExpressionAriphm*)expr;
|
||||
EvalExpr(ariphm->mRight);
|
||||
EvalExpr(ariphm->mLeft);
|
||||
inst(Instruction(ariphm->mOpType));
|
||||
break;
|
||||
}
|
||||
case Expression::Type::NEW: {
|
||||
auto create_new = (ExpressionNew*)expr;
|
||||
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(create_new->mNewType)));
|
||||
inst(Instruction(OpCode::OBJ_CREATE));
|
||||
break;
|
||||
}
|
||||
case Expression::Type::LOCAL: {
|
||||
auto local = (ExpressionLocal*)expr;
|
||||
// RelAssert(mLocals.presents(local->mLocalId) && "undefined local");
|
||||
inst(Instruction(OpCode::LOAD_LOCAL, mConstants.get(local->mLocalId)));
|
||||
break;
|
||||
}
|
||||
case Expression::Type::CONST: {
|
||||
auto constobj = (ExpressionConst*)expr;
|
||||
switch (constobj->mConstType) {
|
||||
case ExpressionConst::STR: {
|
||||
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(constobj->str)));
|
||||
break;
|
||||
}
|
||||
case ExpressionConst::INT: {
|
||||
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(constobj->integer)));
|
||||
break;
|
||||
}
|
||||
case ExpressionConst::FLT: {
|
||||
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(constobj->floating)));
|
||||
break;
|
||||
}
|
||||
case ExpressionConst::BOOL: {
|
||||
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(constobj->boolean)));
|
||||
break;
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
case Expression::Type::CHILD: {
|
||||
auto child = (ExpressionChild*)expr;
|
||||
EvalExpr(child->mParent);
|
||||
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(child->mLocalId)));
|
||||
inst(Instruction(OpCode::CHILD, child->mMethod, 1));
|
||||
break;
|
||||
}
|
||||
case Expression::Type::SELF: {
|
||||
inst(Instruction(OpCode::SELF));
|
||||
break;
|
||||
}
|
||||
case Expression::Type::CALL: {
|
||||
auto call = (ExpressionCall*)expr;
|
||||
inst(Instruction(OpCode::PUSH_ARGS, call->mArgs.size(), 1));
|
||||
for (auto arg : call->mArgs) {
|
||||
EvalExpr(arg.data());
|
||||
}
|
||||
EvalExpr(call->mParent);
|
||||
inst(Instruction(OpCode::CALL));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ASSERT(0)
|
||||
}
|
||||
delete expr;
|
||||
}
|
||||
|
||||
tp::alni instSize(const Instruction& inst) {
|
||||
switch (inst.mInstType) {
|
||||
case Instruction::InstType::JUMP:
|
||||
case Instruction::InstType::JUMP_IF_NOT:
|
||||
case Instruction::InstType::JUMP_IF: {
|
||||
// 2 bytes for offset 1 byte for instrtuction
|
||||
return 3;
|
||||
}
|
||||
case Instruction::InstType::PURE_CONST: {
|
||||
return 2;
|
||||
}
|
||||
case Instruction::InstType::EXEC: {
|
||||
tp::alni out = 1;
|
||||
switch (inst.mArgType) {
|
||||
case Instruction::ArgType::PARAM: {
|
||||
out += inst.mParamBytes;
|
||||
return out;
|
||||
}
|
||||
case Instruction::ArgType::CONST: {
|
||||
out += 2;
|
||||
if (inst.mConstData2) {
|
||||
out += 2;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
case Instruction::ArgType::NO_ARG: {
|
||||
return out;
|
||||
}
|
||||
default: {
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
case Instruction::InstType::NONE: {
|
||||
return 0;
|
||||
}
|
||||
default: {
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void writeConst(ByteCode& out, tp::alni& idx, tp::uint2 data) {
|
||||
for (auto byte : tp::Range(sizeof(tp::uint2))) {
|
||||
out.mInstructions[idx] = OpCode((tp::int1)(data >> byte * 8));
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
void writeParam(ByteCode& out, tp::alni& idx, tp::int1* data, tp::alni size) {
|
||||
for (auto byte : tp::Range(size)) {
|
||||
out.mInstructions[idx] = OpCode(data[byte]);
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
tp::alni calcOffset(tp::List<Instruction>::Node* jump_inst, tp::List<Instruction>::Node* to) {
|
||||
tp::alni offset = 0;
|
||||
bool reversed = jump_inst->data.mInstIdx > to->data.mInstIdx;
|
||||
auto iter_node = reversed ? jump_inst : jump_inst->next;
|
||||
while (iter_node != to) {
|
||||
offset += instSize(iter_node->data);
|
||||
iter_node = reversed ? iter_node->prev : iter_node->next;
|
||||
}
|
||||
if (reversed) {
|
||||
offset += instSize(iter_node->data);
|
||||
}
|
||||
return reversed ? -offset : offset;
|
||||
}
|
||||
|
||||
void FunctionDefinition::generateByteCode(ByteCode& out) {
|
||||
|
||||
out.~ByteCode();
|
||||
new (&out) ByteCode();
|
||||
|
||||
mConstants.save(out.mConstants);
|
||||
|
||||
tp::alni inst_len = 0;
|
||||
for (auto inst_iter : mInstructions) {
|
||||
inst_len += instSize(inst_iter.data());
|
||||
}
|
||||
out.mInstructions.reserve(inst_len);
|
||||
|
||||
tp::alni idx = 0;
|
||||
for (auto inst_iter : mInstructions) {
|
||||
auto inst = inst_iter.data();
|
||||
|
||||
switch (inst.mInstType) {
|
||||
case Instruction::InstType::JUMP_IF:
|
||||
case Instruction::InstType::JUMP_IF_NOT:
|
||||
case Instruction::InstType::JUMP: {
|
||||
tp::alni offset = calcOffset(inst_iter.node(), inst.mInstTarget);
|
||||
|
||||
if (offset == 0) {
|
||||
out.mInstructions[idx] = OpCode::NONE;
|
||||
idx += 3;
|
||||
break;
|
||||
}
|
||||
|
||||
if (inst.mInstType == Instruction::InstType::JUMP_IF) {
|
||||
if (offset > 0) {
|
||||
out.mInstructions[idx] = OpCode::JUMP_IF;
|
||||
}
|
||||
else {
|
||||
out.mInstructions[idx] = OpCode::JUMP_IF_R;
|
||||
}
|
||||
}
|
||||
else if (inst.mInstType == Instruction::InstType::JUMP_IF_NOT) {
|
||||
if (offset > 0) {
|
||||
out.mInstructions[idx] = OpCode::JUMP_IF_NOT;
|
||||
}
|
||||
else {
|
||||
out.mInstructions[idx] = OpCode::JUMP_IF_NOT_R;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (offset > 0) {
|
||||
out.mInstructions[idx] = OpCode::JUMP;
|
||||
}
|
||||
else {
|
||||
out.mInstructions[idx] = OpCode::JUMP_R;
|
||||
}
|
||||
}
|
||||
|
||||
idx++;
|
||||
|
||||
tp::alni offset_mod = abs(offset);
|
||||
tp::uint2 offset_param = (tp::uint2)offset_mod;
|
||||
writeParam(out, idx, (tp::int1*)&offset_param, 2);
|
||||
break;
|
||||
}
|
||||
case Instruction::InstType::PURE_CONST: {
|
||||
writeConst(out, idx, (tp::uint2)inst.mConstData->mConstIdx);
|
||||
break;
|
||||
}
|
||||
case Instruction::InstType::EXEC: {
|
||||
out.mInstructions[idx] = inst.mOp;
|
||||
idx++;
|
||||
switch (inst.mArgType) {
|
||||
case Instruction::ArgType::PARAM: {
|
||||
writeParam(out, idx, (tp::int1*) &inst.mParam, inst.mParamBytes);
|
||||
break;
|
||||
}
|
||||
case Instruction::ArgType::CONST: {
|
||||
writeConst(out, idx, (tp::uint2)inst.mConstData->mConstIdx);
|
||||
if (inst.mConstData2) {
|
||||
writeConst(out, idx, (tp::uint2)inst.mConstData2->mConstIdx);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Instruction::ArgType::NO_ARG: {
|
||||
break;
|
||||
}
|
||||
default:{
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ASSERT(0);
|
||||
}
|
||||
case Instruction::InstType::NONE: {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tp::List<Instruction>::Node* FunctionDefinition::inst(Instruction inst) {
|
||||
mInstructions.pushBack(inst);
|
||||
auto out = &mInstructions.last()->data;
|
||||
out->mInstIdx = mInstructions.length() - 1;
|
||||
return mInstructions.last();
|
||||
}
|
||||
|
||||
static Parser* sParger = NULL;
|
||||
|
||||
void obj::BCgen::init() {
|
||||
ASSERT(!sParger);
|
||||
if (!sParger) {
|
||||
sParger = new Parser();
|
||||
}
|
||||
}
|
||||
|
||||
void obj::BCgen::deinit() {
|
||||
ASSERT(sParger);
|
||||
if (sParger) {
|
||||
delete sParger;
|
||||
}
|
||||
}
|
||||
|
||||
bool obj::BCgen::Compile(obj::MethodObject* method) {
|
||||
|
||||
ASSERT(method);
|
||||
ASSERT(sParger);
|
||||
|
||||
if (!sParger) return false;
|
||||
|
||||
auto script = method->mScript->mReadable->val;
|
||||
auto res = sParger->parse(script);
|
||||
|
||||
if (res.err) {
|
||||
auto loc = res.err->get_err_location(script.read());
|
||||
// TODO : print parse error
|
||||
// tp::gLogeer->write(tp::sfmt("Parser Error (%i,%i): \n", loc.head, loc.tail), true, tp::Logger::LogEntry::ERR);
|
||||
// tp::GLog->write(res.err->mDescr, true, tp::Logger::LogEntry::ERR);
|
||||
return false;
|
||||
}
|
||||
|
||||
BCgen::Genereate(method->mScript->mBytecode, res.scope);
|
||||
|
||||
delete res.scope;
|
||||
|
||||
return true;
|
||||
}
|
||||
29
Objects/private/compiler/instruction.cpp
Normal file
29
Objects/private/compiler/instruction.cpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
#include "compiler/instruction.h"
|
||||
|
||||
using namespace obj;
|
||||
using namespace tp;
|
||||
using namespace BCgen;
|
||||
|
||||
Instruction::Instruction(OpCode op) : mOp(op), mArgType(ArgType::NO_ARG), mInstType(InstType::EXEC) {}
|
||||
|
||||
Instruction::Instruction() : mInstType(InstType::NONE) {}
|
||||
|
||||
Instruction::Instruction(ConstObject* constData)
|
||||
: mConstData(constData), mInstType(InstType::PURE_CONST) {}
|
||||
|
||||
Instruction::Instruction(OpCode op, ConstObject* constData)
|
||||
: mOp(op), mConstData(constData), mArgType(ArgType::CONST), mInstType(InstType::EXEC) {
|
||||
}
|
||||
|
||||
Instruction::Instruction(OpCode op, ConstObject* constData, ConstObject* constData2)
|
||||
: mOp(op), mConstData(constData), mConstData2(constData2), mArgType(ArgType::CONST), mInstType(InstType::EXEC) {
|
||||
}
|
||||
|
||||
Instruction::Instruction(OpCode op, tp::alni param, tp::alni nBytes)
|
||||
: mOp(op), mParam(param), mArgType(ArgType::PARAM), mParamBytes(nBytes), mInstType(InstType::EXEC) {
|
||||
}
|
||||
|
||||
Instruction::Instruction(tp::List<Instruction>::Node* inst, InstType jump_type): mInstTarget(inst) {
|
||||
mInstType = jump_type;
|
||||
}
|
||||
116
Objects/private/compiler/statement.cpp
Normal file
116
Objects/private/compiler/statement.cpp
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
#include "NewPlacement.hpp"
|
||||
#include "compiler/statement.h"
|
||||
|
||||
using namespace obj;
|
||||
using namespace BCgen;
|
||||
|
||||
|
||||
StatementFuncDef::StatementFuncDef(tp::String function_id, tp::init_list<tp::String> args, tp::init_list<Statement*> statements) {
|
||||
mType = Type::DEF_FUNC;
|
||||
mArgs = args;
|
||||
mStatements = statements;
|
||||
mFunctionId = function_id;
|
||||
}
|
||||
|
||||
StatementLocalDef::StatementLocalDef(tp::String id, Expression* value) : mLocalId(id), mNewExpr(value) {
|
||||
mType = Type::DEF_LOCAL;
|
||||
}
|
||||
|
||||
StatementLocalDef::StatementLocalDef(tp::String id, ExpressionConst* value) : mLocalId(id), mConstExpr(value), mIsConstExpr(true) {
|
||||
mType = Type::DEF_LOCAL;
|
||||
}
|
||||
|
||||
StatementCopy::StatementCopy(Expression* left, Expression* right) : mLeft(left), mRight(right) {
|
||||
mType = Type::COPY;
|
||||
}
|
||||
|
||||
StatementReturn::StatementReturn() {
|
||||
mType = Type::RET;
|
||||
}
|
||||
|
||||
StatementReturn::StatementReturn(Expression* ret) : mRet(ret) {
|
||||
mType = Type::RET;
|
||||
}
|
||||
|
||||
StatementPrint::StatementPrint(Expression* target) : mTarget(target) {
|
||||
mType = Type::PRINT;
|
||||
}
|
||||
|
||||
StatementScope::StatementScope(tp::init_list<Statement*> statements, bool aPushToScopeStack) {
|
||||
mType = Type::SCOPE;
|
||||
mStatements = statements;
|
||||
mPushToScopeStack = aPushToScopeStack;
|
||||
}
|
||||
|
||||
StatementIf::StatementIf(Expression* condition, StatementScope* on_true, StatementScope* on_false) {
|
||||
mType = Type::IF;
|
||||
mOnFalse = on_false;
|
||||
mOnTrue = on_true;
|
||||
mCondition = condition;
|
||||
}
|
||||
|
||||
StatementWhile::StatementWhile(Expression* condition, StatementScope* scope) {
|
||||
mType = Type::WHILE;
|
||||
mScope = scope;
|
||||
mCondition = condition;
|
||||
}
|
||||
|
||||
StatementIgnore::StatementIgnore(Expression* expr) {
|
||||
mType = Type::IGNORE;
|
||||
mExpr = expr;
|
||||
}
|
||||
|
||||
StatementClassDef::StatementClassDef(tp::String class_id, StatementScope* scope) {
|
||||
mClassId = class_id;
|
||||
mScope = scope;
|
||||
mType = Type::CLASS_DEF;
|
||||
}
|
||||
// helpers
|
||||
|
||||
StatementFuncDef* obj::BCgen::StmDefFunc(tp::String id, tp::init_list<tp::String> args, tp::init_list<Statement*> stms) {
|
||||
return new StatementFuncDef(id, args, stms);
|
||||
}
|
||||
|
||||
StatementLocalDef* obj::BCgen::StmDefLocal(tp::String id, Expression* value) {
|
||||
if (value->mType == Expression::Type::CONST) {
|
||||
return new StatementLocalDef(id, (ExpressionConst*)value);
|
||||
}
|
||||
|
||||
return new StatementLocalDef(id, value);
|
||||
}
|
||||
|
||||
StatementCopy* obj::BCgen::StmCopy(Expression* left, Expression* right) {
|
||||
return new StatementCopy(left, right);
|
||||
}
|
||||
|
||||
StatementPrint* obj::BCgen::StmPrint(Expression* target) {
|
||||
return new StatementPrint(target);
|
||||
}
|
||||
|
||||
StatementReturn* obj::BCgen::StmReturn() {
|
||||
return new StatementReturn();
|
||||
}
|
||||
|
||||
StatementReturn* obj::BCgen::StmReturn(Expression* obj) {
|
||||
return new StatementReturn(obj);
|
||||
}
|
||||
|
||||
StatementIf* obj::BCgen::StmIf(Expression* condition, StatementScope* on_true, StatementScope* on_false) {
|
||||
return new StatementIf(condition, on_true, on_false);
|
||||
}
|
||||
|
||||
StatementScope* obj::BCgen::StmScope(tp::init_list<Statement*> statements, bool aPushToScopeStack = false) {
|
||||
return new StatementScope(statements, aPushToScopeStack);
|
||||
}
|
||||
|
||||
StatementWhile* obj::BCgen::StmWhile(Expression* condition, StatementScope* scope) {
|
||||
return new StatementWhile(condition, scope);
|
||||
}
|
||||
|
||||
StatementIgnore* obj::BCgen::StmIgnore(Expression* expr) {
|
||||
return new StatementIgnore(expr);
|
||||
}
|
||||
|
||||
StatementClassDef* obj::BCgen::StmClassDef(tp::String id, StatementScope* scope) {
|
||||
return new StatementClassDef(id, scope);
|
||||
}
|
||||
250
Objects/private/core/object.cpp
Normal file
250
Objects/private/core/object.cpp
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
|
||||
|
||||
#include "NewPlacement.hpp"
|
||||
|
||||
#include "core/object.h"
|
||||
|
||||
#include "primitives/nullobject.h"
|
||||
#include "primitives/classobject.h"
|
||||
#include "primitives/methodobject.h"
|
||||
|
||||
#include "interpreter/interpreter.h"
|
||||
#include "compiler/function.h"
|
||||
|
||||
namespace obj {
|
||||
|
||||
Object* ObjectMemAllocate(const ObjectType* type);
|
||||
void ObjectMemDeallocate(Object* in);
|
||||
|
||||
objects_api* NDO = NULL;
|
||||
|
||||
void hierarchy_copy(Object* self, const Object* in, const ObjectType* type);
|
||||
void hierarchy_construct(Object* self, const ObjectType* type);
|
||||
|
||||
objects_api::objects_api() {
|
||||
tp::memSetVal(sl_callbacks, SAVE_LOAD_MAX_CALLBACK_SLOTS * sizeof(save_load_callbacks*), 0);
|
||||
interp = new Interpreter();
|
||||
}
|
||||
|
||||
objects_api::~objects_api() {
|
||||
delete interp;
|
||||
}
|
||||
|
||||
void objects_api::define(ObjectType* type) {
|
||||
MODULE_SANITY_CHECK(gModuleObjects);
|
||||
|
||||
DEBUG_ASSERT(NDO && "using uninitialize objects api");
|
||||
DEBUG_ASSERT(!types.presents(type->name) && "Type Redefinition");
|
||||
types.put(type->name, type);
|
||||
|
||||
type->type_methods.init();
|
||||
}
|
||||
|
||||
Object* objects_api::create(const tp::String& name) {
|
||||
MODULE_SANITY_CHECK(gModuleObjects);
|
||||
|
||||
const ObjectType* type = types.get(name);
|
||||
|
||||
Object* obj_instance = ObjectMemAllocate(type);
|
||||
|
||||
if (!obj_instance) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hierarchy_construct(obj_instance, obj_instance->type);
|
||||
|
||||
setrefc(obj_instance, 0);
|
||||
|
||||
NDO_CASTV(ClassObject, obj_instance, classobj);
|
||||
if (classobj) {
|
||||
auto idx = classobj->members->presents("__init__");
|
||||
DEBUG_ASSERT(idx);
|
||||
if (idx) {
|
||||
auto constructor_obj = classobj->members->getSlotVal(idx);
|
||||
NDO_CASTV(MethodObject, constructor_obj, constructor_method);
|
||||
if (constructor_method) {
|
||||
interp->execAll(constructor_method, classobj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return obj_instance;
|
||||
}
|
||||
|
||||
Object* objects_api::copy(Object* self, const Object* in) {
|
||||
if (self->type != in->type) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hierarchy_copy(self, in, self->type);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
bool objects_api::compare(Object* first, Object* second) {
|
||||
if (first->type == second->type) {
|
||||
if (first->type->comparison) {
|
||||
return first->type->comparison(first, second);
|
||||
}
|
||||
|
||||
// raw data comparison
|
||||
return tp::memCompare(first, second, first->type->size) == 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Object* objects_api::instatiate(Object* in) {
|
||||
obj::Object* obj = NDO->create(in->type->name);
|
||||
NDO->copy(obj, in);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void objects_api::set(Object* self, tp::alni val) {
|
||||
if (self->type->convesions && self->type->convesions->from_int) {
|
||||
self->type->convesions->from_int(self, val);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void objects_api::set(Object* self, tp::alnf val) {
|
||||
if (self->type->convesions && self->type->convesions->from_float) {
|
||||
self->type->convesions->from_float(self, val);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void objects_api::set(Object* self, tp::String val) {
|
||||
if (self->type->convesions && self->type->convesions->from_string) {
|
||||
self->type->convesions->from_string(self, val);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
tp::alni objects_api::toInt(Object* self) {
|
||||
DEBUG_ASSERT(self->type->convesions && self->type->convesions->to_int);
|
||||
return self->type->convesions->to_int(self);
|
||||
}
|
||||
|
||||
tp::alnf objects_api::toFloat(Object* self) {
|
||||
DEBUG_ASSERT(self->type->convesions && self->type->convesions->to_float);
|
||||
return self->type->convesions->to_float(self);
|
||||
}
|
||||
|
||||
bool objects_api::toBool(Object* self) {
|
||||
if (self->type->convesions && self->type->convesions->to_int) {
|
||||
return (bool) self->type->convesions->to_int(self);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
tp::String objects_api::toString(Object* self) {
|
||||
DEBUG_ASSERT(self->type->convesions && self->type->convesions->to_string);
|
||||
return self->type->convesions->to_string(self);
|
||||
}
|
||||
|
||||
void objects_api::destroy(Object* in) {
|
||||
|
||||
if (!in) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef OBJECT_REF_COUNT
|
||||
ObjectMemHead* mh = NDO_MEMH_FROM_NDO(in);
|
||||
if (mh->refc > 1) {
|
||||
mh->refc--;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
NDO_CASTV(ClassObject, in, classobj);
|
||||
if (classobj) {
|
||||
auto idx = classobj->members->presents("__del__");
|
||||
DEBUG_ASSERT(idx);
|
||||
if (idx) {
|
||||
auto constructor_obj = classobj->members->getSlotVal(idx);
|
||||
NDO_CASTV(MethodObject, constructor_obj, constructor_method);
|
||||
if (constructor_method) {
|
||||
interp->execAll(constructor_method, classobj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const ObjectType* iter = in->type; iter; iter = iter->base) {
|
||||
if (iter->destructor) {
|
||||
iter->destructor(in);
|
||||
}
|
||||
}
|
||||
|
||||
ObjectMemDeallocate(in);
|
||||
}
|
||||
|
||||
#ifdef OBJECT_REF_COUNT
|
||||
tp::halni objects_api::getrefc(Object* in) {
|
||||
ObjectMemHead* mh = NDO_MEMH_FROM_NDO(in);
|
||||
return (tp::halni)mh->refc;
|
||||
}
|
||||
|
||||
void objects_api::refinc(Object* in) {
|
||||
ObjectMemHead* mh = NDO_MEMH_FROM_NDO(in);
|
||||
mh->refc++;
|
||||
}
|
||||
|
||||
void objects_api::setrefc(Object* in, tp::halni refc) {
|
||||
ObjectMemHead* mh = NDO_MEMH_FROM_NDO(in);
|
||||
mh->refc = refc;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void hierarchy_copy(Object* self, const Object* in, const ObjectType* type) {
|
||||
if (type->base) {
|
||||
hierarchy_copy(self, in, type->base);
|
||||
}
|
||||
|
||||
if (type->copy) {
|
||||
type->copy(self, in);
|
||||
}
|
||||
}
|
||||
|
||||
void hierarchy_construct(Object* self, const ObjectType* type) {
|
||||
if (type->base) {
|
||||
hierarchy_construct(self, type->base);
|
||||
}
|
||||
|
||||
if (type->constructor) {
|
||||
type->constructor(self);
|
||||
}
|
||||
}
|
||||
|
||||
Object* ndo_cast(const Object* in, const ObjectType* to_type) {
|
||||
const ObjectType* typeiter = in->type;
|
||||
while (typeiter) {
|
||||
if (typeiter == to_type) {
|
||||
return (Object*) in;
|
||||
}
|
||||
typeiter = typeiter->base;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
objects_api* objects_init() {
|
||||
if (!NDO) {
|
||||
NDO = new objects_api();
|
||||
}
|
||||
|
||||
obj::BCgen::init();
|
||||
|
||||
return NDO;
|
||||
}
|
||||
|
||||
void objects_finalize() {
|
||||
|
||||
if (NDO) {
|
||||
delete NDO;
|
||||
}
|
||||
|
||||
obj::BCgen::deinit();
|
||||
}
|
||||
|
||||
};
|
||||
411
Objects/private/core/objectsave.cpp
Normal file
411
Objects/private/core/objectsave.cpp
Normal file
|
|
@ -0,0 +1,411 @@
|
|||
|
||||
|
||||
#include "core/object.h"
|
||||
|
||||
#include "HeapAllocatorGlobal.hpp"
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
namespace obj {
|
||||
|
||||
ObjectMemHead* bottom = nullptr;
|
||||
|
||||
struct ObjectsFileHeader {
|
||||
char name[10] = {0};
|
||||
char version[10] = {0};
|
||||
|
||||
ObjectsFileHeader(bool default_val = true) {
|
||||
if (default_val) {
|
||||
tp::memCopy(&name, "objects", tp::String::Logic::calcLength("objects") + 1);
|
||||
tp::memCopy(&version, "0", tp::String::Logic::calcLength("0") + 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Object* ObjectMemAllocate(const ObjectType* type) {
|
||||
ObjectMemHead* memh = (ObjectMemHead*) tp::HeapAllocGlobal::allocate(type->size + sizeof(ObjectMemHead));
|
||||
if (!memh) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memh->down = NULL;
|
||||
memh->flags = NULL;
|
||||
|
||||
#ifdef OBJECT_REF_COUNT
|
||||
memh->refc = (tp::alni) 1;
|
||||
#endif
|
||||
|
||||
if (bottom) {
|
||||
bottom->down = memh;
|
||||
}
|
||||
memh->up = bottom;
|
||||
bottom = memh;
|
||||
|
||||
NDO_FROM_MEMH(memh)->type = type;
|
||||
return NDO_FROM_MEMH(memh);
|
||||
}
|
||||
|
||||
void ObjectMemDeallocate(Object* in) {
|
||||
ObjectMemHead* memh = ((ObjectMemHead*) in) - 1;
|
||||
|
||||
if (memh->up) {
|
||||
memh->up->down = memh->down;
|
||||
}
|
||||
|
||||
if (memh->down) {
|
||||
memh->down->up = memh->up;
|
||||
} else {
|
||||
bottom = memh->up;
|
||||
}
|
||||
|
||||
tp::HeapAllocGlobal::deallocate(memh);
|
||||
}
|
||||
|
||||
struct ObjectFileHead {
|
||||
Object* load_head_adress = 0;
|
||||
tp::halni refc = 0;
|
||||
};
|
||||
|
||||
tp::int1* loaded_file = nullptr;
|
||||
|
||||
|
||||
void objects_api::clear_object_flags() {
|
||||
// clear all object flags
|
||||
for (ObjectMemHead* iter = bottom; iter; iter = iter->up) {
|
||||
iter->flags = -1;
|
||||
}
|
||||
}
|
||||
|
||||
tp::alni& getObjectFlags(Object* in) {
|
||||
return NDO_MEMH_FROM_NDO(in)->flags;
|
||||
}
|
||||
|
||||
tp::alni objsize_ram_util(Object* self, const ObjectType* type) {
|
||||
tp::alni out = 0;
|
||||
|
||||
if (type->allocated_size) {
|
||||
out += type->allocated_size(self);
|
||||
} else {
|
||||
out += type->size - sizeof(ObjectType*);
|
||||
}
|
||||
|
||||
if (type->base) {
|
||||
out += objsize_ram_util(self, type->base);
|
||||
} else {
|
||||
out += sizeof(ObjectType*);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
tp::alni objects_api::objsize_ram(Object* self) {
|
||||
return objsize_ram_util(self, self->type);
|
||||
}
|
||||
|
||||
tp::alni objects_api::objsize_ram_recursive_util(Object* self, const ObjectType* type, bool different_object) {
|
||||
tp::alni out = 0;
|
||||
|
||||
if (different_object) {
|
||||
if (getObjectFlags(self) == 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
getObjectFlags(self) = 1;
|
||||
}
|
||||
|
||||
if (type->allocated_size_recursive) {
|
||||
out += type->allocated_size_recursive(self);
|
||||
} else {
|
||||
if (type->allocated_size) {
|
||||
out += type->allocated_size(self);
|
||||
} else {
|
||||
out += type->size - sizeof(ObjectType*);
|
||||
}
|
||||
}
|
||||
|
||||
if (type->base) {
|
||||
out += objsize_ram_recursive_util(self, type->base, false);
|
||||
} else {
|
||||
out += sizeof(ObjectType*);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
tp::alni objects_api::objsize_ram_recursive(Object* self) {
|
||||
clear_object_flags();
|
||||
return objsize_ram_recursive_util(self, self->type);
|
||||
}
|
||||
|
||||
tp::alni objsize_file_util(Object* self, const ObjectType* type) {
|
||||
tp::alni out = 0;
|
||||
|
||||
if (type->save_size) {
|
||||
out += type->save_size(self);
|
||||
}
|
||||
|
||||
if (type->base) {
|
||||
out += objsize_file_util(self, type->base);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
tp::alni objects_api::objsize_file(Object* self) {
|
||||
return objsize_file_util(self, self->type);
|
||||
}
|
||||
|
||||
tp::alni objsize_file_recursive_util(Object* self, const ObjectType* type) {
|
||||
tp::alni out = 0;
|
||||
|
||||
getObjectFlags(self) = 1;
|
||||
|
||||
if (type->save_size) {
|
||||
out += type->save_size(self);
|
||||
}
|
||||
|
||||
if (type->childs_retrival) {
|
||||
tp::Buffer<Object*> childs = type->childs_retrival(self);
|
||||
for (auto child : childs) {
|
||||
if (getObjectFlags(child.data()) != 1) {
|
||||
out += objsize_file_recursive_util(child.data(), child.data()->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type->base) {
|
||||
out += objsize_file_recursive_util(self, type->base);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
tp::alni objects_api::objsize_file_recursive(Object* self) {
|
||||
clear_object_flags();
|
||||
return objsize_file_recursive_util(self, self->type);
|
||||
}
|
||||
|
||||
void object_recursive_save(Archiver& ndf, Object* self, const ObjectType* type) {
|
||||
if (type->base) {
|
||||
object_recursive_save(ndf, self, type->base);
|
||||
}
|
||||
|
||||
// automatically offsets for parent type to write
|
||||
if (type->save) {
|
||||
type->save(self, ndf);
|
||||
}
|
||||
}
|
||||
|
||||
tp::alni objects_api::save(Archiver& ndf, Object* in) {
|
||||
// if already saved return file_adress
|
||||
if (NDO_MEMH_FROM_NDO(in)->flags != -1) {
|
||||
return NDO_MEMH_FROM_NDO(in)->flags;
|
||||
}
|
||||
|
||||
// save write adress for parent save function call
|
||||
tp::alni tmp_adress = ndf.adress;
|
||||
|
||||
// save requested object to first available adress
|
||||
tp::alni save_adress = ndf.avl_adress;
|
||||
|
||||
// save file_adress in memhead
|
||||
NDO_MEMH_FROM_NDO(in)->flags = save_adress;
|
||||
|
||||
// update write adress
|
||||
ndf.adress = save_adress;
|
||||
|
||||
// save file object header
|
||||
ObjectFileHead ofh = { 0, getrefc(in) };
|
||||
ndf.write(&ofh);
|
||||
tp::String(in->type->name).save(&ndf);
|
||||
|
||||
// allocate for object file header
|
||||
ndf.avl_adress += sizeof(ObjectFileHead) + tp::String::Logic::calcLength(in->type->name) + 1;
|
||||
|
||||
// calc max size needed for saving all hierarchy of types
|
||||
tp::alni file_alloc_size = objsize_file_util(in, in->type);
|
||||
|
||||
// offes first available adress
|
||||
ndf.avl_adress += file_alloc_size;
|
||||
|
||||
object_recursive_save(ndf, in, in->type);
|
||||
|
||||
// restore adress for parent save function
|
||||
ndf.adress = tmp_adress;
|
||||
|
||||
// return addres of saved object in file space
|
||||
return save_adress;
|
||||
}
|
||||
|
||||
void object_recursive_load(Archiver& ndf, Object* out, const ObjectType* type) {
|
||||
if (type->base) {
|
||||
object_recursive_load(ndf, out, type->base);
|
||||
}
|
||||
|
||||
// automatically offsets for parent type to read
|
||||
if (type->load) {
|
||||
type->load(ndf, out);
|
||||
}
|
||||
}
|
||||
|
||||
Object* objects_api::load(Archiver& ndf, tp::alni file_adress) {
|
||||
// check if already saved
|
||||
if (((ObjectFileHead*) (loaded_file + file_adress))->load_head_adress) {
|
||||
return ((ObjectFileHead*) (loaded_file + file_adress))->load_head_adress;
|
||||
}
|
||||
|
||||
// save read adress
|
||||
tp::alni parent_file_adress = ndf.adress;
|
||||
|
||||
// set read adress
|
||||
ndf.adress = file_adress;
|
||||
|
||||
ObjectFileHead ofh;
|
||||
ndf.read<ObjectFileHead>(&ofh);
|
||||
tp::String type_name;
|
||||
type_name.load(&ndf);
|
||||
|
||||
const ObjectType* object_type = NDO->types.get(type_name);
|
||||
Object* out = ObjectMemAllocate(object_type);
|
||||
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
setrefc(out, ofh.refc);
|
||||
|
||||
// save heap adress in "loaded_file"
|
||||
((ObjectFileHead*) (loaded_file + file_adress))->load_head_adress = out;
|
||||
|
||||
// loads recursivelly
|
||||
object_recursive_load(ndf, out, object_type);
|
||||
|
||||
// restore read adress for parent call to continue
|
||||
ndf.adress = parent_file_adress;
|
||||
|
||||
// return heap memory adress
|
||||
return out;
|
||||
}
|
||||
|
||||
bool objects_api::save(Object* in, tp::String path, bool compressed) {
|
||||
Archiver ndf(path.read(), Archiver::SAVE);
|
||||
|
||||
if (!ndf.opened) {
|
||||
return false;
|
||||
}
|
||||
|
||||
clear_object_flags();
|
||||
|
||||
// save vesion info
|
||||
ObjectsFileHeader header;
|
||||
ndf.write(&header);
|
||||
|
||||
ndf.avl_adress = ndf.adress;
|
||||
|
||||
// pre allocate
|
||||
for (tp::alni i = 0; i < SAVE_LOAD_MAX_CALLBACK_SLOTS; i++) {
|
||||
if (sl_callbacks[i]) {
|
||||
DEBUG_ASSERT(sl_callbacks[i]->size);
|
||||
ndf.avl_adress += sl_callbacks[i]->size(sl_callbacks[i]->self, ndf);
|
||||
}
|
||||
}
|
||||
|
||||
// presave
|
||||
for (tp::alni i = 0; i < SAVE_LOAD_MAX_CALLBACK_SLOTS; i++) {
|
||||
if (sl_callbacks[i] && sl_callbacks[i]->pre_save) {
|
||||
sl_callbacks[i]->pre_save(sl_callbacks[i]->self, ndf);
|
||||
}
|
||||
}
|
||||
|
||||
save(ndf, in);
|
||||
|
||||
// postsave
|
||||
for (tp::alni i = 0; i < SAVE_LOAD_MAX_CALLBACK_SLOTS; i++) {
|
||||
if (sl_callbacks[i] && sl_callbacks[i]->post_save) {
|
||||
sl_callbacks[i]->post_save(sl_callbacks[i]->self, ndf);
|
||||
}
|
||||
}
|
||||
|
||||
ndf.disconnect();
|
||||
|
||||
// TODO : add compression
|
||||
/*
|
||||
if (compressed) {
|
||||
auto temp = path + ".bz2";
|
||||
tp::compressF2F(path.read(), temp.cstr());
|
||||
|
||||
File::remove(path.read());
|
||||
File::rename(temp.cstr(), path.read());
|
||||
}
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Object* objects_api::load(tp::String path) {
|
||||
/*
|
||||
auto temp_file_name = path + ".unz";
|
||||
bool unz_res = tp::decompressF2F(path.cstr(), temp_file_name.cstr());
|
||||
|
||||
if (!unz_res) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
File ndf(temp_file_name.cstr(), tp::osfile_openflags::LOAD);
|
||||
*/
|
||||
|
||||
Archiver ndf(path.read(), Archiver::LOAD);
|
||||
|
||||
if (!ndf.opened) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// check for compability
|
||||
ObjectsFileHeader current_header;
|
||||
ObjectsFileHeader loaded_header(false);
|
||||
ndf.read(&loaded_header);
|
||||
if (!tp::memEqual(¤t_header, &loaded_header, sizeof(ObjectsFileHeader))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ndf.adress = 0;
|
||||
loaded_file = (tp::int1*) malloc(ndf.size());
|
||||
ndf.read_bytes(loaded_file, ndf.size());
|
||||
ndf.adress = sizeof(ObjectsFileHeader);
|
||||
|
||||
// preload
|
||||
for (tp::alni i = 0; i < SAVE_LOAD_MAX_CALLBACK_SLOTS; i++) {
|
||||
if (sl_callbacks[i] && sl_callbacks[i]->pre_load) {
|
||||
sl_callbacks[i]->pre_load(sl_callbacks[i]->self, ndf);
|
||||
}
|
||||
}
|
||||
|
||||
Object* out = load(ndf, ndf.adress);
|
||||
|
||||
// post
|
||||
for (tp::alni i = 0; i < SAVE_LOAD_MAX_CALLBACK_SLOTS; i++) {
|
||||
if (sl_callbacks[i] && sl_callbacks[i]->post_save) {
|
||||
sl_callbacks[i]->post_load(sl_callbacks[i]->self, ndf);
|
||||
}
|
||||
}
|
||||
|
||||
free(loaded_file);
|
||||
|
||||
/*
|
||||
ndf.close();
|
||||
|
||||
if (unz_res == NULL) {
|
||||
File::remove(temp_file_name.cstr());
|
||||
}
|
||||
*/
|
||||
|
||||
setrefc(out, 0);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void objects_api::add_sl_callbacks(save_load_callbacks* in) {
|
||||
sl_callbacks[sl_callbacks_load_idx] = in;
|
||||
sl_callbacks_load_idx++;
|
||||
}
|
||||
};
|
||||
265
Objects/private/core/scriptsection.cpp
Normal file
265
Objects/private/core/scriptsection.cpp
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
|
||||
#include "NewPlacement.hpp"
|
||||
#include "HeapAllocatorGlobal.hpp"
|
||||
|
||||
#include "core/scriptsection.h"
|
||||
|
||||
using namespace obj;
|
||||
|
||||
ScriptSection* gScriptSection = NULL;
|
||||
|
||||
struct script_data_head {
|
||||
tp::alni refc = 0;
|
||||
tp::alni store_adress = 0;
|
||||
};
|
||||
|
||||
void set_script_head_store_adress(Script* in, tp::alni address) {
|
||||
((script_data_head*)in - 1)->store_adress = address;
|
||||
}
|
||||
|
||||
tp::alni get_script_head_store_adress(Script* in) {
|
||||
return ((script_data_head*)in - 1)->store_adress;
|
||||
}
|
||||
|
||||
Script* ScriptSection::createScript() {
|
||||
auto sdhead = (script_data_head*)tp::HeapAllocGlobal::allocate(sizeof(script_data_head) + sizeof(Script));
|
||||
auto out = (Script*)(sdhead + 1);
|
||||
|
||||
if (!sdhead) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sdhead->refc = 1;
|
||||
sdhead->store_adress = -1;
|
||||
|
||||
mScripts.pushBack(out);
|
||||
|
||||
new (out) Script();
|
||||
out->mReadable = obj::StringObject::create("");
|
||||
obj::NDO->refinc(out->mReadable);
|
||||
return out;
|
||||
}
|
||||
|
||||
void ScriptSection::delete_script(Script* script) {
|
||||
script->~Script();
|
||||
obj::NDO->destroy(script->mReadable);
|
||||
|
||||
tp::HeapAllocGlobal::deallocate((((script_data_head*)script) - 1));
|
||||
}
|
||||
|
||||
void ScriptSection::reference_script(Script* script) {
|
||||
(((script_data_head*)script) - 1)->refc++;
|
||||
}
|
||||
|
||||
void ScriptSection::abandonScript(Script* script) {
|
||||
if ((((script_data_head*)script) - 1)->refc > 1) {
|
||||
(((script_data_head*)script) - 1)->refc--;
|
||||
}
|
||||
else {
|
||||
// ISSUE : on delete list structure is outdated
|
||||
// FIXME : use pool alloc with ref count
|
||||
// forwarding to global destruction
|
||||
//delete_script(script);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptSection::changeScript(Script** current_script, Script** new_script) {
|
||||
abandonScript(*current_script);
|
||||
reference_script(*new_script);
|
||||
|
||||
*current_script = *new_script;
|
||||
}
|
||||
|
||||
tp::alni ScriptSection::get_script_file_adress(Script* in) {
|
||||
return get_script_head_store_adress(in);
|
||||
}
|
||||
|
||||
tp::alni ScriptSection::save_script_table_to_file_size(ScriptSection* self, Archiver& file) {
|
||||
tp::alni size = 0;
|
||||
size += 5; // header
|
||||
size += sizeof(tp::alni); // scripts length
|
||||
|
||||
for (auto iter : self->mScripts) {
|
||||
|
||||
set_script_head_store_adress(iter.data(), file.adress + size);
|
||||
|
||||
size += sizeof(tp::alni); // scripts string obj ref
|
||||
size += sizeof(tp::alni); // constants length
|
||||
|
||||
for (auto const_obj : iter->mBytecode.mConstants) {
|
||||
size += sizeof(tp::alni); // constant object addres
|
||||
}
|
||||
|
||||
// instructions
|
||||
size += iter->mBytecode.mInstructions.saveSize();
|
||||
}
|
||||
|
||||
size += sizeof(tp::alni); // objects mem offset
|
||||
size += 5; // header
|
||||
return size;
|
||||
}
|
||||
|
||||
void ScriptSection::save_script_table_to_file(ScriptSection* self, Archiver& file) {
|
||||
// header
|
||||
file.write_bytes("/scr/", 5);
|
||||
|
||||
// scripts length
|
||||
tp::alni scripts_count = self->mScripts.length();
|
||||
file.write<tp::alni>(&scripts_count);
|
||||
|
||||
for (auto iter : self->mScripts) {
|
||||
|
||||
// scripts string obj ref
|
||||
auto obj_addres = obj::NDO->save(file, iter->mReadable);
|
||||
file.write(&obj_addres);
|
||||
|
||||
// constants length
|
||||
tp::alni consts_count = iter->mBytecode.mConstants.size();
|
||||
file.write<tp::alni>(&consts_count);
|
||||
|
||||
for (auto const_obj : iter->mBytecode.mConstants) {
|
||||
// constant object addres
|
||||
auto obj_addres = obj::NDO->save(file, const_obj.data());
|
||||
file.write(&obj_addres);
|
||||
}
|
||||
|
||||
// mInstructions
|
||||
iter->mBytecode.mInstructions.save(file);
|
||||
}
|
||||
|
||||
// header
|
||||
file.write_bytes("/scr/", 5);
|
||||
|
||||
tp::alni objects_mem_offset = file.avl_adress;
|
||||
file.write<tp::alni>(&objects_mem_offset);
|
||||
}
|
||||
|
||||
void load_constants(ScriptSection* self, Archiver& file, tp::alni start_addr) {
|
||||
auto addres = file.adress;
|
||||
|
||||
file.adress = start_addr;
|
||||
file.adress += 5; // header
|
||||
|
||||
tp::alni scripts_count;
|
||||
file.read<tp::alni>(&scripts_count);
|
||||
|
||||
for (tp::alni i = 0; i < scripts_count; i++) {
|
||||
|
||||
auto script = self->get_scritp_from_file_adress(file.adress);
|
||||
|
||||
// script text
|
||||
tp::alni str_addr;
|
||||
file.read<tp::alni>(&str_addr);
|
||||
script->mReadable = NDO_CAST(obj::StringObject, obj::NDO->load(file, str_addr));
|
||||
|
||||
file.adress += sizeof(tp::alni); // constants length
|
||||
|
||||
for (auto const_obj : script->mBytecode.mConstants) {
|
||||
tp::alni consts_addr;
|
||||
file.read<tp::alni>(&consts_addr);
|
||||
const_obj.data() = obj::NDO->load(file, consts_addr);
|
||||
}
|
||||
|
||||
// instructions
|
||||
file.adress += script->mBytecode.mInstructions.saveSize();
|
||||
}
|
||||
|
||||
file.adress = addres;
|
||||
}
|
||||
|
||||
void ScriptSection::load_script_table_from_file(ScriptSection* self, Archiver& file) {
|
||||
for (auto iter : self->mScripts) {
|
||||
set_script_head_store_adress(iter.data(), -1);
|
||||
}
|
||||
|
||||
auto section_start_addr = file.adress;
|
||||
|
||||
// header
|
||||
file.adress += 5;
|
||||
|
||||
// scripts length
|
||||
tp::alni scripts_count;
|
||||
file.read<tp::alni>(&scripts_count);
|
||||
|
||||
for (tp::alni i = 0; i < scripts_count; i++) {
|
||||
|
||||
auto new_script = self->createScript();
|
||||
set_script_head_store_adress(new_script, file.adress);
|
||||
|
||||
// scripts text
|
||||
file.adress += sizeof(tp::alni);
|
||||
|
||||
// constants length
|
||||
tp::alni consts_count;
|
||||
file.read<tp::alni>(&consts_count);
|
||||
|
||||
new_script->mBytecode.mConstants.reserve(consts_count);
|
||||
|
||||
for (tp::alni j = 0; j < consts_count; j++) {
|
||||
// constant object addres
|
||||
tp::alni consts_addr;
|
||||
file.read<tp::alni>(&consts_addr);
|
||||
|
||||
// skiping
|
||||
//new_script->mBytecode.mConstants[j] = obj::NDO->load(file, consts_addr);
|
||||
}
|
||||
|
||||
// mInstructions
|
||||
new_script->mBytecode.mInstructions.load(file);
|
||||
}
|
||||
|
||||
load_constants(self, file, section_start_addr);
|
||||
|
||||
// header
|
||||
file.adress += 5;
|
||||
|
||||
tp::alni objects_mem_offset;
|
||||
file.read<tp::alni>(&objects_mem_offset);
|
||||
|
||||
file.adress = objects_mem_offset;
|
||||
}
|
||||
|
||||
Script* ScriptSection::get_scritp_from_file_adress(tp::alni file_adress) {
|
||||
for (auto iter : mScripts) {
|
||||
if (get_script_head_store_adress(iter.data()) == file_adress) {
|
||||
return iter.data();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ScriptSection::~ScriptSection() {
|
||||
for (auto iter : mScripts) {
|
||||
delete_script(iter.data());
|
||||
}
|
||||
}
|
||||
|
||||
obj::save_load_callbacks ScriptSection::slcb_script_section = {
|
||||
.self = gScriptSection,
|
||||
.pre_save = (obj::pre_save_callback*)ScriptSection::save_script_table_to_file,
|
||||
.size = (obj::slcb_size_callback*)ScriptSection::save_script_table_to_file_size,
|
||||
.pre_load = (obj::pre_load_callback*)ScriptSection::load_script_table_from_file,
|
||||
.post_save = NULL,
|
||||
.post_load = NULL,
|
||||
};
|
||||
|
||||
|
||||
void ScriptSection::initialize() {
|
||||
ASSERT(!gScriptSection);
|
||||
gScriptSection = new ScriptSection();
|
||||
|
||||
ASSERT(obj::NDO && "Forgot to initialize objects?");
|
||||
|
||||
slcb_script_section.self = gScriptSection;
|
||||
obj::NDO->add_sl_callbacks(&slcb_script_section);
|
||||
}
|
||||
|
||||
void ScriptSection::uninitialize() {
|
||||
ASSERT(gScriptSection);
|
||||
delete gScriptSection;
|
||||
}
|
||||
|
||||
ScriptSection* ScriptSection::globalHandle() {
|
||||
return gScriptSection;
|
||||
}
|
||||
|
||||
81
Objects/private/core/typegroups.cpp
Normal file
81
Objects/private/core/typegroups.cpp
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
|
||||
#include "NewPlacement.hpp"
|
||||
|
||||
#include "core/typegroups.h"
|
||||
|
||||
#include "core/object.h"
|
||||
|
||||
using namespace obj;
|
||||
|
||||
obj::TypeGroups::TypeGroups() : is_group(true) {
|
||||
new (&childs) Dict();
|
||||
}
|
||||
|
||||
obj::TypeGroups::TypeGroups(bool is_group) : is_group(is_group) {
|
||||
if (is_group) {
|
||||
new (&childs) Dict();
|
||||
} else {
|
||||
type = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool obj::TypeGroups::isGroup() { return is_group; }
|
||||
|
||||
obj::TypeGroups::Dict* obj::TypeGroups::getChilds() {
|
||||
DEBUG_ASSERT(is_group);
|
||||
return &childs;
|
||||
}
|
||||
|
||||
void obj::TypeGroups::setType(ObjectType* type) {
|
||||
DEBUG_ASSERT(!is_group);
|
||||
this->type = type;
|
||||
}
|
||||
|
||||
void obj::TypeGroups::addType(ObjectType* type, tp::init_list<const char*> path, tp::alni cur_dir_idx) {
|
||||
DEBUG_ASSERT(is_group);
|
||||
|
||||
tp::alni dir_len = (tp::alni) path.size();
|
||||
|
||||
if (dir_len == cur_dir_idx) {
|
||||
TypeGroups* type_ref = new TypeGroups(false);
|
||||
type_ref->setType(type);
|
||||
childs.put(type->name, type_ref);
|
||||
return;
|
||||
}
|
||||
|
||||
TypeGroups* group = NULL;
|
||||
tp::alni index = 0;
|
||||
|
||||
for (auto dir : path) {
|
||||
if (index != cur_dir_idx) {
|
||||
index++;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto child_idx = childs.presents(dir);
|
||||
if (child_idx) {
|
||||
group = childs.getSlotVal(child_idx);
|
||||
} else {
|
||||
group = new TypeGroups(true);
|
||||
childs.put(dir, group);
|
||||
}
|
||||
|
||||
group->addType(type, path, cur_dir_idx + 1);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const obj::ObjectType* obj::TypeGroups::getType() {
|
||||
DEBUG_ASSERT(!is_group);
|
||||
return type;
|
||||
}
|
||||
|
||||
obj::TypeGroups::~TypeGroups() {
|
||||
if (is_group) {
|
||||
for (auto& child : childs) {
|
||||
delete child->val;
|
||||
}
|
||||
childs.~Map();
|
||||
}
|
||||
}
|
||||
138
Objects/private/core/typemethods.cpp
Normal file
138
Objects/private/core/typemethods.cpp
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
|
||||
#include "NewPlacement.hpp"
|
||||
|
||||
#include "core/typemethods.h"
|
||||
|
||||
#include "primitives/nullobject.h"
|
||||
#include "primitives/typeobject.h"
|
||||
#include "primitives/floatobject.h"
|
||||
|
||||
#include "interpreter/interpreter.h"
|
||||
|
||||
|
||||
using namespace obj;
|
||||
|
||||
TypeMethod obj::gDefaultTypeMethods[] = {
|
||||
{
|
||||
.nameid = "type",
|
||||
.descr = "retrieves typeobject",
|
||||
.exec = [](const TypeMethod* tm) {
|
||||
tm->ret.obj = TypeObject::create(tm->self->type);
|
||||
},
|
||||
.ret = { "typeobject", NULL },
|
||||
},
|
||||
{
|
||||
.nameid = "to_str",
|
||||
.descr = "converts to string",
|
||||
.exec = [](const TypeMethod* tm) {
|
||||
if (tm->self->type->convesions && tm->self->type->convesions->to_string) {
|
||||
tm->ret.obj = StringObject::create(NDO->toString(tm->self));
|
||||
}
|
||||
},
|
||||
.ret = { "string object", NULL },
|
||||
},
|
||||
{
|
||||
.nameid = "to_float",
|
||||
.descr = "converts to float",
|
||||
.exec = [](const TypeMethod* tm) {
|
||||
if (tm->self->type->convesions && tm->self->type->convesions->to_float) {
|
||||
tm->ret.obj = FloatObject::create(NDO->toFloat(tm->self));
|
||||
}
|
||||
},
|
||||
.ret = { "string object", NULL },
|
||||
},
|
||||
};
|
||||
|
||||
tp::int2 TypeMethods::presents(tp::String id) const {
|
||||
for (tp::int2 idx = 0; idx < mNMethods; idx++) {
|
||||
if (id == methods[idx]->nameid) {
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
|
||||
tp::int2 idx = 0;
|
||||
for (auto& tm : gDefaultTypeMethods) {
|
||||
if (id == tm.nameid) {
|
||||
return { tp::int2(idx + MAX_TYPE_METHODS) };
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
TypeMethods::LookupKey TypeMethods::presents(const ObjectType* type, tp::string id) {
|
||||
|
||||
tp::int2 depth = 0;
|
||||
tp::int2 idx = 0;
|
||||
|
||||
for (auto iter_type = type; iter_type; iter_type = iter_type->base) {
|
||||
idx = iter_type->type_methods.presents(id);
|
||||
if (idx != -1) {
|
||||
break;
|
||||
}
|
||||
depth++;
|
||||
}
|
||||
|
||||
return { idx, depth};
|
||||
}
|
||||
|
||||
const TypeMethod* TypeMethods::getMethod(tp::int2 key) const {
|
||||
if (key < MAX_TYPE_METHODS) {
|
||||
return methods[key];
|
||||
}
|
||||
return &gDefaultTypeMethods[key - MAX_TYPE_METHODS];
|
||||
}
|
||||
|
||||
const TypeMethod* TypeMethods::getMethod(const ObjectType* type, LookupKey key) {
|
||||
auto type_iter = type;
|
||||
for (auto idx = 0; idx < key.type_depth; idx++) {
|
||||
type_iter = type_iter->base;
|
||||
}
|
||||
return type_iter->type_methods.getMethod(key.key);
|
||||
}
|
||||
|
||||
void TypeMethods::init() {
|
||||
while (methods[mNMethods]) {
|
||||
mNMethods++;
|
||||
}
|
||||
|
||||
for (tp::int1 i = 0; i < mNMethods; i++) {
|
||||
methods[i]->init();
|
||||
}
|
||||
|
||||
// initialize and use finate state automata to lookup methods
|
||||
}
|
||||
|
||||
tp::halni TypeMethods::nMethods() const {
|
||||
return mNMethods;
|
||||
}
|
||||
|
||||
void TypeMethod::operator()(Interpreter* interp) const{
|
||||
for (auto i = 1; i <= mNargs; i++) {
|
||||
args[mNargs - i].obj = interp->mOperandsStack.getOperand();
|
||||
//NDO->refinc(args[i].obj);
|
||||
ASSERT(args[mNargs - i].obj && "expected an argument");
|
||||
}
|
||||
|
||||
ASSERT(!interp->mOperandsStack.getOperand() && "args remained");
|
||||
interp->mOperandsStack.getOperand();
|
||||
|
||||
self = interp->mLastParent;
|
||||
|
||||
exec(this);
|
||||
|
||||
if (ret.obj) {
|
||||
interp->mOperandsStack.push(ret.obj);
|
||||
interp->mScopeStack.addTempReturn(ret.obj);
|
||||
}
|
||||
else {
|
||||
interp->mOperandsStack.push(NDO_NULL_REF);
|
||||
}
|
||||
}
|
||||
|
||||
void TypeMethod::init() {
|
||||
while (args[mNargs].descr) {
|
||||
mNargs++;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
904
Objects/private/parser/parser.cpp
Normal file
904
Objects/private/parser/parser.cpp
Normal file
|
|
@ -0,0 +1,904 @@
|
|||
|
||||
#include "Logging.hpp"
|
||||
#include "List.hpp"
|
||||
|
||||
#include "parser/parser.h"
|
||||
#include "compiler/function.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#define MAX_STREAM_LENGTH 1024 * 8 * 200
|
||||
|
||||
#define REQUIRE(expr, desc, on_catch) DEBUG_BREAK(mRes.err); if (!(expr)) { mRes.err = new Error(desc, mTok.getCursorPrev().mAdvancedOffset); on_catch; return NULL; }
|
||||
#define CHECK(expr, on_catch) if (!(expr)) { on_catch; return NULL; }
|
||||
#define CHECK_ERROR(value, on_catch) if (mRes.err || !value) { on_catch; return NULL; }
|
||||
|
||||
using namespace tp;
|
||||
using namespace obj;
|
||||
using namespace BCgen;
|
||||
|
||||
bool Parser::Token::isAriphm() {
|
||||
switch (type) {
|
||||
case Token::ADD:
|
||||
case Token::SUB:
|
||||
case Token::DIV:
|
||||
case Token::MUL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Parser::Token::isBoolean() {
|
||||
switch (type) {
|
||||
case Token::EQUAL:
|
||||
case Token::NOT_EQUAL:
|
||||
case Token::BOOL_AND:
|
||||
case Token::BOOL_OR:
|
||||
case Token::MORE:
|
||||
case Token::LESS:
|
||||
case Token::QE_OR_MORE:
|
||||
case Token::QE_OR_LESS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Parser::Parser() {
|
||||
mTok.build({
|
||||
{ "\n|\t| |\r", Token::SPACE },
|
||||
{ "var", Token::VAR },
|
||||
{ "class", Token::CLASS_DEF },
|
||||
{ "self", Token::SELF },
|
||||
{ "\\{", Token::SCOPE_IN },
|
||||
{ "\\}", Token::SCOPE_OUT },
|
||||
{ "=", Token::ASSIGN },
|
||||
{ "def", Token::DEF_FUNC },
|
||||
{ "<<", Token::PRINT },
|
||||
{ "if", Token::IF },
|
||||
{ "else", Token::ELSE },
|
||||
{ "while", Token::WHILE },
|
||||
{ "\\(", Token::BRACKET_IN },
|
||||
{ "\\)", Token::BRACKET_OUT },
|
||||
{ ",", Token::COMMA },
|
||||
{ "new", Token::NEW },
|
||||
{ "\\.", Token::CHILD },
|
||||
{ "return", Token::RETURN },
|
||||
{ "==", Token::EQUAL },
|
||||
{ "!=", Token::NOT_EQUAL },
|
||||
{ ">", Token::MORE },
|
||||
{ "<", Token::LESS },
|
||||
{ ">=", Token::QE_OR_MORE },
|
||||
{ "<=", Token::QE_OR_LESS },
|
||||
{ "!", Token::BOOL_NOT },
|
||||
{ "&&", Token::BOOL_AND },
|
||||
{ "\\|\\|", Token::BOOL_OR },
|
||||
{ "\\+", Token::ADD },
|
||||
{ "\\*", Token::MUL },
|
||||
{ "\\-", Token::SUB },
|
||||
{ "/", Token::DIV },
|
||||
{ ";", Token::STM_END },
|
||||
{ "true", Token::CONST_TRUE },
|
||||
{ "false", Token::CONST_FALSE },
|
||||
{ "((\\-)|(\\+))?[0-9]+i?", Token::CONST_INT },
|
||||
{ "((\\-)|(\\+))?([0-9]+)(\\.)([0-9]*)?f?", Token::CONST_FLOAT },
|
||||
{ "(/\\*){\\*-\\*}*(\\*/)", Token::COMMENT_BLOCK },
|
||||
{ "\"{\"-\"}*\"", Token::CONST_STRING },
|
||||
{ "([a-z]|[A-Z]|_)+([a-z]|[A-Z]|[0-9]|_)*", Token::ID },
|
||||
});
|
||||
}
|
||||
|
||||
tp::String to_string(const char* stream, tp::alni len) {
|
||||
tp::String out;
|
||||
out.reserve(len + 1);
|
||||
tp::memcp(out.get_writable(), stream, len);
|
||||
out.get_writable()[len] = '\0';
|
||||
return out;
|
||||
}
|
||||
|
||||
Parser::Token Parser::tokRead() {
|
||||
Token out;
|
||||
|
||||
if (!tokInputLeft()) {
|
||||
Token out;
|
||||
out.type = Token::NO_TOKEN;
|
||||
return out;
|
||||
}
|
||||
|
||||
auto crs_start = mTok.getCursor();
|
||||
out.type = mTok.readTok();
|
||||
out.token = to_string(crs_start.str(), mTok.lastTokLEn());
|
||||
|
||||
switch (out.type) {
|
||||
case Token::CONST_FALSE:
|
||||
out.boolean = false;
|
||||
break;
|
||||
case Token::CONST_TRUE:
|
||||
out.boolean = true;
|
||||
break;
|
||||
case Token::CONST_INT: {
|
||||
char* p_end;
|
||||
out.integer = std::strtol(out.token.read(), &p_end, 10);
|
||||
DEBUG_ASSERT(out.token.read() != p_end);
|
||||
break;
|
||||
}
|
||||
case Token::CONST_FLOAT: {
|
||||
char* p_end;
|
||||
out.floating = std::strtod(out.token.read(), &p_end);
|
||||
DEBUG_ASSERT(out.token.read() != p_end);
|
||||
break;
|
||||
}
|
||||
case Token::CONST_STRING: {
|
||||
out.str = to_string(crs_start.str() + 1, mTok.lastTokLEn() - 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
Parser::Token Parser::tokLookup() {
|
||||
auto crs = mTok.getCursor();
|
||||
auto out = tokRead();
|
||||
mTok.setCursor(crs);
|
||||
return out;
|
||||
}
|
||||
|
||||
bool Parser::tokInputLeft() {
|
||||
auto type = mTok.lookupTok();
|
||||
|
||||
while (mTok.isInputLeft() && type == Token::SPACE || (type >= Token::__END__ && type <= Token::__START__)) {
|
||||
mTok.skipTok();
|
||||
type = mTok.lookupTok();
|
||||
}
|
||||
|
||||
return type != Token::SOURCE_END_TOKEN;
|
||||
}
|
||||
|
||||
void Parser::tokSkip() {
|
||||
if (!tokInputLeft()) {
|
||||
return;
|
||||
}
|
||||
mTok.skipTok();
|
||||
}
|
||||
|
||||
Parser::Tokenizer::Cursor Parser::tokGetCursor() { return mTok.getCursor();}
|
||||
void Parser::tokSetCursor(Tokenizer::Cursor crs) { mTok.setCursor(crs); }
|
||||
|
||||
Expression* Parser::parseExprCompound() {
|
||||
CHECK(tokRead() == Token::BRACKET_IN, {});
|
||||
auto ret = parseExpr();
|
||||
CHECK_ERROR(ret, {});
|
||||
REQUIRE(tokRead() == Token::BRACKET_OUT, "Expected Closing Bracket", {});
|
||||
return ret;
|
||||
}
|
||||
|
||||
Expression* Parser::parseExprNEW() {
|
||||
CHECK(tokRead() == Token::NEW, {});
|
||||
auto name = tokRead();
|
||||
REQUIRE(name == Token::ID, "Expected Identifier", {});
|
||||
|
||||
REQUIRE(tokRead() == Token::BRACKET_IN, "Expected opening brackets", {});
|
||||
REQUIRE(tokRead() == Token::BRACKET_OUT, "Expected closing brackets", {});
|
||||
|
||||
return ExprNew(name.token);
|
||||
}
|
||||
|
||||
Expression* Parser::parseExprLOCAL() {
|
||||
auto local_id_tok = tokRead();
|
||||
if (local_id_tok == Token::ID) {
|
||||
return ExprLocal(local_id_tok.token);
|
||||
}
|
||||
else if (local_id_tok == Token::SELF) {
|
||||
return ExprSelf();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Expression* Parser::parseExprCONST() {
|
||||
auto tok = tokRead();
|
||||
switch (tok) {
|
||||
case Token::CONST_FALSE:
|
||||
return ExprConst(false);
|
||||
case Token::CONST_TRUE:
|
||||
return ExprConst(true);
|
||||
case Token::CONST_INT:
|
||||
return ExprConst(tok.integer);
|
||||
case Token::CONST_FLOAT:
|
||||
return ExprConst(tok.floating);
|
||||
case Token::CONST_STRING:
|
||||
return ExprConst(tok.str);
|
||||
default:
|
||||
REQUIRE(0, "not a const Expr", {});
|
||||
}
|
||||
}
|
||||
|
||||
Expression* Parser::parseExprCHILD(Expression* prnt) {
|
||||
CHECK(tokRead() == Token::CHILD, {});
|
||||
auto id = tokRead();
|
||||
REQUIRE(id == Token::ID, "Exprected Identifier", {});
|
||||
return prnt->ExprChild(id.str);
|
||||
}
|
||||
|
||||
Expression* Parser::parseExprCALL(Expression* prnt) {
|
||||
CHECK(tokRead() == Token::BRACKET_IN, {});
|
||||
|
||||
List<Expression*> args;
|
||||
|
||||
READ_ARG:
|
||||
Expression* expr = NULL;
|
||||
auto tok = tokLookup();
|
||||
REQUIRE(tok != Token::NO_TOKEN, "Missing Closing Bracket", {});
|
||||
|
||||
if (tok != Token::BRACKET_OUT) {
|
||||
|
||||
expr = parseExpr();
|
||||
CHECK_ERROR(expr, {
|
||||
for (auto arg : args) {
|
||||
delete arg.data();
|
||||
}
|
||||
});
|
||||
|
||||
args.pushBack(expr);
|
||||
|
||||
tok = tokLookup();
|
||||
if (tok == Token::COMMA) {
|
||||
tokSkip();
|
||||
goto READ_ARG;
|
||||
}
|
||||
else if (tok != Token::BRACKET_OUT) {
|
||||
for (auto arg : args) {
|
||||
delete arg.data();
|
||||
}
|
||||
REQUIRE(0, "Expected A Closing Bracket", {});
|
||||
}
|
||||
}
|
||||
tokSkip();
|
||||
|
||||
auto out = prnt->ExprCall({});
|
||||
out->mArgs.reserve(args.length());
|
||||
|
||||
for (auto arg : args) {
|
||||
out->mArgs[arg.idx()] = arg.data();
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
Expression* Parser::parseExprAriphm() {
|
||||
|
||||
tp::init_list<ExprType> expessions = {
|
||||
ExprType::Compound,
|
||||
ExprType::NEW,
|
||||
ExprType::LOCAL,
|
||||
ExprType::CONST,
|
||||
};
|
||||
|
||||
Expression* left = parseExpr(expessions);
|
||||
CHECK_ERROR(left, {});
|
||||
|
||||
Expression* ret = NULL;
|
||||
|
||||
PARSE:
|
||||
|
||||
Expression* right = NULL;
|
||||
|
||||
auto tok = tokLookup();
|
||||
if (tok.isAriphm()) {
|
||||
tokSkip();
|
||||
|
||||
|
||||
right = parseExpr(expessions);
|
||||
|
||||
if (mRes.err) {
|
||||
if (ret) {
|
||||
goto PRECEDENCE;
|
||||
}
|
||||
|
||||
delete left;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
CHECK(ret, {
|
||||
delete left;
|
||||
});
|
||||
goto PRECEDENCE;
|
||||
}
|
||||
|
||||
switch (tok) {
|
||||
case Token::ADD:
|
||||
ret = ExprAriphm(left, right, OpCode::OBJ_ADD);
|
||||
break;
|
||||
case Token::SUB:
|
||||
ret = ExprAriphm(left, right, OpCode::OBJ_SUB);
|
||||
break;
|
||||
case Token::DIV:
|
||||
ret = ExprAriphm(left, right, OpCode::OBJ_DIV);
|
||||
break;
|
||||
case Token::MUL:
|
||||
ret = ExprAriphm(left, right, OpCode::OBJ_MUL);
|
||||
}
|
||||
|
||||
left = ret;
|
||||
goto PARSE;
|
||||
|
||||
PRECEDENCE:
|
||||
// FIXME: Not Implemented
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Expression* Parser::parseExprBOOLEAN() {
|
||||
|
||||
tp::init_list<ExprType> expessions = {
|
||||
ExprType::Compound,
|
||||
ExprType::NEW,
|
||||
ExprType::LOCAL,
|
||||
ExprType::CONST,
|
||||
ExprType::BOOLEAN_NOT,
|
||||
};
|
||||
|
||||
|
||||
Expression* left = parseExpr(expessions);
|
||||
CHECK_ERROR(left, {});
|
||||
|
||||
Expression* ret = NULL;
|
||||
|
||||
PARSE:
|
||||
|
||||
Expression* right = NULL;
|
||||
|
||||
auto tok = tokLookup();
|
||||
if (tok.isBoolean()) {
|
||||
tokSkip();
|
||||
|
||||
right = parseExpr(expessions);
|
||||
|
||||
if (mRes.err) {
|
||||
if (ret) {
|
||||
goto PRECEDENCE;
|
||||
}
|
||||
|
||||
delete left;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
CHECK(ret, {
|
||||
delete left;
|
||||
});
|
||||
goto PRECEDENCE;
|
||||
}
|
||||
|
||||
switch (tok) {
|
||||
case Token::EQUAL:
|
||||
ret = ExprBool(left, right, OpCode::EQUAL);
|
||||
break;
|
||||
case Token::NOT_EQUAL:
|
||||
ret = ExprBool(left, right, OpCode::NOT_EQUAL);
|
||||
break;
|
||||
case Token::BOOL_AND:
|
||||
ret = ExprBool(left, right, OpCode::AND);
|
||||
break;
|
||||
case Token::BOOL_OR:
|
||||
ret = ExprBool(left, right, OpCode::OR);
|
||||
break;
|
||||
case Token::MORE:
|
||||
ret = ExprBool(left, right, OpCode::MORE);
|
||||
break;
|
||||
case Token::LESS:
|
||||
ret = ExprBool(left, right, OpCode::LESS);
|
||||
break;
|
||||
case Token::QE_OR_MORE:
|
||||
ret = ExprBool(left, right, OpCode::EQUAL_OR_MORE);
|
||||
break;
|
||||
case Token::QE_OR_LESS:
|
||||
ret = ExprBool(left, right, OpCode::EQUAL_OR_LESS);
|
||||
}
|
||||
|
||||
left = ret;
|
||||
goto PARSE;
|
||||
|
||||
PRECEDENCE:
|
||||
// FIXME: Not Implemented
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Expression* Parser::parseExprBOOLEAN_NOT() {
|
||||
CHECK(tokRead() == Token::BOOL_NOT, {});
|
||||
|
||||
tp::init_list<ExprType> exprs = {
|
||||
ExprType::Compound,
|
||||
ExprType::BOOLEAN,
|
||||
ExprType::Ariphm,
|
||||
ExprType::NEW,
|
||||
ExprType::LOCAL,
|
||||
ExprType::CONST,
|
||||
};
|
||||
|
||||
auto out = parseExpr(exprs);
|
||||
CHECK_ERROR(out, {});
|
||||
|
||||
return ExprBoolNot(out);
|
||||
}
|
||||
|
||||
Expression* Parser::parseExprFUNC() {
|
||||
auto op_tok = tokRead();
|
||||
CHECK(op_tok == Token::ID, {});
|
||||
return ExprFunc(op_tok.token);
|
||||
}
|
||||
|
||||
// passed prnt isno longer responsability of callee
|
||||
// suc : returns top level parent
|
||||
// err : returns NULL
|
||||
Expression* Parser::parseExprChain(Expression* prnt) {
|
||||
|
||||
PARSE_CHAIN:
|
||||
auto tok = tokLookup();
|
||||
|
||||
switch (tok) {
|
||||
case Token::CHILD: {
|
||||
tokRead();
|
||||
|
||||
auto child_id = tokRead();
|
||||
REQUIRE(child_id == Token::ID, "expected an id", {
|
||||
delete prnt;
|
||||
});
|
||||
|
||||
prnt = prnt->ExprChild(child_id.token);
|
||||
goto PARSE_CHAIN;
|
||||
}
|
||||
|
||||
case Token::BRACKET_IN: {
|
||||
|
||||
auto new_prnt = parseExprCALL(prnt);
|
||||
CHECK_ERROR(new_prnt, {
|
||||
delete prnt;
|
||||
});
|
||||
|
||||
if (prnt->mType == Expression::Type::CHILD) {
|
||||
((ExpressionChild*)prnt)->mMethod = true;
|
||||
}
|
||||
|
||||
prnt = new_prnt;
|
||||
goto PARSE_CHAIN;
|
||||
}
|
||||
}
|
||||
|
||||
return prnt;
|
||||
}
|
||||
|
||||
Expression* Parser::parseExpr(tp::init_list<ExprType> expressions) {
|
||||
|
||||
Expression* out = NULL;
|
||||
|
||||
List<Error*> errors;
|
||||
|
||||
for (auto expr_type : expressions) {
|
||||
auto crs = tokGetCursor();
|
||||
switch (expr_type) {
|
||||
case Parser::ExprType::BOOLEAN_NOT:
|
||||
out = parseExprBOOLEAN_NOT();
|
||||
break;
|
||||
case Parser::ExprType::BOOLEAN:
|
||||
out = parseExprBOOLEAN();
|
||||
break;
|
||||
case Parser::ExprType::Ariphm:
|
||||
out = parseExprAriphm();
|
||||
break;
|
||||
case Parser::ExprType::NEW:
|
||||
out = parseExprNEW();
|
||||
break;
|
||||
case Parser::ExprType::LOCAL:
|
||||
out = parseExprLOCAL();
|
||||
break;
|
||||
case Parser::ExprType::CONST:
|
||||
out = parseExprCONST();
|
||||
break;
|
||||
case Parser::ExprType::Compound:
|
||||
out = parseExprCompound();
|
||||
break;
|
||||
}
|
||||
|
||||
if (out) {
|
||||
break;
|
||||
}
|
||||
|
||||
tokSetCursor(crs);
|
||||
if (mRes.err) {
|
||||
errors.pushBack(mRes.err);
|
||||
mRes.err = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (out) {
|
||||
// check for child expression and calls
|
||||
out = parseExprChain(out);
|
||||
|
||||
// check errors
|
||||
if (mRes.err) {
|
||||
errors.pushBack(mRes.err);
|
||||
mRes.err = NULL;
|
||||
goto ERRORS;
|
||||
}
|
||||
|
||||
for (auto err : errors) {
|
||||
delete err.data();
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
ERRORS:
|
||||
Error* error = NULL;
|
||||
tp::alni max_advanced = 0;
|
||||
for (auto err : errors) {
|
||||
if (err.data()->mAdvanecedIdx && err.data()->mAdvanecedIdx > max_advanced) {
|
||||
max_advanced = err.data()->mAdvanecedIdx;
|
||||
error = err.data();
|
||||
}
|
||||
}
|
||||
|
||||
if (error) {
|
||||
mRes.err = new Error(*error);
|
||||
|
||||
for (auto err : errors) {
|
||||
delete err.data();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
REQUIRE(0, "Expected and expression", {});
|
||||
}
|
||||
|
||||
Statement* Parser::parseStmCall() {
|
||||
|
||||
Expression* expr = parseExpr();
|
||||
CHECK_ERROR(expr, {});
|
||||
|
||||
REQUIRE(expr->mType == Expression::Type::CALL,
|
||||
"expression statement can only be function call", {
|
||||
delete expr;
|
||||
});
|
||||
|
||||
if (tokRead() != Token::STM_END) {
|
||||
delete expr;
|
||||
REQUIRE(0, "Expected End Of Statement", {});
|
||||
}
|
||||
|
||||
return StmIgnore(expr);
|
||||
}
|
||||
|
||||
Statement* Parser::parseStmDefFunc() {
|
||||
CHECK(tokRead() == Token::DEF_FUNC, {});
|
||||
List<tp::String> args;
|
||||
auto name = tokRead();
|
||||
REQUIRE(name == Token::ID, "Expected an Identifier", {});
|
||||
|
||||
REQUIRE(tokRead() == Token::BRACKET_IN, "Expected Opening Bracket", {});
|
||||
|
||||
READ_ARG:
|
||||
auto tok = tokLookup();
|
||||
|
||||
REQUIRE(tok != Token::NO_TOKEN, "Missing Closing Bracket", {});
|
||||
|
||||
if (tok == Token::ID) {
|
||||
args.pushBack(tok.token);
|
||||
tokSkip();
|
||||
tok = tokLookup();
|
||||
}
|
||||
|
||||
if (tok == Token::COMMA) {
|
||||
tokSkip();
|
||||
goto READ_ARG;
|
||||
}
|
||||
|
||||
REQUIRE(tok == Token::BRACKET_OUT, "Expected Closing Bracket", {});
|
||||
tokSkip();
|
||||
|
||||
auto func_def = StmDefFunc(name.token, {}, {});
|
||||
|
||||
func_def->mArgs.reserve(args.length());
|
||||
for (auto iter : args) {
|
||||
func_def->mArgs[iter.idx()] = iter.data();
|
||||
}
|
||||
|
||||
StatementScope* scope = parseScope(true);
|
||||
CHECK_ERROR(scope, {
|
||||
delete func_def;
|
||||
});
|
||||
|
||||
func_def->mStatements.reserve(scope->mStatements.size());
|
||||
for (auto stm : scope->mStatements) {
|
||||
func_def->mStatements[stm.idx()] = stm.data();
|
||||
}
|
||||
|
||||
delete scope;
|
||||
return func_def;
|
||||
}
|
||||
|
||||
Statement* Parser::parseStmDefLocal() {
|
||||
CHECK(tokRead() == Token::VAR, {});
|
||||
|
||||
auto tok = tokRead();
|
||||
REQUIRE(tok == Token::ID, "Expected an Identifier", {});
|
||||
REQUIRE(tokRead() == Token::ASSIGN, "Expected an assigment", {});
|
||||
|
||||
auto expr = parseExpr();
|
||||
CHECK_ERROR(expr, {});
|
||||
|
||||
if (tokRead() != Token::STM_END) {
|
||||
delete expr;
|
||||
REQUIRE(0, "Expected End Of Statement", {});
|
||||
}
|
||||
|
||||
return StmDefLocal(tok.token, expr);
|
||||
}
|
||||
|
||||
Statement* Parser::parseStmReturn() {
|
||||
CHECK(tokRead() == Token::RETURN, {});
|
||||
auto crs = tokGetCursor();
|
||||
|
||||
auto expr = parseExpr();
|
||||
if (mRes.err) {
|
||||
tokSetCursor(crs);
|
||||
delete mRes.err;
|
||||
mRes.err = NULL;
|
||||
}
|
||||
|
||||
if (tokRead() != Token::STM_END) {
|
||||
if (expr) delete expr;
|
||||
REQUIRE(0, "Expected End Of Statement", {});
|
||||
}
|
||||
|
||||
return expr ? StmReturn(expr) : StmReturn();
|
||||
}
|
||||
|
||||
Statement* Parser::parseStmPrint() {
|
||||
CHECK(tokRead() == Token::PRINT, {});
|
||||
auto expr = parseExpr();
|
||||
CHECK_ERROR(expr, {});
|
||||
|
||||
if (tokRead() != Token::STM_END) {
|
||||
delete expr;
|
||||
REQUIRE(0, "Expected End Of Statement", {});
|
||||
}
|
||||
return StmPrint(expr);
|
||||
}
|
||||
|
||||
Statement* Parser::parseStmIf() {
|
||||
CHECK(tokRead() == Token::IF, {});
|
||||
|
||||
// single if
|
||||
REQUIRE(tokRead() == Token::BRACKET_IN, "Expected Opening Bracket", {});
|
||||
auto expr = parseExpr();
|
||||
CHECK_ERROR(expr, {});
|
||||
|
||||
if (tokRead() != Token::BRACKET_OUT) {
|
||||
delete expr;
|
||||
REQUIRE(0, "Expected Closing Bracket", {});
|
||||
}
|
||||
|
||||
auto ontrue = parseScope(false);
|
||||
CHECK_ERROR(ontrue, {});
|
||||
|
||||
// if-else
|
||||
auto crs = tokGetCursor();
|
||||
if (tokRead() == Token::ELSE) {
|
||||
StatementScope* onfalse = parseScope(false);
|
||||
CHECK_ERROR(onfalse, {
|
||||
delete ontrue;
|
||||
delete expr;
|
||||
});
|
||||
|
||||
return StmIf(expr, ontrue, onfalse);
|
||||
}
|
||||
tokSetCursor(crs);
|
||||
|
||||
return StmIf(expr, ontrue, NULL);
|
||||
}
|
||||
|
||||
Statement* Parser::parseStmWhile() {
|
||||
CHECK(tokRead() == Token::WHILE, {});
|
||||
|
||||
REQUIRE(tokRead() == Token::BRACKET_IN, "Expected Opening Bracket", {});
|
||||
auto expr = parseExpr();
|
||||
CHECK_ERROR(expr, {});
|
||||
|
||||
if (tokRead() != Token::BRACKET_OUT) {
|
||||
delete expr;
|
||||
REQUIRE(0, "Expected Closing Bracket", {});
|
||||
}
|
||||
|
||||
auto scope = parseScope(false);
|
||||
CHECK_ERROR(scope, {});
|
||||
|
||||
return StmWhile(expr, scope);
|
||||
}
|
||||
|
||||
Statement* Parser::parseStmCopy() {
|
||||
auto left = parseExpr();
|
||||
CHECK_ERROR(left, {});
|
||||
|
||||
CHECK(tokRead() == Token::ASSIGN, {});
|
||||
|
||||
auto right = parseExpr();
|
||||
CHECK_ERROR(right, {
|
||||
delete left;
|
||||
});
|
||||
|
||||
if (tokRead() != Token::STM_END) {
|
||||
delete left;
|
||||
delete right;
|
||||
REQUIRE(0, "Expected End Of Statement", {});
|
||||
}
|
||||
|
||||
return StmCopy(left, right);
|
||||
}
|
||||
|
||||
Statement* Parser::parseStmClassDef() {
|
||||
CHECK(tokRead() == Token::CLASS_DEF, {});
|
||||
|
||||
auto id = tokRead();
|
||||
REQUIRE(id == Token::ID, "Expected an Identifier", {});
|
||||
|
||||
auto scope = parseScope(true);
|
||||
CHECK_ERROR(scope, {});
|
||||
|
||||
return StmClassDef(id.token, scope);
|
||||
}
|
||||
|
||||
Statement* Parser::parseStm(tp::init_list<StmType> stm_types) {
|
||||
Statement* out = NULL;
|
||||
|
||||
List<Error*> errors;
|
||||
|
||||
for (auto stm_type : stm_types) {
|
||||
auto crs = tokGetCursor();
|
||||
switch (stm_type) {
|
||||
case StmType::DefFunc:
|
||||
out = parseStmDefFunc();
|
||||
break;
|
||||
case StmType::DefLocal:
|
||||
out = parseStmDefLocal();
|
||||
break;
|
||||
case StmType::Return:
|
||||
out = parseStmReturn();
|
||||
break;
|
||||
case StmType::Print:
|
||||
out = parseStmPrint();
|
||||
break;
|
||||
case StmType::If:
|
||||
out = parseStmIf();
|
||||
break;
|
||||
case StmType::While:
|
||||
out = parseStmWhile();
|
||||
break;
|
||||
case StmType::Copy:
|
||||
out = parseStmCopy();
|
||||
break;
|
||||
case StmType::Call:
|
||||
out = parseStmCall();
|
||||
break;
|
||||
case StmType::CLASS_DEF:
|
||||
out = parseStmClassDef();
|
||||
break;
|
||||
}
|
||||
|
||||
if (out) {
|
||||
break;
|
||||
}
|
||||
|
||||
tokSetCursor(crs);
|
||||
if (mRes.err) {
|
||||
errors.pushBack(mRes.err);
|
||||
mRes.err = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (out) {
|
||||
for (auto err : errors) {
|
||||
delete err.data();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Error* error = NULL;
|
||||
tp::alni max_advanced = 0;
|
||||
for (auto err : errors) {
|
||||
if (err.data()->mAdvanecedIdx && max_advanced < err.data()->mAdvanecedIdx) {
|
||||
max_advanced = err.data()->mAdvanecedIdx;
|
||||
error = err.data();
|
||||
}
|
||||
}
|
||||
|
||||
if (error) {
|
||||
mRes.err = new Error(*error);
|
||||
|
||||
for (auto err : errors) {
|
||||
delete err.data();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
REQUIRE(0, "Exprected A Statement", {});
|
||||
}
|
||||
|
||||
StatementScope* Parser::parseScope(bool aPushToScopeStack) {
|
||||
CHECK(tokRead() == Token::SCOPE_IN, {});
|
||||
|
||||
auto out = new StatementScope({}, aPushToScopeStack);
|
||||
List<Statement*> stms;
|
||||
|
||||
READ_STM:
|
||||
auto crs = tokGetCursor();
|
||||
auto tok = tokRead();
|
||||
|
||||
if (tok == Token::NO_TOKEN) {
|
||||
delete out;
|
||||
for (auto stm : stms) {
|
||||
delete stm.data();
|
||||
}
|
||||
REQUIRE(0, "Missing Scope Closing Bracket", {});
|
||||
}
|
||||
|
||||
if (tok != Token::SCOPE_OUT) {
|
||||
tokSetCursor(crs);
|
||||
|
||||
auto stm = parseStm();
|
||||
CHECK_ERROR(stm, {
|
||||
delete out;
|
||||
for (auto stm : stms) {
|
||||
delete stm.data();
|
||||
}
|
||||
});
|
||||
|
||||
stms.pushBack(stm);
|
||||
|
||||
goto READ_STM;
|
||||
}
|
||||
|
||||
out->mStatements.reserve(stms.length());
|
||||
for (auto stm : stms) {
|
||||
out->mStatements[stm.idx()] = stm.data();
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
Parser::Resault Parser::parse(const tp::String& oscript) {
|
||||
mTok.bindSource(oscript.read());
|
||||
|
||||
mRes.scope = new StatementScope({}, true);
|
||||
|
||||
List<Statement*> stms;
|
||||
do {
|
||||
auto stm = parseStm();
|
||||
|
||||
if (mRes.err || !stm) { // catch
|
||||
delete mRes.scope;
|
||||
mRes.scope = NULL;
|
||||
for (auto stm : stms) {
|
||||
delete stm.data();
|
||||
}
|
||||
|
||||
return mRes;
|
||||
}
|
||||
|
||||
stms.pushBack(stm);
|
||||
|
||||
} while (tokInputLeft());
|
||||
|
||||
mRes.scope->mStatements.reserve(stms.length());
|
||||
for (auto stm : stms) {
|
||||
mRes.scope->mStatements[stm.idx()] = stm.data();
|
||||
}
|
||||
|
||||
return mRes;
|
||||
}
|
||||
78
Objects/private/primitives/boolobject.cpp
Normal file
78
Objects/private/primitives/boolobject.cpp
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
|
||||
|
||||
#include "NewPlacement.hpp"
|
||||
#include "primitives/boolobject.h"
|
||||
|
||||
using namespace obj;
|
||||
using namespace tp;
|
||||
|
||||
void BoolObject::constructor(BoolObject* self) {
|
||||
self->val = false;
|
||||
}
|
||||
|
||||
void BoolObject::copy(BoolObject* self, const BoolObject* in) {
|
||||
self->val = in->val;
|
||||
}
|
||||
|
||||
BoolObject* BoolObject::create(bool in) {
|
||||
NDO_CASTV(BoolObject, NDO->create("bool"), out)->val = alni(in);
|
||||
return out;
|
||||
}
|
||||
|
||||
void BoolObject::from_int(BoolObject* self, alni in) {
|
||||
self->val = in;
|
||||
}
|
||||
|
||||
void BoolObject::from_float(BoolObject* self, alnf in) {
|
||||
self->val = alni(bool(in));
|
||||
}
|
||||
|
||||
void BoolObject::from_string(BoolObject* self, String in) {
|
||||
self->val = alni(bool(in));
|
||||
}
|
||||
|
||||
String BoolObject::to_string(BoolObject* self) {
|
||||
return String(bool(self->val));
|
||||
}
|
||||
|
||||
alni BoolObject::to_int(BoolObject* self) {
|
||||
return self->val;
|
||||
}
|
||||
|
||||
alnf BoolObject::to_float(BoolObject* self) {
|
||||
return alnf(bool(self->val));
|
||||
}
|
||||
|
||||
static alni save_size(BoolObject* self) {
|
||||
return sizeof(alni);
|
||||
}
|
||||
|
||||
static void save(BoolObject* self, Archiver& file_self) {
|
||||
file_self.write<alni>(&self->val);
|
||||
}
|
||||
|
||||
static void load(Archiver& file_self, BoolObject* self) {
|
||||
file_self.read<alni>(&self->val);
|
||||
}
|
||||
|
||||
struct ObjectTypeConversions BoolObjectTypeConversions = {
|
||||
.from_int = (object_from_int) BoolObject::from_int,
|
||||
.from_float = (object_from_float) BoolObject::from_float,
|
||||
.from_string = (object_from_string) BoolObject::from_string,
|
||||
.to_string = (object_to_string) BoolObject::to_string,
|
||||
.to_int = (object_to_int) BoolObject::to_int,
|
||||
.to_float = (object_to_float) BoolObject::to_float,
|
||||
};
|
||||
|
||||
struct obj::ObjectType obj::BoolObject::TypeData = {
|
||||
.base = NULL,
|
||||
.constructor = (object_constructor) BoolObject::constructor,
|
||||
.destructor = NULL,
|
||||
.copy = (object_copy) BoolObject::copy,
|
||||
.size = sizeof(BoolObject),
|
||||
.name = "bool",
|
||||
.convesions = &BoolObjectTypeConversions,
|
||||
.save_size = (object_save_size)save_size,
|
||||
.save = (object_save)save,
|
||||
.load = (object_load)load,
|
||||
};
|
||||
81
Objects/private/primitives/classobject.cpp
Normal file
81
Objects/private/primitives/classobject.cpp
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
#pragma once
|
||||
|
||||
#include "NewPlacement.hpp"
|
||||
|
||||
#include "primitives/classobject.h"
|
||||
#include "primitives/dictobject.h"
|
||||
#include "primitives/nullobject.h"
|
||||
|
||||
using namespace obj;
|
||||
using namespace tp;
|
||||
|
||||
void ClassObject::constructor(ClassObject* self) {
|
||||
self->members = NDO_CAST(DictObject, NDO->create("dict"));
|
||||
|
||||
self->addMember(NDO_NULL, "__init__");
|
||||
self->addMember(NDO_NULL, "__del__");
|
||||
}
|
||||
|
||||
void ClassObject::copy(ClassObject* self, const ClassObject* blueprint) {
|
||||
NDO->copy(self->members, blueprint->members);
|
||||
}
|
||||
|
||||
void ClassObject::destructor(ClassObject* self) {
|
||||
NDO->destroy(self->members);
|
||||
}
|
||||
|
||||
void ClassObject::addMember(Object* obj, tp::String id) {
|
||||
members->put(id, obj);
|
||||
}
|
||||
|
||||
void ClassObject::createMember(tp::String type, tp::String id) {
|
||||
auto newo = NDO->create(type);
|
||||
members->put(id, newo);
|
||||
}
|
||||
|
||||
alni ClassObject::save_size(ClassObject* self) {
|
||||
return sizeof(alni); // dict object adress
|
||||
}
|
||||
|
||||
void ClassObject::save(ClassObject* self, Archiver& file_self) {
|
||||
// save dictobject
|
||||
alni ndo_object_adress = NDO->save(file_self, self->members);
|
||||
file_self.write<alni>(&ndo_object_adress);
|
||||
}
|
||||
|
||||
void ClassObject::load(Archiver& file_self, ClassObject* self) {
|
||||
alni ndo_object_adress;
|
||||
file_self.read<alni>(&ndo_object_adress);
|
||||
self->members = NDO_CAST(DictObject, NDO->load(file_self, ndo_object_adress));
|
||||
}
|
||||
|
||||
tp::Buffer<Object*> childs_retrival(ClassObject* self) {
|
||||
tp::Buffer<Object*> out;
|
||||
out.append(self->members);
|
||||
return out;
|
||||
}
|
||||
|
||||
alni allocated_size(ClassObject* self) {
|
||||
return sizeof(DictObject*);
|
||||
}
|
||||
|
||||
alni allocated_size_recursive(ClassObject* self) {
|
||||
alni out = sizeof(DictObject*);
|
||||
out += NDO->objsize_ram_recursive_util(self->members, self->members->type);
|
||||
return out;
|
||||
}
|
||||
|
||||
struct ObjectType ClassObject::TypeData = {
|
||||
.base = NULL,
|
||||
.constructor = (object_constructor) ClassObject::constructor,
|
||||
.destructor = (object_destructor) ClassObject::destructor,
|
||||
.copy = (object_copy) ClassObject::copy,
|
||||
.size = sizeof(ClassObject),
|
||||
.name = "class",
|
||||
.save_size = (object_save_size)save_size,
|
||||
.save = (object_save)save,
|
||||
.load = (object_load)load,
|
||||
.childs_retrival = (object_debug_all_childs_retrival) childs_retrival,
|
||||
.allocated_size = (object_allocated_size) allocated_size,
|
||||
.allocated_size_recursive = (object_allocated_size_recursive) allocated_size_recursive
|
||||
};
|
||||
84
Objects/private/primitives/colorobject.cpp
Normal file
84
Objects/private/primitives/colorobject.cpp
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
|
||||
#include "NewPlacement.hpp"
|
||||
#include "primitives/colorobject.h"
|
||||
|
||||
using namespace obj;
|
||||
using namespace tp;
|
||||
|
||||
void ColorObject::constructor(Object* self) {
|
||||
NDO_CAST(ColorObject, self)->mCol = tp::RGBA(1.f);
|
||||
}
|
||||
|
||||
void ColorObject::copy(ColorObject* self, const ColorObject* in) {
|
||||
self->mCol = in->mCol;
|
||||
}
|
||||
|
||||
ColorObject* ColorObject::create(tp::RGBA in) {
|
||||
NDO_CASTV(ColorObject, NDO->create("RGBA"), out)->mCol = in;
|
||||
return out;
|
||||
}
|
||||
|
||||
void ColorObject::from_int(ColorObject* self, alni in) {
|
||||
self->mCol = tp::RGBA((tp::halnf)tp::clamp(in, (tp::alni) 0, (tp::alni) 1));
|
||||
}
|
||||
|
||||
void ColorObject::from_float(ColorObject* self, alnf in) {
|
||||
NDO_CAST(ColorObject, self)->mCol = tp::RGBA(tp::clamp((tp::halnf)in, 0.f, 1.f));
|
||||
}
|
||||
|
||||
String ColorObject::to_string(ColorObject* self) {
|
||||
// auto &col = NDO_CAST(ColorObject, self)->mCol;
|
||||
// return tp::sfmt("%i:%i:%i:%i", (tp::alni) (col.r * 255), (tp::alni)(col.g * 255), (tp::alni)(col.b * 255), (tp::alni)(col.a * 255));
|
||||
// TODO : implement
|
||||
return {};
|
||||
}
|
||||
|
||||
static alni save_size(ColorObject* self) {
|
||||
return sizeof(tp::RGBA);
|
||||
}
|
||||
|
||||
static void save(ColorObject* self, Archiver& file_self) {
|
||||
file_self.write<tp::RGBA>(&self->mCol);
|
||||
}
|
||||
|
||||
static void load(Archiver& file_self, ColorObject* self) {
|
||||
file_self.read<tp::RGBA>(&self->mCol);
|
||||
}
|
||||
|
||||
struct ObjectTypeConversions ColorObjectTypeConversions = {
|
||||
.from_int = (object_from_int) ColorObject::from_int,
|
||||
.from_float = (object_from_float) ColorObject::from_float,
|
||||
.from_string = NULL,
|
||||
.to_string = (object_to_string) ColorObject::to_string,
|
||||
.to_int = NULL,
|
||||
.to_float = NULL,
|
||||
};
|
||||
|
||||
void sub(ColorObject* self, ColorObject* in) {
|
||||
self->mCol = in->mCol - self->mCol;
|
||||
}
|
||||
|
||||
void add(ColorObject* self, ColorObject* in) {
|
||||
self->mCol = in->mCol + self->mCol;
|
||||
}
|
||||
|
||||
struct ObjectTypeAriphmetics ColorObject::TypeAriphm = {
|
||||
.add = (object_add) add,
|
||||
.sub = (object_sub) sub,
|
||||
.mul = (object_mul) NULL,
|
||||
.div = (object_div) NULL,
|
||||
};
|
||||
|
||||
struct obj::ObjectType obj::ColorObject::TypeData = {
|
||||
.base = NULL,
|
||||
.constructor = ColorObject::constructor,
|
||||
.destructor = NULL,
|
||||
.copy = (object_copy) ColorObject::copy,
|
||||
.size = sizeof(ColorObject),
|
||||
.name = "RGBA",
|
||||
.convesions = &ColorObjectTypeConversions,
|
||||
.ariphmetics = &ColorObject::TypeAriphm,
|
||||
.save_size = (object_save_size)save_size,
|
||||
.save = (object_save)save,
|
||||
.load = (object_load)load,
|
||||
};
|
||||
232
Objects/private/primitives/dictobject.cpp
Normal file
232
Objects/private/primitives/dictobject.cpp
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
#pragma once
|
||||
|
||||
#include "NewPlacement.hpp"
|
||||
|
||||
#include "primitives/dictobject.h"
|
||||
#include "primitives/stringobject.h"
|
||||
|
||||
using namespace obj;
|
||||
using namespace tp;
|
||||
|
||||
void DictObject::constructor(Object* self) {
|
||||
NDO_CASTV(DictObject, self, dict);
|
||||
|
||||
new (&dict->items) Map<String, Object*>();
|
||||
}
|
||||
|
||||
void DictObject::copy(Object* in, const Object* target) {
|
||||
NDO_CASTV(DictObject, in, self);
|
||||
NDO_CASTV(DictObject, target, src);
|
||||
|
||||
destructor(self);
|
||||
constructor(self);
|
||||
|
||||
for (auto item : src->items) {
|
||||
auto instance = NDO->instatiate(item->val);
|
||||
self->items.put(item->key, instance);
|
||||
}
|
||||
}
|
||||
|
||||
void DictObject::destructor(Object* self) {
|
||||
NDO_CASTV(DictObject, self, dict);
|
||||
for (auto item : dict->items) {
|
||||
NDO->destroy(item->val);
|
||||
}
|
||||
dict->items.~Map();
|
||||
}
|
||||
|
||||
alni DictObject::save_size(DictObject* self) {
|
||||
// calculate size needed
|
||||
alni save_size = 0;
|
||||
|
||||
// number on entries
|
||||
save_size += sizeof(alni);
|
||||
|
||||
for (auto item : self->items) {
|
||||
// string length
|
||||
save_size += (item->key.size() + 1) * sizeof(*item->key.read());
|
||||
// object file adress
|
||||
save_size += sizeof(alni);
|
||||
}
|
||||
|
||||
return save_size;
|
||||
}
|
||||
|
||||
void DictObject::save(DictObject* self, Archiver& file_self) {
|
||||
|
||||
// write size
|
||||
alni len = self->items.size();
|
||||
file_self.write<alni>(&len);
|
||||
|
||||
// save hashmap pairs
|
||||
for (auto item : self->items) {
|
||||
// item val
|
||||
alni ndo_object_adress = NDO->save(file_self, item->val);
|
||||
file_self.write<alni>(&ndo_object_adress);
|
||||
|
||||
// item key
|
||||
item->key.save(&file_self);
|
||||
}
|
||||
}
|
||||
|
||||
void DictObject::load(Archiver& file_self, DictObject* self) {
|
||||
new (&self->items) tp::Map<tp::String, Object*>();
|
||||
|
||||
alni len;
|
||||
file_self.read<alni>(&len);
|
||||
|
||||
for (alni i = 0; i < len; i++) {
|
||||
|
||||
// read val
|
||||
alni ndo_object_adress;
|
||||
file_self.read<alni>(&ndo_object_adress);
|
||||
Object* val = NDO->load(file_self, ndo_object_adress);
|
||||
|
||||
// read key value
|
||||
String key;
|
||||
key.load(&file_self);
|
||||
|
||||
// add to dictinary
|
||||
self->items.put(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
tp::Buffer<Object*> DictObject::childs_retrival(DictObject* self) {
|
||||
tp::Buffer<Object*> out;
|
||||
out.reserve(self->items.size());
|
||||
ualni i = 0;
|
||||
for (auto item : self->items) {
|
||||
out[i] = item->val;
|
||||
i++;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
alni DictObject::allocated_size(DictObject* self) {
|
||||
alni out = self->items.sizeAllocatedMem();
|
||||
for (auto item : self->items) {
|
||||
out += item->key.sizeAllocatedMem();
|
||||
}
|
||||
return out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
alni DictObject::allocated_size_recursive(DictObject* self) {
|
||||
alni out = allocated_size(self);
|
||||
for (auto item : self->items) {
|
||||
out += NDO->objsize_ram_recursive_util(item->val, item->val->type);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void DictObject::put(tp::String str, Object* obj) {
|
||||
DEBUG_ASSERT(obj);
|
||||
NDO->refinc(obj);
|
||||
items.put(str, obj);
|
||||
}
|
||||
|
||||
void DictObject::remove(tp::String str) {
|
||||
auto idx = items.presents(str);
|
||||
if (idx) {
|
||||
NDO->destroy(items.getSlotVal(idx));
|
||||
items.remove(str);
|
||||
}
|
||||
}
|
||||
|
||||
Object* DictObject::get(tp::String str) {
|
||||
return items.get(str);
|
||||
}
|
||||
|
||||
tp::Map<tp::String, Object*>::Idx DictObject::presents(tp::String str) {
|
||||
return items.presents(str);
|
||||
}
|
||||
|
||||
Object* DictObject::getSlotVal(tp::alni idx) {
|
||||
return items.getSlotVal(idx);
|
||||
}
|
||||
|
||||
const tp::Map<tp::String, Object*>& DictObject::getItems() const {
|
||||
return items;
|
||||
}
|
||||
|
||||
static auto tm_get = TypeMethod{
|
||||
.nameid = "get",
|
||||
.descr = "gets the object",
|
||||
.args = {
|
||||
{ "str key", NULL }
|
||||
},
|
||||
.exec = [](const TypeMethod* tm) {
|
||||
auto const self = (DictObject*)tm->self;
|
||||
auto str_key = tm->args[0].obj;
|
||||
|
||||
NDO_CASTV(StringObject, str_key, key);
|
||||
ASSERT(key);
|
||||
|
||||
auto idx = self->presents(key->val);
|
||||
if (idx) {
|
||||
tm->ret.obj = self->getSlotVal(idx);
|
||||
}
|
||||
},
|
||||
.ret = { "object", NULL }
|
||||
};
|
||||
|
||||
static auto tm_put = TypeMethod{
|
||||
.nameid = "put",
|
||||
.descr = "puts the object into the dictinary",
|
||||
.args = {
|
||||
{ "key", NULL },
|
||||
{ "object", NULL }
|
||||
},
|
||||
.exec = [](const TypeMethod* tm) {
|
||||
auto const self = (DictObject*)tm->self;
|
||||
|
||||
auto str_key = tm->args[0].obj;
|
||||
auto obj = tm->args[1].obj;
|
||||
|
||||
NDO_CASTV(StringObject, str_key, key);
|
||||
ASSERT(key);
|
||||
|
||||
self->put(key->val, obj);
|
||||
},
|
||||
};
|
||||
|
||||
static auto tm_remove = TypeMethod{
|
||||
.nameid = "remove",
|
||||
.descr = "remove the object from the dictinary",
|
||||
.args = {
|
||||
{ "key", NULL },
|
||||
},
|
||||
.exec = [](const TypeMethod* tm) {
|
||||
auto const self = (DictObject*)tm->self;
|
||||
|
||||
auto str_key = tm->args[0].obj;
|
||||
|
||||
NDO_CASTV(StringObject, str_key, key);
|
||||
ASSERT(key);
|
||||
|
||||
self->remove(key->val);
|
||||
},
|
||||
};
|
||||
|
||||
struct obj::ObjectType DictObject::TypeData = {
|
||||
.base = NULL,
|
||||
.constructor = DictObject::constructor,
|
||||
.destructor = DictObject::destructor,
|
||||
.copy = DictObject::copy,
|
||||
.size = sizeof(DictObject),
|
||||
.name = "dict",
|
||||
.save_size = (object_save_size)DictObject::save_size,
|
||||
.save = (object_save)DictObject::save,
|
||||
.load = (object_load)DictObject::load,
|
||||
.childs_retrival = (object_debug_all_childs_retrival)DictObject::childs_retrival,
|
||||
.allocated_size = (object_allocated_size)DictObject::allocated_size,
|
||||
.allocated_size_recursive = (object_allocated_size_recursive)DictObject::allocated_size_recursive,
|
||||
|
||||
.type_methods = {
|
||||
.methods = {
|
||||
&tm_put,
|
||||
&tm_remove,
|
||||
&tm_get,
|
||||
}
|
||||
}
|
||||
};
|
||||
182
Objects/private/primitives/enumobject.cpp
Normal file
182
Objects/private/primitives/enumobject.cpp
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "NewPlacement.hpp"
|
||||
#include "primitives/enumobject.h"
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
using namespace obj;
|
||||
using namespace tp;
|
||||
|
||||
void EnumObject::constructor(EnumObject* self) {
|
||||
self->active = 0;
|
||||
self->nentries = 0;
|
||||
self->entries = NULL;
|
||||
}
|
||||
|
||||
void obj::EnumObject::destructor(EnumObject* self) {
|
||||
if (self->entries) free(self->entries);
|
||||
}
|
||||
|
||||
void EnumObject::copy(EnumObject* self, const EnumObject* in) {
|
||||
if (self->entries) free(self->entries);
|
||||
self->active = in->active;
|
||||
self->nentries = in->nentries;
|
||||
|
||||
self->entries = (alni*)malloc(self->nentries * ENV_ALNI_SIZE_B);
|
||||
tp::memCopy(self->entries, in->entries, self->nentries * ENV_ALNI_SIZE_B);
|
||||
}
|
||||
|
||||
void obj::EnumObject::init(tp::init_list<const char*> list) {
|
||||
|
||||
if (entries) free(entries);
|
||||
|
||||
active = 0;
|
||||
nentries = (uhalni) list.size();
|
||||
entries = (alni*) malloc(nentries * ENV_ALNI_SIZE_B);
|
||||
tp::memSetVal(entries, nentries * ENV_ALNI_SIZE_B, 0);
|
||||
|
||||
alni* entry = entries;
|
||||
for (auto elem : list) {
|
||||
|
||||
alni len = tp::String::Logic::calcLength(elem);
|
||||
if (len > ENV_ALNI_SIZE_B - 1) len = ENV_ALNI_SIZE_B - 1;
|
||||
|
||||
tp::memCopy(entry, elem, len);
|
||||
|
||||
for (alni* chech_entry = entries; chech_entry != entry; chech_entry++) {
|
||||
DEBUG_ASSERT(tp::memCompare(chech_entry, entry, ENV_ALNI_SIZE_B) != 0);
|
||||
}
|
||||
|
||||
entry++;
|
||||
}
|
||||
}
|
||||
|
||||
const char* obj::EnumObject::getActiveName() {
|
||||
return getItemName(active);
|
||||
}
|
||||
|
||||
const char* obj::EnumObject::getItemName(tp::uhalni idx) {
|
||||
DEBUG_ASSERT(entries && idx >= 0 && idx < nentries);
|
||||
return (const char*) (entries + idx);
|
||||
}
|
||||
|
||||
|
||||
void EnumObject::from_int(EnumObject* self, alni in) {
|
||||
if (self->entries && in >= 0 && in < self->nentries) {
|
||||
self->active = uhalni(in);
|
||||
}
|
||||
}
|
||||
|
||||
void EnumObject::from_float(EnumObject* self, alnf in) {
|
||||
if (self->entries && in >= 0 && in < self->nentries) {
|
||||
self->active = uhalni(in);
|
||||
}
|
||||
}
|
||||
|
||||
void EnumObject::from_string(EnumObject* self, String in) {
|
||||
if (self->entries) {
|
||||
alni* entry = self->entries;
|
||||
for (uhalni i = 0; i < self->nentries; i++) {
|
||||
if (tp::String::Logic::isEqualLogic((const char*)entry, in.read())) {
|
||||
self->active = i;
|
||||
}
|
||||
entry += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String EnumObject::to_string(EnumObject* self) {
|
||||
if (!self->entries) {
|
||||
return tp::String();
|
||||
}
|
||||
auto val = (const char*)(&self->entries[self->active]);
|
||||
return String(val);
|
||||
}
|
||||
|
||||
alni EnumObject::to_int(EnumObject* self) {
|
||||
if (!self->entries) {
|
||||
return -1;
|
||||
}
|
||||
return alni(self->active);
|
||||
}
|
||||
|
||||
alnf EnumObject::to_float(EnumObject* self) {
|
||||
if (!self->entries) {
|
||||
return -1;
|
||||
}
|
||||
return alnf(self->active);
|
||||
}
|
||||
|
||||
static alni save_size(EnumObject* self) {
|
||||
if (!self->entries) {
|
||||
return sizeof(uhalni);
|
||||
}
|
||||
return sizeof(uhalni) + sizeof(uhalni) + sizeof(alni) * self->nentries;
|
||||
}
|
||||
|
||||
static void save(EnumObject* self, Archiver& file_self) {
|
||||
if (!self->entries) {
|
||||
uhalni empty_code = -1;
|
||||
file_self.write<uhalni>(&empty_code);
|
||||
return;
|
||||
}
|
||||
file_self.write<uhalni>(&self->active);
|
||||
file_self.write<uhalni>(&self->nentries);
|
||||
file_self.write_bytes((tp::int1*) self->entries, self->nentries * ENV_ALNI_SIZE_B);
|
||||
}
|
||||
|
||||
static void load(Archiver& file_self, EnumObject* self) {
|
||||
file_self.read<uhalni>(&self->active);
|
||||
if (self->active == -1) {
|
||||
self->nentries = 0;
|
||||
self->entries = NULL;
|
||||
return;
|
||||
}
|
||||
file_self.read<uhalni>(&self->nentries);
|
||||
self->entries = (alni*) malloc(self->nentries * ENV_ALNI_SIZE_B);
|
||||
file_self.read_bytes((tp::int1*) self->entries, self->nentries * ENV_ALNI_SIZE_B);
|
||||
}
|
||||
|
||||
bool obj::EnumObject::compare(EnumObject* first, EnumObject* second) {
|
||||
return first->entries != NULL && second->entries != NULL && first->active == second->active;
|
||||
}
|
||||
|
||||
EnumObject* obj::EnumObject::create(tp::init_list<const char*> list) {
|
||||
auto enum_object = (EnumObject*)obj::NDO->create("enum");
|
||||
enum_object->init(list);
|
||||
return enum_object;
|
||||
}
|
||||
|
||||
alni allocated_size(EnumObject* self) {
|
||||
alni out = sizeof(uhalni) * 2 + sizeof(tp::alni*);
|
||||
if (self->entries) {
|
||||
out += self->nentries * sizeof(alni) * 2;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
struct ObjectTypeConversions EnumObjectTypeConversions = {
|
||||
.from_int = (object_from_int) EnumObject::from_int,
|
||||
.from_float = (object_from_float) EnumObject::from_float,
|
||||
.from_string = (object_from_string) EnumObject::from_string,
|
||||
.to_string = (object_to_string) EnumObject::to_string,
|
||||
.to_int = (object_to_int) EnumObject::to_int,
|
||||
.to_float = (object_to_float) EnumObject::to_float,
|
||||
};
|
||||
|
||||
struct obj::ObjectType obj::EnumObject::TypeData = {
|
||||
.base = NULL,
|
||||
.constructor = (object_constructor) EnumObject::constructor,
|
||||
.destructor = (object_destructor) EnumObject::destructor,
|
||||
.copy = (object_copy) EnumObject::copy,
|
||||
.size = sizeof(EnumObject),
|
||||
.name = "enum",
|
||||
.convesions = &EnumObjectTypeConversions,
|
||||
.save_size = (object_save_size)save_size,
|
||||
.save = (object_save)save,
|
||||
.load = (object_load)load,
|
||||
.comparison = (object_compare) EnumObject::compare,
|
||||
.allocated_size = (object_allocated_size) allocated_size,
|
||||
};
|
||||
102
Objects/private/primitives/floatobject.cpp
Normal file
102
Objects/private/primitives/floatobject.cpp
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
#pragma once
|
||||
|
||||
#include "NewPlacement.hpp"
|
||||
#include "primitives/floatobject.h"
|
||||
|
||||
using namespace obj;
|
||||
using namespace tp;
|
||||
|
||||
void FloatObject::constructor(FloatObject* self) {
|
||||
self->val = 0;
|
||||
}
|
||||
|
||||
void FloatObject::copy(FloatObject* self, const FloatObject* in) {
|
||||
self->val = in->val;
|
||||
}
|
||||
|
||||
FloatObject* FloatObject::create(alnf in) {
|
||||
NDO_CASTV(FloatObject, NDO->create("float"), out)->val = alnf(in);
|
||||
return out;
|
||||
}
|
||||
|
||||
void FloatObject::from_int(FloatObject* self, alni in) {
|
||||
self->val = alnf(in);
|
||||
}
|
||||
|
||||
void FloatObject::from_float(FloatObject* self, alnf in) {
|
||||
self->val = in;
|
||||
}
|
||||
|
||||
void FloatObject::from_string(FloatObject* self, String in) {
|
||||
self->val = alnf(in);
|
||||
}
|
||||
|
||||
String FloatObject::to_string(FloatObject* self) {
|
||||
return String(self->val);
|
||||
}
|
||||
|
||||
alni FloatObject::to_int(FloatObject* self) {
|
||||
return alni(self->val);
|
||||
}
|
||||
|
||||
alnf FloatObject::to_float(FloatObject* self) {
|
||||
return self->val;
|
||||
}
|
||||
|
||||
static alni save_size(FloatObject* self) {
|
||||
return sizeof(alnf);
|
||||
}
|
||||
|
||||
static void save(FloatObject* self, Archiver& file_self) {
|
||||
file_self.write<alnf>(&self->val);
|
||||
}
|
||||
|
||||
static void load(Archiver& file_self, FloatObject* self) {
|
||||
file_self.read<alnf>(&self->val);
|
||||
}
|
||||
|
||||
struct ObjectTypeConversions FloatObjectTypeConversions = {
|
||||
.from_int = (object_from_int) FloatObject::from_int,
|
||||
.from_float = (object_from_float) FloatObject::from_float,
|
||||
.from_string = (object_from_string) FloatObject::from_string,
|
||||
.to_string = (object_to_string) FloatObject::to_string,
|
||||
.to_int = (object_to_int) FloatObject::to_int,
|
||||
.to_float = (object_to_float) FloatObject::to_float,
|
||||
};
|
||||
|
||||
static void mul(FloatObject* self, FloatObject* in) {
|
||||
self->val *= in->val;
|
||||
}
|
||||
|
||||
static void sub(FloatObject* self, FloatObject* in) {
|
||||
self->val -= in->val;
|
||||
}
|
||||
|
||||
static void add(FloatObject* self, FloatObject* in) {
|
||||
self->val += in->val;
|
||||
}
|
||||
|
||||
static void divide(FloatObject* self, FloatObject* in) {
|
||||
self->val /= in->val;
|
||||
}
|
||||
|
||||
struct ObjectTypeAriphmetics FloatObject::TypeAriphm = {
|
||||
.add = (object_add)add,
|
||||
.sub = (object_sub)sub,
|
||||
.mul = (object_mul)mul,
|
||||
.div = (object_div)divide,
|
||||
};
|
||||
|
||||
struct obj::ObjectType obj::FloatObject::TypeData = {
|
||||
.base = NULL,
|
||||
.constructor = (object_constructor) FloatObject::constructor,
|
||||
.destructor = NULL,
|
||||
.copy = (object_copy) FloatObject::copy,
|
||||
.size = sizeof(FloatObject),
|
||||
.name = "float",
|
||||
.convesions = &FloatObjectTypeConversions,
|
||||
.ariphmetics = &FloatObject::TypeAriphm,
|
||||
.save_size = (object_save_size) save_size,
|
||||
.save = (object_save) save,
|
||||
.load = (object_load) load,
|
||||
};
|
||||
82
Objects/private/primitives/interpreterobject.cpp
Normal file
82
Objects/private/primitives/interpreterobject.cpp
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
|
||||
#include "NewPlacement.hpp"
|
||||
|
||||
#include "primitives/interpreterobject.h"
|
||||
#include "primitives/linkobject.h"
|
||||
#include "primitives/methodobject.h"
|
||||
|
||||
using namespace obj;
|
||||
using namespace tp;
|
||||
|
||||
void InterpreterObject::constructor(InterpreterObject* self) {
|
||||
new (&self->mInterpreter) Interpreter();
|
||||
|
||||
self->createMember("dict", "globals");
|
||||
self->createMember("link", "target method");
|
||||
}
|
||||
|
||||
void InterpreterObject::destructor(InterpreterObject* self) {
|
||||
self->mInterpreter.~Interpreter();
|
||||
}
|
||||
|
||||
void InterpreterObject::load(Archiver& file_self, InterpreterObject* self) {
|
||||
new (&self->mInterpreter) Interpreter();
|
||||
}
|
||||
|
||||
bool InterpreterObject::running() { return !mInterpreter.finished(); }
|
||||
|
||||
void InterpreterObject::exec(obj::ClassObject* self, tp::init_list<Interpreter::GlobalDef> globals) {
|
||||
|
||||
if (running()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto link_target = getMember<obj::LinkObject>("target method");
|
||||
if (!link_target) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto target = link_target->getLink();
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
NDO_CASTV(obj::MethodObject, target, method);
|
||||
if (!method || !method->mScript->mBytecode.mInstructions.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mInterpreter.execAll(method, self, getMember<obj::DictObject>("globals"), globals);
|
||||
}
|
||||
|
||||
void InterpreterObject::debug() {
|
||||
if (running()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto link_target = getMember<obj::LinkObject>("target method");
|
||||
if (!link_target) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto target = link_target->getLink();
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
NDO_CASTV(obj::MethodObject, target, method);
|
||||
if (!method || !method->mScript->mBytecode.mInstructions.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mInterpreter.exec(method, this, getMember<obj::DictObject>("globals"));
|
||||
}
|
||||
|
||||
struct obj::ObjectType InterpreterObject::TypeData = {
|
||||
.base = &ClassObject::TypeData,
|
||||
.constructor = (object_constructor)InterpreterObject::constructor,
|
||||
.destructor = (object_destructor)InterpreterObject::destructor,
|
||||
.size = sizeof(InterpreterObject),
|
||||
.name = "interpreter",
|
||||
.load = (object_load)InterpreterObject::load,
|
||||
};
|
||||
104
Objects/private/primitives/intobject.cpp
Normal file
104
Objects/private/primitives/intobject.cpp
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "NewPlacement.hpp"
|
||||
|
||||
#include "primitives/intobject.h"
|
||||
|
||||
using namespace obj;
|
||||
using namespace tp;
|
||||
|
||||
void IntObject::constructor(Object* self) {
|
||||
NDO_CAST(IntObject, self)->val = 0;
|
||||
}
|
||||
|
||||
void IntObject::copy(IntObject* self, const IntObject* in) {
|
||||
self->val = in->val;
|
||||
}
|
||||
|
||||
IntObject* IntObject::create(alni in) {
|
||||
NDO_CASTV(IntObject, NDO->create("int"), out)->val = in;
|
||||
return out;
|
||||
}
|
||||
|
||||
void IntObject::from_int(Object* self, alni in) {
|
||||
NDO_CAST(IntObject, self)->val = in;
|
||||
}
|
||||
|
||||
void IntObject::from_float(Object* self, alnf in) {
|
||||
NDO_CAST(IntObject, self)->val = (alni)in;
|
||||
}
|
||||
|
||||
void IntObject::from_string(Object* self, String in) {
|
||||
NDO_CAST(IntObject, self)->val = alni(in);
|
||||
}
|
||||
|
||||
String IntObject::to_string(Object* self) {
|
||||
return String(NDO_CAST(IntObject, self)->val);
|
||||
}
|
||||
|
||||
alni IntObject::to_int(Object* self) {
|
||||
return alni(NDO_CAST(IntObject, self)->val);
|
||||
}
|
||||
|
||||
alnf IntObject::to_float(Object* self) {
|
||||
return alnf(NDO_CAST(IntObject, self)->val);
|
||||
}
|
||||
|
||||
static alni save_size(IntObject* self) {
|
||||
return sizeof(alni);
|
||||
}
|
||||
|
||||
static void save(IntObject* self, Archiver& file_self) {
|
||||
file_self.write<alni>(&self->val);
|
||||
}
|
||||
|
||||
static void load(Archiver& file_self, IntObject* self) {
|
||||
file_self.read<alni>(&self->val);
|
||||
}
|
||||
|
||||
struct ObjectTypeConversions IntObjectTypeConversions = {
|
||||
.from_int = IntObject::from_int,
|
||||
.from_float = IntObject::from_float,
|
||||
.from_string = IntObject::from_string,
|
||||
.to_string = IntObject::to_string,
|
||||
.to_int = IntObject::to_int,
|
||||
.to_float = IntObject::to_float,
|
||||
};
|
||||
|
||||
void divide(IntObject* self, IntObject* in) {
|
||||
self->val /= in->val;
|
||||
}
|
||||
|
||||
void mul(IntObject* self, IntObject* in) {
|
||||
self->val *= in->val;
|
||||
}
|
||||
|
||||
void sub(IntObject* self, IntObject* in) {
|
||||
self->val -= in->val;
|
||||
}
|
||||
|
||||
void add(IntObject* self, IntObject* in) {
|
||||
self->val += in->val;
|
||||
}
|
||||
|
||||
struct ObjectTypeAriphmetics IntObject::TypeAriphm = {
|
||||
.add = (object_add) add,
|
||||
.sub = (object_sub) sub,
|
||||
.mul = (object_mul) mul,
|
||||
.div = (object_div) divide,
|
||||
};
|
||||
|
||||
struct obj::ObjectType obj::IntObject::TypeData = {
|
||||
.base = NULL,
|
||||
.constructor = IntObject::constructor,
|
||||
.destructor = NULL,
|
||||
.copy = (object_copy) IntObject::copy,
|
||||
.size = sizeof(IntObject),
|
||||
.name = "int",
|
||||
.convesions = &IntObjectTypeConversions,
|
||||
.ariphmetics = &IntObject::TypeAriphm,
|
||||
.save_size = (object_save_size)save_size,
|
||||
.save = (object_save)save,
|
||||
.load = (object_load)load,
|
||||
};
|
||||
132
Objects/private/primitives/linkobject.cpp
Normal file
132
Objects/private/primitives/linkobject.cpp
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "NewPlacement.hpp"
|
||||
#include "primitives/linkobject.h"
|
||||
|
||||
using namespace obj;
|
||||
using namespace tp;
|
||||
|
||||
void LinkObject::constructor(Object* self) {
|
||||
NDO_CAST(LinkObject, self)->link = 0;
|
||||
}
|
||||
|
||||
void LinkObject::destructor(LinkObject* self) {
|
||||
if (self->link) NDO->destroy(self->link);
|
||||
}
|
||||
|
||||
void LinkObject::copy(Object* self, const Object* in) {
|
||||
NDO_CAST(LinkObject, self)->setLink(NDO_CAST(LinkObject, in)->link);
|
||||
}
|
||||
|
||||
LinkObject* LinkObject::create(Object* in) {
|
||||
NDO_CASTV(LinkObject, NDO->create("link"), out)->link = in;
|
||||
return out;
|
||||
}
|
||||
|
||||
alni LinkObject::save_size(LinkObject* self) {
|
||||
return sizeof(alni);
|
||||
}
|
||||
|
||||
void LinkObject::save(LinkObject* self, Archiver& file_self) {
|
||||
if (self->link != NULL) {
|
||||
alni link_object_save_adress = NDO->save(file_self, self->link);
|
||||
file_self.write<alni>(&link_object_save_adress);
|
||||
}
|
||||
else {
|
||||
alni null = -1;
|
||||
file_self.write<alni>(&null);
|
||||
}
|
||||
}
|
||||
|
||||
void LinkObject::load(Archiver& file_self, LinkObject* self) {
|
||||
|
||||
alni saved_object_adress;
|
||||
file_self.read<alni>(&saved_object_adress);
|
||||
|
||||
if (saved_object_adress == -1) {
|
||||
self->link = NULL;
|
||||
}
|
||||
else {
|
||||
self->link = NDO->load(file_self, saved_object_adress);
|
||||
}
|
||||
}
|
||||
|
||||
tp::Buffer<Object*> LinkObject::childs_retrival(LinkObject* self) {
|
||||
tp::Buffer<Object*> out;
|
||||
if (self->link) out.append(self->link);
|
||||
return out;
|
||||
}
|
||||
|
||||
alni LinkObject::allocated_size(LinkObject* self) {
|
||||
return sizeof(Object*);
|
||||
}
|
||||
|
||||
alni LinkObject::allocated_size_recursive(LinkObject* self) {
|
||||
alni out = sizeof(Object*);
|
||||
if (self->link) {
|
||||
out += NDO->objsize_ram_recursive_util(self->link, self->link->type);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Object* LinkObject::getLink() {
|
||||
return link;
|
||||
}
|
||||
|
||||
void LinkObject::setLink(Object* obj) {
|
||||
#ifdef OBJECT_REF_COUNT
|
||||
if (link) NDO->destroy(link);
|
||||
if (obj) NDO->refinc(obj);
|
||||
#endif // OBJECT_REF_COUNT
|
||||
link = obj;
|
||||
}
|
||||
|
||||
static auto tm_set = TypeMethod{
|
||||
.nameid = "set",
|
||||
.descr = "sets the link",
|
||||
.args = {
|
||||
{ "target", NULL }
|
||||
},
|
||||
.exec = [](const TypeMethod* tm) {
|
||||
auto const self = (LinkObject*)tm->self;
|
||||
auto const target = tm->args[0].obj;
|
||||
self->setLink(target);
|
||||
}
|
||||
};
|
||||
|
||||
static auto tm_get = TypeMethod{
|
||||
.nameid = "get",
|
||||
.descr = "gets the link",
|
||||
.exec = [](const TypeMethod* tm) {
|
||||
auto const self = (LinkObject*)tm->self;
|
||||
auto link = self->getLink();
|
||||
if (link) {
|
||||
tm->ret.obj = link;
|
||||
}
|
||||
},
|
||||
.ret = { "the link", NULL }
|
||||
};
|
||||
|
||||
struct obj::ObjectType LinkObject::TypeData = {
|
||||
.base = NULL,
|
||||
.constructor = LinkObject::constructor,
|
||||
.destructor = (object_destructor)LinkObject::destructor,
|
||||
.copy = LinkObject::copy,
|
||||
.size = sizeof(LinkObject),
|
||||
.name = "link",
|
||||
.convesions = NULL,
|
||||
.save_size = (object_save_size)LinkObject::save_size,
|
||||
.save = (object_save)LinkObject::save,
|
||||
.load = (object_load)LinkObject::load,
|
||||
.childs_retrival = (object_debug_all_childs_retrival)LinkObject::childs_retrival,
|
||||
.allocated_size = (object_allocated_size)LinkObject::allocated_size,
|
||||
.allocated_size_recursive = (object_allocated_size_recursive)LinkObject::allocated_size_recursive,
|
||||
|
||||
.type_methods = {
|
||||
.methods = {
|
||||
&tm_set,
|
||||
&tm_get,
|
||||
}
|
||||
}
|
||||
};
|
||||
135
Objects/private/primitives/listobject.cpp
Normal file
135
Objects/private/primitives/listobject.cpp
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "NewPlacement.hpp"
|
||||
|
||||
#include "primitives/listobject.h"
|
||||
#include "primitives/intobject.h"
|
||||
|
||||
using namespace obj;
|
||||
using namespace tp;
|
||||
|
||||
void ListObject::constructor(Object* in) {
|
||||
NDO_CASTV(ListObject, in, self);
|
||||
new (&self->items) List<Object*>();
|
||||
}
|
||||
|
||||
void ListObject::copy(Object* in, const Object* target) {
|
||||
NDO_CASTV(ListObject, in, self);
|
||||
NDO_CASTV(ListObject, target, src);
|
||||
|
||||
destructor(in);
|
||||
|
||||
for (auto item : src->items) {
|
||||
self->pushBack(NDO->instatiate(item.data()));
|
||||
}
|
||||
}
|
||||
|
||||
void ListObject::destructor(Object* in) {
|
||||
NDO_CASTV(ListObject, in, self);
|
||||
for (auto item : self->items) {
|
||||
NDO->destroy(item.data());
|
||||
}
|
||||
self->items.removeAll();
|
||||
}
|
||||
|
||||
alni ListObject::save_size(ListObject* self) {
|
||||
alni len = self->items.length();
|
||||
return (len + 1) * sizeof(alni);
|
||||
}
|
||||
|
||||
void ListObject::save(ListObject* self, Archiver& file_self) {
|
||||
alni len = self->items.length();
|
||||
file_self.write<alni>(&len);
|
||||
|
||||
for (auto item : self->items) {
|
||||
alni ndo_object_adress = NDO->save(file_self, item.data());
|
||||
file_self.write<alni>(&ndo_object_adress);
|
||||
}
|
||||
}
|
||||
|
||||
void ListObject::load(Archiver& file_self, ListObject* self) {
|
||||
new (&self->items) tp::List<Object*>();
|
||||
|
||||
alni len;
|
||||
file_self.read<alni>(&len);
|
||||
|
||||
for (alni i = 0; i < len; i++) {
|
||||
alni ndo_object_adress;
|
||||
file_self.read<alni>(&ndo_object_adress);
|
||||
self->items.pushBack(NDO->load(file_self, ndo_object_adress));
|
||||
}
|
||||
}
|
||||
|
||||
tp::Buffer<Object*> ListObject::childs_retrival(ListObject* self) {
|
||||
tp::Buffer<Object*> out;
|
||||
out.reserve(self->items.length());
|
||||
ualni i = 0;
|
||||
for (auto item : self->items) {
|
||||
out[i] = item.data();
|
||||
i++;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
alni ListObject::allocated_size(ListObject* self) {
|
||||
// return self->items.sizeAllocatedMem();
|
||||
return {};
|
||||
}
|
||||
|
||||
alni ListObject::allocated_size_recursive(ListObject* self) {
|
||||
alni out = self->items.sizeAllocatedMem();
|
||||
for (auto item : self->items) {
|
||||
out += NDO->objsize_ram_recursive_util(item.data(), item->type);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void ListObject::pushBack(Object* obj) {
|
||||
#ifdef OBJECT_REF_COUNT
|
||||
obj::NDO->refinc(obj);
|
||||
#endif // OBJECT_REF_COUNT
|
||||
items.pushBack(obj);
|
||||
}
|
||||
|
||||
void ListObject::pushFront(Object* obj) {
|
||||
#ifdef OBJECT_REF_COUNT
|
||||
obj::NDO->refinc(obj);
|
||||
#endif // OBJECT_REF_COUNT
|
||||
items.pushFront(obj);
|
||||
}
|
||||
|
||||
void ListObject::delNode(tp::List<Object*>::Node* node) {
|
||||
#ifdef OBJECT_REF_COUNT
|
||||
obj::NDO->destroy(node->data);
|
||||
#endif // OBJECT_REF_COUNT
|
||||
items.deleteNode(node);
|
||||
}
|
||||
|
||||
void ListObject::popBack() {
|
||||
#ifdef OBJECT_REF_COUNT
|
||||
auto obj = items.last();
|
||||
if (obj) obj::NDO->destroy(obj->data);
|
||||
#endif // OBJECT_REF_COUNT
|
||||
items.popBack();
|
||||
}
|
||||
|
||||
const tp::List<Object*>& ListObject::getItems() const {
|
||||
return items;
|
||||
}
|
||||
|
||||
struct obj::ObjectType obj::ListObject::TypeData = {
|
||||
.base = NULL,
|
||||
.constructor = ListObject::constructor,
|
||||
.destructor = ListObject::destructor,
|
||||
.copy = ListObject::copy,
|
||||
.size = sizeof(ListObject),
|
||||
.name = "list",
|
||||
.convesions = NULL,
|
||||
.save_size = (object_save_size)save_size,
|
||||
.save = (object_save)save,
|
||||
.load = (object_load)load,
|
||||
.childs_retrival = (object_debug_all_childs_retrival) childs_retrival,
|
||||
.allocated_size = (object_allocated_size) allocated_size,
|
||||
.allocated_size_recursive = (object_allocated_size_recursive) allocated_size_recursive
|
||||
};
|
||||
78
Objects/private/primitives/methodobject.cpp
Normal file
78
Objects/private/primitives/methodobject.cpp
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
#pragma once
|
||||
|
||||
#include "NewPlacement.hpp"
|
||||
|
||||
#include "primitives/methodobject.h"
|
||||
#include "core/scriptsection.h"
|
||||
#include "compiler/function.h"
|
||||
|
||||
using namespace obj;
|
||||
|
||||
struct ObjectType MethodObject::TypeData = {
|
||||
.base = NULL,
|
||||
.constructor = (object_constructor)MethodObject::constructor,
|
||||
.destructor = (object_destructor)MethodObject::destructor,
|
||||
.copy = (object_copy)MethodObject::copy,
|
||||
.size = sizeof(MethodObject),
|
||||
.name = "method",
|
||||
.convesions = NULL,
|
||||
.save_size = (object_save_size)MethodObject::save_size,
|
||||
.save = (object_save)MethodObject::save,
|
||||
.load = (object_load)MethodObject::load,
|
||||
};
|
||||
|
||||
void MethodObject::constructor(MethodObject* self) {
|
||||
self->mScript = obj::ScriptSection::globalHandle()->createScript();
|
||||
}
|
||||
|
||||
void MethodObject::copy(MethodObject* self, MethodObject* in) {
|
||||
obj::ScriptSection::globalHandle()->changeScript(&self->mScript, &in->mScript);
|
||||
}
|
||||
|
||||
void MethodObject::destructor(MethodObject* self) {
|
||||
obj::ScriptSection::globalHandle()->abandonScript(self->mScript);
|
||||
}
|
||||
|
||||
tp::alni MethodObject::save_size(MethodObject* self) {
|
||||
// script_table_file_address & script string object address
|
||||
return sizeof(tp::alni);
|
||||
}
|
||||
|
||||
void MethodObject::save(MethodObject* self, Archiver& file_self) {
|
||||
auto script_section = obj::ScriptSection::globalHandle();
|
||||
|
||||
// script_table_file_address
|
||||
tp::alni script_table_file_address = script_section->get_script_file_adress(self->mScript);
|
||||
file_self.write<tp::alni>(&script_table_file_address);
|
||||
}
|
||||
|
||||
void MethodObject::load(Archiver& file_self, obj::MethodObject* self) {
|
||||
auto script_section = obj::ScriptSection::globalHandle();
|
||||
|
||||
// script_table_file_address
|
||||
tp::alni script_table_file_address;
|
||||
file_self.read<tp::alni>(&script_table_file_address);
|
||||
self->mScript = script_section->get_scritp_from_file_adress(script_table_file_address);
|
||||
}
|
||||
|
||||
|
||||
void MethodObject::Initialize() {
|
||||
obj::ScriptSection::initialize();
|
||||
NDO->define(&MethodObject::TypeData);
|
||||
obj::NDO->type_groups.addType(&MethodObject::TypeData, { "Primitives" });
|
||||
}
|
||||
|
||||
void MethodObject::UnInitialize() {
|
||||
obj::ScriptSection::uninitialize();
|
||||
}
|
||||
|
||||
void MethodObject::compile() {
|
||||
BCgen::Compile(this);
|
||||
}
|
||||
|
||||
MethodObject* MethodObject::create(tp::String script) {
|
||||
auto out = (MethodObject*)NDO->create(MethodObject::TypeData.name);
|
||||
out->mScript->mReadable->val = script;
|
||||
out->compile();
|
||||
return out;
|
||||
}
|
||||
60
Objects/private/primitives/nullobject.cpp
Normal file
60
Objects/private/primitives/nullobject.cpp
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "NewPlacement.hpp"
|
||||
|
||||
#include "primitives/nullobject.h"
|
||||
|
||||
using namespace obj;
|
||||
using namespace tp;
|
||||
|
||||
obj::NullObject* obj::NdoNull_globalInstance = NULL;
|
||||
bool uninit_flag = false;
|
||||
|
||||
void NullObject::uninit() {
|
||||
uninit_flag = true;
|
||||
NDO->destroy(NdoNull_globalInstance);
|
||||
}
|
||||
|
||||
void NullObject::destructor(Object* self) {
|
||||
DEBUG_ASSERT(uninit_flag && "Only one the instance of NullObject exists and thus it can't be destroyed");
|
||||
}
|
||||
|
||||
|
||||
String to_string(NullObject* self) {
|
||||
return "NULL";
|
||||
}
|
||||
|
||||
alni to_int(NullObject* self) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
alnf to_float(NullObject* self) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
obj::TypeMethods* tm_construct() {
|
||||
auto out = new obj::TypeMethods();
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
struct ObjectTypeConversions NullObjectTypeConversions = {
|
||||
.from_int = NULL,
|
||||
.from_float = NULL,
|
||||
.from_string = NULL,
|
||||
.to_string = (object_to_string) to_string,
|
||||
.to_int = (object_to_int) to_int,
|
||||
.to_float = (object_to_float) to_float,
|
||||
};
|
||||
|
||||
|
||||
struct ObjectType NullObject::TypeData = {
|
||||
.base = NULL,
|
||||
.constructor = NULL,
|
||||
.destructor = NullObject::destructor,
|
||||
.copy = NULL,
|
||||
.size = sizeof(NullObject),
|
||||
.name = "null",
|
||||
.convesions = &NullObjectTypeConversions,
|
||||
};
|
||||
83
Objects/private/primitives/primitives.cpp
Normal file
83
Objects/private/primitives/primitives.cpp
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "NewPlacement.hpp"
|
||||
|
||||
#include "primitives/primitives.h"
|
||||
|
||||
#include "Tokenizer.hpp"
|
||||
|
||||
void obj::primitives_uninitialize() {
|
||||
obj::NullObject::uninit();
|
||||
obj::MethodObject::UnInitialize();
|
||||
}
|
||||
|
||||
void obj::primitives_define_types() {
|
||||
|
||||
using namespace obj;
|
||||
using namespace tp;
|
||||
|
||||
static bool initialized = false;
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_ASSERT(NDO && "Objects library is not initialized");
|
||||
|
||||
NDO->define(&DictObject::TypeData);
|
||||
NDO->define(&IntObject::TypeData);
|
||||
NDO->define(&LinkObject::TypeData);
|
||||
NDO->define(&ListObject::TypeData);
|
||||
NDO->define(&NullObject::TypeData);
|
||||
NDO->define(&StringObject::TypeData);
|
||||
NDO->define(&BoolObject::TypeData);
|
||||
NDO->define(&FloatObject::TypeData);
|
||||
NDO->define(&EnumObject::TypeData);
|
||||
NDO->define(&ClassObject::TypeData);
|
||||
NDO->define(&ColorObject::TypeData);
|
||||
NDO->define(&InterpreterObject::TypeData);
|
||||
NDO->define(&TypeObject::TypeData);
|
||||
|
||||
NDO->type_groups.addType(&DictObject::TypeData, {"Primitives"});
|
||||
NDO->type_groups.addType(&IntObject::TypeData, {"Primitives"});
|
||||
NDO->type_groups.addType(&LinkObject::TypeData, {"Primitives"});
|
||||
NDO->type_groups.addType(&ListObject::TypeData, {"Primitives"});
|
||||
NDO->type_groups.addType(&NullObject::TypeData, {"Primitives"});
|
||||
NDO->type_groups.addType(&StringObject::TypeData, {"Primitives"});
|
||||
NDO->type_groups.addType(&BoolObject::TypeData, {"Primitives"});
|
||||
NDO->type_groups.addType(&FloatObject::TypeData, {"Primitives"});
|
||||
NDO->type_groups.addType(&EnumObject::TypeData, {"Primitives"});
|
||||
NDO->type_groups.addType(&ClassObject::TypeData, {"Primitives"});
|
||||
NDO->type_groups.addType(&ColorObject::TypeData, {"Primitives"});
|
||||
NDO->type_groups.addType(&InterpreterObject::TypeData, { "scripting" });
|
||||
|
||||
obj::MethodObject::Initialize();
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
namespace obj {
|
||||
objects_api* objects_init();
|
||||
void objects_finalize();
|
||||
};
|
||||
|
||||
static bool objInit() {
|
||||
obj::objects_init();
|
||||
obj::primitives_define_types();
|
||||
return true;
|
||||
}
|
||||
|
||||
static void objDeinit() {
|
||||
obj::primitives_uninitialize();
|
||||
obj::objects_finalize();
|
||||
}
|
||||
|
||||
static tp::ModuleManifest* sModuleDependencies[] = {
|
||||
// &tp::gModuleCompressor,
|
||||
&tp::gModuleMath,
|
||||
&tp::gModuleStrings,
|
||||
&tp::gModuleTokenizer,
|
||||
NULL
|
||||
};
|
||||
|
||||
tp::ModuleManifest obj::gModuleObjects = tp::ModuleManifest("Objects", objInit, objDeinit, sModuleDependencies);
|
||||
97
Objects/private/primitives/stringobject.cpp
Normal file
97
Objects/private/primitives/stringobject.cpp
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "NewPlacement.hpp"
|
||||
|
||||
#include "primitives/stringobject.h"
|
||||
|
||||
using namespace obj;
|
||||
using namespace tp;
|
||||
|
||||
void StringObject::constructor(Object* self) {
|
||||
new (&NDO_CAST(StringObject, self)->val) String();
|
||||
}
|
||||
|
||||
void StringObject::destructor(StringObject* self) {
|
||||
self->val.~String();
|
||||
}
|
||||
|
||||
void StringObject::copy(Object* self, const Object* in) {
|
||||
NDO_CAST(StringObject, self)->val = NDO_CAST(StringObject, in)->val;
|
||||
}
|
||||
|
||||
StringObject* StringObject::create(String in) {
|
||||
NDO_CASTV(StringObject, NDO->create("str"), out)->val = in;
|
||||
return out;
|
||||
}
|
||||
|
||||
void StringObject::from_int(StringObject* self, alni in) {
|
||||
// self->val = in;
|
||||
}
|
||||
|
||||
void StringObject::from_float(StringObject* self, alnf in) {
|
||||
// self->val = in;
|
||||
}
|
||||
|
||||
void StringObject::from_string(StringObject* self, String in) {
|
||||
// self->val = in;
|
||||
}
|
||||
|
||||
String StringObject::to_string(StringObject* self) {
|
||||
return self->val;
|
||||
}
|
||||
|
||||
alni StringObject::to_int(StringObject* self) {
|
||||
return alni(self->val);
|
||||
}
|
||||
|
||||
alnf StringObject::to_float(StringObject* self) {
|
||||
return alnf(self->val);
|
||||
}
|
||||
|
||||
static alni save_size(StringObject* self) {
|
||||
// return self->val.save_size();
|
||||
return {};
|
||||
}
|
||||
|
||||
static void save(StringObject* self, Archiver& file_self) {
|
||||
self->val.save(&file_self);
|
||||
}
|
||||
|
||||
static void load(Archiver& file_self, StringObject* self) {
|
||||
new (&self->val) tp::String();
|
||||
self->val.load(&file_self);
|
||||
}
|
||||
|
||||
alni allocated_size(StringObject* self) {
|
||||
// return self->val.sizeAllocatedMem();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool compare_strings(StringObject* left, StringObject* right) {
|
||||
return left->val == right->val;
|
||||
}
|
||||
|
||||
struct ObjectTypeConversions StringObjectTypeConversions = {
|
||||
.from_int = (object_from_int)StringObject::from_int,
|
||||
.from_float = (object_from_float)StringObject::from_float,
|
||||
.from_string = (object_from_string)StringObject::from_string,
|
||||
.to_string = (object_to_string)StringObject::to_string,
|
||||
.to_int = (object_to_int)StringObject::to_int,
|
||||
.to_float = (object_to_float)StringObject::to_float,
|
||||
};
|
||||
|
||||
struct obj::ObjectType StringObject::TypeData = {
|
||||
.base = NULL,
|
||||
.constructor = StringObject::constructor,
|
||||
.destructor = (object_destructor)StringObject::destructor,
|
||||
.copy = StringObject::copy,
|
||||
.size = sizeof(StringObject),
|
||||
.name = "str",
|
||||
.convesions = &StringObjectTypeConversions,
|
||||
.save_size = (object_save_size)save_size,
|
||||
.save = (object_save)save,
|
||||
.load = (object_load)load,
|
||||
.comparison = (object_compare) compare_strings,
|
||||
.allocated_size = (object_allocated_size) allocated_size,
|
||||
};
|
||||
80
Objects/private/primitives/typeobject.cpp
Normal file
80
Objects/private/primitives/typeobject.cpp
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "NewPlacement.hpp"
|
||||
#include "primitives/typeobject.h"
|
||||
#include "primitives/nullobject.h"
|
||||
|
||||
using namespace obj;
|
||||
using namespace tp;
|
||||
|
||||
TypeObject* TypeObject::create(const ObjectType* type) {
|
||||
NDO_CASTV(TypeObject, NDO->create("typeobject"), out);
|
||||
out->mTypeRef = type;
|
||||
return out;
|
||||
}
|
||||
|
||||
static alni save_size(TypeObject* self) {
|
||||
tp::String const nameid(self->mTypeRef->name);
|
||||
return nameid.save_size();
|
||||
}
|
||||
|
||||
static void save(TypeObject* self, Archiver& file_self) {
|
||||
tp::String const nameid(self->mTypeRef->name);
|
||||
nameid.save(&file_self);
|
||||
}
|
||||
|
||||
static void load(Archiver& file_self, TypeObject* self) {
|
||||
tp::String nameid;
|
||||
nameid.load(&file_self);
|
||||
|
||||
auto idx = NDO->types.presents(nameid);
|
||||
|
||||
if (idx) {
|
||||
self->mTypeRef = NDO->types.getSlotVal(idx);
|
||||
}
|
||||
else {
|
||||
self->mTypeRef = &NullObject::TypeData;
|
||||
}
|
||||
}
|
||||
|
||||
static alni allocated_size(TypeObject* self) {
|
||||
return sizeof(alni);
|
||||
}
|
||||
|
||||
static void from_string(TypeObject* self, tp::String in) {
|
||||
auto idx = NDO->types.presents(in);
|
||||
|
||||
if (idx) {
|
||||
self->mTypeRef = NDO->types.getSlotVal(idx);
|
||||
}
|
||||
else {
|
||||
self->mTypeRef = &NullObject::TypeData;
|
||||
}
|
||||
}
|
||||
|
||||
static String to_string(TypeObject* self) {
|
||||
return self->mTypeRef->name;
|
||||
}
|
||||
|
||||
bool comparator(TypeObject* left, TypeObject* right) {
|
||||
return left->mTypeRef == right->mTypeRef;
|
||||
}
|
||||
|
||||
static struct ObjectTypeConversions conversions = {
|
||||
.from_string = (object_from_string) from_string,
|
||||
.to_string = (object_to_string) to_string,
|
||||
};
|
||||
|
||||
struct obj::ObjectType TypeObject::TypeData = {
|
||||
.base = NULL,
|
||||
//.constructor = (object_constructor) TypeObject::constructor,
|
||||
.size = sizeof(TypeObject),
|
||||
.name = "typeobject",
|
||||
.convesions = &conversions,
|
||||
.save_size = (object_save_size) save_size,
|
||||
.save = (object_save) save,
|
||||
.load = (object_load) load,
|
||||
.comparison = (object_compare) comparator,
|
||||
.allocated_size = (object_allocated_size) allocated_size,
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue