diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d883a0..d0d6658 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,3 +24,5 @@ add_subdirectory(Externals) add_subdirectory(Connection) add_subdirectory(Graphics) + +add_subdirectory(Objects) diff --git a/Containers/public/Buffer.hpp b/Containers/public/Buffer.hpp index 71af4b7..31ab348 100644 --- a/Containers/public/Buffer.hpp +++ b/Containers/public/Buffer.hpp @@ -20,42 +20,111 @@ namespace tp { template class ConstSizeBuffer { - SelCopyArg Arg; + typedef SelCopyArg Arg; private: tType mBuff[tSize]; + ualni mLoad = 0; public: ConstSizeBuffer() = default; public: - [[nodiscard]] ualni size() const { return tSize; } + [[nodiscard]] ualni size() const { return mLoad; } + [[nodiscard]] ualni getBuffSize() const { return tSize; } - tType& first() { - return *mBuff; - } - - const tType& first() const { - return *mBuff; + tType& first() { + DEBUG_ASSERT(mLoad) + return *mBuff; } - tType& last() { - return mBuff[tSize - 1]; + const tType& first() const { + DEBUG_ASSERT(mLoad) + return *mBuff; } - - const tType& last() const { - return mBuff[tSize - 1]; + + tType& last() { + DEBUG_ASSERT(mLoad) + return mBuff[mLoad - 1]; + } + + const tType& last() const { + DEBUG_ASSERT(mLoad) + return mBuff[mLoad - 1]; } tType& operator[](ualni aIdx) { - DEBUG_ASSERT(aIdx >= 0 && aIdx < tSize) + DEBUG_ASSERT(aIdx >= 0 && aIdx < mLoad) return mBuff[aIdx]; } const tType& operator[](ualni aIdx) const { - DEBUG_ASSERT(aIdx >= 0 && aIdx < tSize) + DEBUG_ASSERT(aIdx >= 0 && aIdx < mLoad) return mBuff[aIdx]; } + + void append(Arg data) { + ASSERT(mLoad != tSize) + new (&mBuff[mLoad]) tType(data); + mLoad++; + } + + void pop() { + DEBUG_ASSERT(mLoad) + mBuff[mLoad].~tType(); + mLoad--; + } + + ConstSizeBuffer& operator=(const tp::init_list& init) { + for (auto arg : init) { + append(arg); + } + return *this; + } + + public: + + class IteratorPointer { + protected: + tType* mIter; + public: + IteratorPointer() = default; + tType& operator->() { return *mIter; } + const tType& operator->() const { return *mIter; } + }; + + class IteratorReference { + protected: + tType* mIter; + public: + IteratorReference() = default; + tType* operator->() { return mIter; } + const tType* operator->() const { return mIter; } + }; + + class Iterator : public TypeSelect::isPointer, IteratorPointer, IteratorReference>::Result { + public: + + explicit Iterator(tType* iter) { this->mIter = iter; } + + const Iterator& operator*() const { return *this; } + + Iterator& operator++() { + this->mIter++; + return *this; + } + + bool operator==(const Iterator& left) const { return left.mIter == this->mIter; } + bool operator!=(const Iterator& left) const { return left.mIter != this->mIter; } + }; + + [[nodiscard]] Iterator begin() const { + return Iterator(mBuff); + } + + [[nodiscard]] Iterator end() const { + return Iterator(mBuff + mLoad); + } }; template< @@ -150,6 +219,14 @@ namespace tp { } public: + Buffer& operator=(const tp::init_list& init) { + // TODO : optimize + for (auto arg : init) { + append(arg); + } + return *this; + } + void append(Arg data) { if (mLoad == mSize) resizeBuffer(tResizePolicy(mSize)); new (&mBuff[mLoad]) tType(data); @@ -183,6 +260,53 @@ namespace tp { for (ualni i = 0; i < mLoad; i++) new (mBuff + i) tType(); } + public: + class IteratorPointer { + protected: + tType* mIter; + public: + IteratorPointer() = default; + tType& operator->() { return *mIter; } + const tType& operator->() const { return *mIter; } + }; + + class IteratorReference { + protected: + tType* mIter; + public: + IteratorReference() = default; + tType* operator->() { return mIter; } + const tType* operator->() const { return mIter; } + }; + + class Iterator : public TypeSelect::isPointer, IteratorPointer, IteratorReference>::Result { + public: + + explicit Iterator(tType* iter) { this->mIter = iter; } + + const Iterator& operator*() const { return *this; } + + tType& data() { + return *this->mIter; + } + + Iterator& operator++() { + this->mIter++; + return *this; + } + + bool operator==(const Iterator& left) const { return left.mIter == this->mIter; } + bool operator!=(const Iterator& left) const { return left.mIter != this->mIter; } + }; + + [[nodiscard]] Iterator begin() const { + return Iterator(mBuff); + } + + [[nodiscard]] Iterator end() const { + return Iterator(mBuff + mLoad); + } + private: void resizeBuffer(ualni newSize) { DEBUG_ASSERT(newSize >= mLoad) diff --git a/Objects/CMakeLists.txt b/Objects/CMakeLists.txt new file mode 100644 index 0000000..a8e81b5 --- /dev/null +++ b/Objects/CMakeLists.txt @@ -0,0 +1,31 @@ + +cmake_minimum_required(VERSION 3.2) + +set(CMAKE_CXX_STANDARD 23) + +project(Objects) + +### ---------------------- Static Library --------------------- ### +file(GLOB SOURCES "./private/*.cpp" "./private/*/*.cpp") +file(GLOB HEADERS "./public/*.hpp" "./public/*/*.hpp") + +add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS}) + +target_include_directories(${PROJECT_NAME} PUBLIC ./public/) +target_link_libraries(${PROJECT_NAME} PUBLIC Strings Math Tokenizer CommandLine Connection) + +### -------------------------- Applications -------------------------- ### +add_executable(osc ./applications/Compiler.cpp) +add_executable(osi ./applications/Interpreter.cpp) + +target_link_libraries(osc ${PROJECT_NAME}) +target_link_libraries(osi ${PROJECT_NAME}) + +### -------------------------- Tests -------------------------- ### +enable_testing() +file(GLOB TEST_SOURCES "./tests/*.cpp") +add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES}) +target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Utils) +add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests) + +install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/lib) \ No newline at end of file diff --git a/Objects/README.md b/Objects/README.md new file mode 100644 index 0000000..c2ebb0e --- /dev/null +++ b/Objects/README.md @@ -0,0 +1,20 @@ + Objects + +Objects are simple structures with run-time type information attached.
+ +## Features +- Encapsulates most of the basic [types](https://github.com/IlyaShurupov/types.git) into primitives. +- Has its own scripting language to manipulate those objects at run-time. +- Can save and load any object at any point in execution. + +## TODO +- Dubug information support +- Run-time error handling +- Dead code elimination & optimization + +## Building +1. [Types](https://github.com/IlyaShurupov/types.git) repository must be in the same directory. +2. Export the parent path to the system variables. +``` +setx SRC_DIR "parent path" +``` diff --git a/Objects/applications/Compiler.cpp b/Objects/applications/Compiler.cpp new file mode 100644 index 0000000..93ef9c8 --- /dev/null +++ b/Objects/applications/Compiler.cpp @@ -0,0 +1,49 @@ + +#include "Compiler/Compiler.h" + +#include "primitives/primitives.h" +#include "MethodObject/MethodObject.h" +#include "log.h" + +using namespace osc; +using namespace tp; +using namespace obj; + +int main(int argc, char* argv[]) { + + tp::alloc_init(); + string::Initialize(); + Logger::init(); + + objects_init(); + primitives_define_types(); + MethodObject::Initialize(); + + { + Compiler compiler; + + tp::string script; + + RelAssert(argc == 2 && "Invalid Arguments"); + + script.loadFile(argv[1]); + + compiler.compile(script); + + GLog->write("oscc : compilation finished", 1); + } + + try { + MethodObject::UnInitialize(); + objects_finalize(); + primitives_uninitialize(); + + Logger::deinit(); + string::UnInitialize(); + tp::alloc_uninit(); + + } + catch (...) { + tp::terminate(); + } +} \ No newline at end of file diff --git a/Objects/applications/Interpreter.cpp b/Objects/applications/Interpreter.cpp new file mode 100644 index 0000000..d9b38da --- /dev/null +++ b/Objects/applications/Interpreter.cpp @@ -0,0 +1,58 @@ + + +#include "MethodObject/methodobject.h" +#include "primitives/primitives.h" + +#include "Interpreter/Interpreter.h" + +#include "log.h" + +using namespace osc; +using namespace tp; +using namespace obj; + +int main(int argc, char* argv[]) { + tp::alloc_init(); + string::Initialize(); + Logger::init(); + + objects_init(); + primitives_define_types(); + MethodObject::Initialize(); + + { + time_ms load_start = get_time(); + RelAssert(argc == 2 && "Invalid Arguments"); + auto obj = NDO->load(argv[1]); + RelAssert(obj && "Failed to Load the File"); + RelAssert(obj->type == &MethodObject::TypeData && "Innvalid file content"); + + Interpreter interp; + NDO_CASTV(MethodObject, obj, method); + + RelAssert(method->mScript && "Innvalid file content"); + time_ms load_end = get_time(); + + GLog->write("\noscvm - execution started\n"); + time_ms exec_start = get_time(); + interp.exec(&method->mScript->mBytecode); + time_ms exec_end = get_time(); + + auto exec_time = (exec_end - exec_start); + auto load_time = (load_end - load_start); + GLog->write(sfmt("\noscvm - execution finished (Load : %f Exec : %f)", load_time, exec_time)); + } + + try { + MethodObject::UnInitialize(); + objects_finalize(); + primitives_uninitialize(); + + Logger::deinit(); + string::UnInitialize(); + tp::alloc_uninit(); + + } catch (...) { + tp::terminate(); + } +} \ No newline at end of file diff --git a/Objects/private/compiler/constants.cpp b/Objects/private/compiler/constants.cpp new file mode 100644 index 0000000..3208eaa --- /dev/null +++ b/Objects/private/compiler/constants.cpp @@ -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& 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; +} \ No newline at end of file diff --git a/Objects/private/compiler/expression.cpp b/Objects/private/compiler/expression.cpp new file mode 100644 index 0000000..48a8390 --- /dev/null +++ b/Objects/private/compiler/expression.cpp @@ -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 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 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) {} diff --git a/Objects/private/compiler/function.cpp b/Objects/private/compiler/function.cpp new file mode 100644 index 0000000..014da8f --- /dev/null +++ b/Objects/private/compiler/function.cpp @@ -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 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::Node* jump_inst, tp::List::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::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; +} \ No newline at end of file diff --git a/Objects/private/compiler/instruction.cpp b/Objects/private/compiler/instruction.cpp new file mode 100644 index 0000000..90e2705 --- /dev/null +++ b/Objects/private/compiler/instruction.cpp @@ -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::Node* inst, InstType jump_type): mInstTarget(inst) { + mInstType = jump_type; +} \ No newline at end of file diff --git a/Objects/private/compiler/statement.cpp b/Objects/private/compiler/statement.cpp new file mode 100644 index 0000000..4d7e671 --- /dev/null +++ b/Objects/private/compiler/statement.cpp @@ -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 args, tp::init_list 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 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 args, tp::init_list 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 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); +} \ No newline at end of file diff --git a/Objects/private/core/object.cpp b/Objects/private/core/object.cpp new file mode 100644 index 0000000..c121ddb --- /dev/null +++ b/Objects/private/core/object.cpp @@ -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(); + } + +}; \ No newline at end of file diff --git a/Objects/private/core/objectsave.cpp b/Objects/private/core/objectsave.cpp new file mode 100644 index 0000000..138f741 --- /dev/null +++ b/Objects/private/core/objectsave.cpp @@ -0,0 +1,411 @@ + + +#include "core/object.h" + +#include "HeapAllocatorGlobal.hpp" + +#include + +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 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(&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++; + } +}; \ No newline at end of file diff --git a/Objects/private/core/scriptsection.cpp b/Objects/private/core/scriptsection.cpp new file mode 100644 index 0000000..6af3c54 --- /dev/null +++ b/Objects/private/core/scriptsection.cpp @@ -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(&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(&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(&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(&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(&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(&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(&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(&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(&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(&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; +} + diff --git a/Objects/private/core/typegroups.cpp b/Objects/private/core/typegroups.cpp new file mode 100644 index 0000000..e98af62 --- /dev/null +++ b/Objects/private/core/typegroups.cpp @@ -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 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(); + } +} \ No newline at end of file diff --git a/Objects/private/core/typemethods.cpp b/Objects/private/core/typemethods.cpp new file mode 100644 index 0000000..d756d2a --- /dev/null +++ b/Objects/private/core/typemethods.cpp @@ -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++; + } +} \ No newline at end of file diff --git a/Objects/private/interpreter/callstack.cpp b/Objects/private/interpreter/callstack.cpp new file mode 100644 index 0000000..ccf37aa --- /dev/null +++ b/Objects/private/interpreter/callstack.cpp @@ -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(); +} \ No newline at end of file diff --git a/Objects/private/interpreter/interpreter.cpp b/Objects/private/interpreter/interpreter.cpp new file mode 100644 index 0000000..7978c18 --- /dev/null +++ b/Objects/private/interpreter/interpreter.cpp @@ -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 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(); + auto id = mOperandsStack.getOperand(); + mScopeStack.addLocal(NDO->create(type->val), id->val); + break; + } + + case OpCode::DEF_LOCAL: { + auto id = mOperandsStack.getOperand(); + auto obj = mOperandsStack.getOperand(); + mScopeStack.addLocal(obj, id->val); + NDO->refinc(obj); + //mScopeStack.popTemp(); + break; + } + + case OpCode::OBJ_CREATE: { + auto type = mOperandsStack.getOperand(); + 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(); + 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(); + auto obj = NDO->load(path->val); + mScopeStack.addTemp(obj); + mOperandsStack.push(obj); + break; + } + case OpCode::OBJ_SAVE: { + auto path = mOperandsStack.getOperand(); + 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 globals2) { + if (!method->mScript->mBytecode.mInstructions.size()) { + return; + } + + exec(method, self, globals, globals2); + while (!finished()) { + stepBytecodeIn(); + } +} \ No newline at end of file diff --git a/Objects/private/interpreter/opcodes.cpp b/Objects/private/interpreter/opcodes.cpp new file mode 100644 index 0000000..b630b9e --- /dev/null +++ b/Objects/private/interpreter/opcodes.cpp @@ -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 list) { + DEBUG_ASSERT(MAX_OPERANDS >= list.size()); + for (auto item : list) { + buff[len] = item; + len++; + } +} + +OpcodeInfos::ParamsInfo::ParamsInfo() {} +OpcodeInfos::ParamsInfo::ParamsInfo(tp::init_list 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; +} \ No newline at end of file diff --git a/Objects/private/interpreter/operandsstack.cpp b/Objects/private/interpreter/operandsstack.cpp new file mode 100644 index 0000000..e037360 --- /dev/null +++ b/Objects/private/interpreter/operandsstack.cpp @@ -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; +} diff --git a/Objects/private/interpreter/scopestack.cpp b/Objects/private/interpreter/scopestack.cpp new file mode 100644 index 0000000..f00e408 --- /dev/null +++ b/Objects/private/interpreter/scopestack.cpp @@ -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); +} diff --git a/Objects/private/parser/parser.cpp b/Objects/private/parser/parser.cpp new file mode 100644 index 0000000..dacd225 --- /dev/null +++ b/Objects/private/parser/parser.cpp @@ -0,0 +1,904 @@ + +#include "Logging.hpp" +#include "List.hpp" + +#include "parser/parser.h" +#include "compiler/function.h" + +#include + +#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 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 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 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 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 expressions) { + + Expression* out = NULL; + + List 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 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 stm_types) { + Statement* out = NULL; + + List 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 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 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; +} diff --git a/Objects/private/primitives/boolobject.cpp b/Objects/private/primitives/boolobject.cpp new file mode 100644 index 0000000..8d1bd3a --- /dev/null +++ b/Objects/private/primitives/boolobject.cpp @@ -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(&self->val); +} + +static void load(Archiver& file_self, BoolObject* self) { + file_self.read(&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, +}; \ No newline at end of file diff --git a/Objects/private/primitives/classobject.cpp b/Objects/private/primitives/classobject.cpp new file mode 100644 index 0000000..2bfad9d --- /dev/null +++ b/Objects/private/primitives/classobject.cpp @@ -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(&ndo_object_adress); +} + +void ClassObject::load(Archiver& file_self, ClassObject* self) { + alni ndo_object_adress; + file_self.read(&ndo_object_adress); + self->members = NDO_CAST(DictObject, NDO->load(file_self, ndo_object_adress)); +} + +tp::Buffer childs_retrival(ClassObject* self) { + tp::Buffer 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 +}; diff --git a/Objects/private/primitives/colorobject.cpp b/Objects/private/primitives/colorobject.cpp new file mode 100644 index 0000000..587c663 --- /dev/null +++ b/Objects/private/primitives/colorobject.cpp @@ -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(&self->mCol); +} + +static void load(Archiver& file_self, ColorObject* self) { + file_self.read(&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, +}; \ No newline at end of file diff --git a/Objects/private/primitives/dictobject.cpp b/Objects/private/primitives/dictobject.cpp new file mode 100644 index 0000000..483c625 --- /dev/null +++ b/Objects/private/primitives/dictobject.cpp @@ -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(); +} + +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(&len); + + // save hashmap pairs + for (auto item : self->items) { + // item val + alni ndo_object_adress = NDO->save(file_self, item->val); + file_self.write(&ndo_object_adress); + + // item key + item->key.save(&file_self); + } +} + +void DictObject::load(Archiver& file_self, DictObject* self) { + new (&self->items) tp::Map(); + + alni len; + file_self.read(&len); + + for (alni i = 0; i < len; i++) { + + // read val + alni ndo_object_adress; + file_self.read(&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 DictObject::childs_retrival(DictObject* self) { + tp::Buffer 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::Idx DictObject::presents(tp::String str) { + return items.presents(str); +} + +Object* DictObject::getSlotVal(tp::alni idx) { + return items.getSlotVal(idx); +} + +const tp::Map& 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, + } + } +}; diff --git a/Objects/private/primitives/enumobject.cpp b/Objects/private/primitives/enumobject.cpp new file mode 100644 index 0000000..bc6523e --- /dev/null +++ b/Objects/private/primitives/enumobject.cpp @@ -0,0 +1,182 @@ + +#pragma once + +#include "NewPlacement.hpp" +#include "primitives/enumobject.h" + +#include + +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 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(&empty_code); + return; + } + file_self.write(&self->active); + file_self.write(&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(&self->active); + if (self->active == -1) { + self->nentries = 0; + self->entries = NULL; + return; + } + file_self.read(&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 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, +}; \ No newline at end of file diff --git a/Objects/private/primitives/floatobject.cpp b/Objects/private/primitives/floatobject.cpp new file mode 100644 index 0000000..470273f --- /dev/null +++ b/Objects/private/primitives/floatobject.cpp @@ -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(&self->val); +} + +static void load(Archiver& file_self, FloatObject* self) { + file_self.read(&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, +}; \ No newline at end of file diff --git a/Objects/private/primitives/interpreterobject.cpp b/Objects/private/primitives/interpreterobject.cpp new file mode 100644 index 0000000..8732922 --- /dev/null +++ b/Objects/private/primitives/interpreterobject.cpp @@ -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 globals) { + + if (running()) { + return; + } + + auto link_target = getMember("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("globals"), globals); +} + +void InterpreterObject::debug() { + if (running()) { + return; + } + + auto link_target = getMember("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("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, +}; \ No newline at end of file diff --git a/Objects/private/primitives/intobject.cpp b/Objects/private/primitives/intobject.cpp new file mode 100644 index 0000000..06de36a --- /dev/null +++ b/Objects/private/primitives/intobject.cpp @@ -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(&self->val); +} + +static void load(Archiver& file_self, IntObject* self) { + file_self.read(&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, +}; \ No newline at end of file diff --git a/Objects/private/primitives/linkobject.cpp b/Objects/private/primitives/linkobject.cpp new file mode 100644 index 0000000..fb10d8b --- /dev/null +++ b/Objects/private/primitives/linkobject.cpp @@ -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(&link_object_save_adress); + } + else { + alni null = -1; + file_self.write(&null); + } +} + +void LinkObject::load(Archiver& file_self, LinkObject* self) { + + alni saved_object_adress; + file_self.read(&saved_object_adress); + + if (saved_object_adress == -1) { + self->link = NULL; + } + else { + self->link = NDO->load(file_self, saved_object_adress); + } +} + +tp::Buffer LinkObject::childs_retrival(LinkObject* self) { + tp::Buffer 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, + } + } +}; \ No newline at end of file diff --git a/Objects/private/primitives/listobject.cpp b/Objects/private/primitives/listobject.cpp new file mode 100644 index 0000000..cd6b3f5 --- /dev/null +++ b/Objects/private/primitives/listobject.cpp @@ -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(); +} + +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(&len); + + for (auto item : self->items) { + alni ndo_object_adress = NDO->save(file_self, item.data()); + file_self.write(&ndo_object_adress); + } +} + +void ListObject::load(Archiver& file_self, ListObject* self) { + new (&self->items) tp::List(); + + alni len; + file_self.read(&len); + + for (alni i = 0; i < len; i++) { + alni ndo_object_adress; + file_self.read(&ndo_object_adress); + self->items.pushBack(NDO->load(file_self, ndo_object_adress)); + } +} + +tp::Buffer ListObject::childs_retrival(ListObject* self) { + tp::Buffer 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::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& 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 +}; \ No newline at end of file diff --git a/Objects/private/primitives/methodobject.cpp b/Objects/private/primitives/methodobject.cpp new file mode 100644 index 0000000..876c3f3 --- /dev/null +++ b/Objects/private/primitives/methodobject.cpp @@ -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(&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(&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; +} \ No newline at end of file diff --git a/Objects/private/primitives/nullobject.cpp b/Objects/private/primitives/nullobject.cpp new file mode 100644 index 0000000..846c842 --- /dev/null +++ b/Objects/private/primitives/nullobject.cpp @@ -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, +}; \ No newline at end of file diff --git a/Objects/private/primitives/primitives.cpp b/Objects/private/primitives/primitives.cpp new file mode 100644 index 0000000..5591845 --- /dev/null +++ b/Objects/private/primitives/primitives.cpp @@ -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); \ No newline at end of file diff --git a/Objects/private/primitives/stringobject.cpp b/Objects/private/primitives/stringobject.cpp new file mode 100644 index 0000000..678a956 --- /dev/null +++ b/Objects/private/primitives/stringobject.cpp @@ -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, +}; \ No newline at end of file diff --git a/Objects/private/primitives/typeobject.cpp b/Objects/private/primitives/typeobject.cpp new file mode 100644 index 0000000..3ce305c --- /dev/null +++ b/Objects/private/primitives/typeobject.cpp @@ -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, +}; \ No newline at end of file diff --git a/Objects/public/compiler/constants.h b/Objects/public/compiler/constants.h new file mode 100644 index 0000000..5a95697 --- /dev/null +++ b/Objects/public/compiler/constants.h @@ -0,0 +1,42 @@ + +#pragma once + +#include "interpreter/bytecode.h" +#include "core/object.h" + +namespace obj { + namespace BCgen { + + struct ConstObject { + obj::Object* mObj = NULL; + tp::alni mConstIdx = 0; + + ConstObject(); + ConstObject(obj::Object* mObj); + }; + + + struct ConstObjectsPool { + tp::Map mMethods; + tp::Map mStrings; + tp::Map mIntegers; + tp::Map mFloats; + ConstObject mBoolTrue; + ConstObject mBoolFalse; + + bool mDelete = true; + tp::alni mTotalObjects = 0; + + ConstObject* get(tp::alni val); + ConstObject* get(tp::String val); + ConstObject* get(tp::alnf val); + ConstObject* get(bool val); + + ConstObject* addMethod(tp::String method_id, obj::Object* method); + ConstObject* registerObject(obj::Object* obj); + void save(tp::Buffer& out); + + ~ConstObjectsPool(); + }; + }; +}; \ No newline at end of file diff --git a/Objects/public/compiler/expression.h b/Objects/public/compiler/expression.h new file mode 100644 index 0000000..c297b99 --- /dev/null +++ b/Objects/public/compiler/expression.h @@ -0,0 +1,126 @@ + +#pragma once + +#include "Strings.hpp" +#include "Buffer.hpp" + +#include "interpreter/opcodes.h" + +namespace obj { + namespace BCgen { + + struct ExpressionChild; + struct ExpressionCall; + + struct Expression { + + enum class Type { + NONE, + NEW, + LOCAL, + CONST, + CHILD, + CALL, + ARIPHM, + FUNC, + BOOLEAN, + SELF, + } mType = Type::NONE; + + bool mValueUsed = false; + + Expression(); + Expression(Type type); + + ExpressionChild* ExprChild(tp::String id); + ExpressionCall* ExprCall(tp::init_list args); + }; + + struct ExpressionNew : public Expression { + tp::String mNewType; + ExpressionNew(tp::String type); + }; + + struct ExpressionLocal : public Expression { + tp::String mLocalId; + ExpressionLocal(tp::String id); + }; + + struct ExpressionFunc : public Expression { + tp::String mFuncId; + ExpressionFunc(tp::String id); + }; + + struct ExpressionChild : public Expression { + Expression* mParent = NULL; + tp::String mLocalId; + bool mMethod = false; + ExpressionChild(Expression* mParent, tp::String id); + }; + + struct ExpressionCall : public Expression { + Expression* mParent = NULL; + tp::Buffer mArgs; + ExpressionCall(Expression* mParent, tp::init_list args); + }; + + struct ExpressionAriphm : public Expression { + Expression* mLeft = NULL; + Expression* mRight = NULL; + OpCode mOpType; + ExpressionAriphm(Expression* left, Expression* right, OpCode type); + }; + + struct ExpressionBoolean : public Expression { + Expression* mLeft = NULL; + Expression* mRight = NULL; + + enum class BoolType : tp::uint1 { + AND = 24U, + OR, + EQUAL, + NOT_EQUAL, + MORE, + LESS, + EQUAL_OR_MORE, + EQUAL_OR_LESS, + NOT, + } mBoolType; + + ExpressionBoolean(Expression* left, Expression* right, BoolType type); + ExpressionBoolean(Expression* invert); + }; + + struct ExpressionConst : public Expression { + enum ConstType { STR, INT, BOOL, FLT } mConstType; + tp::String str; + tp::alni integer = 0; + tp::alnf floating = 0; + bool boolean = 0; + + ExpressionConst(tp::String val); + ExpressionConst(const char* val); + ExpressionConst(tp::alni val); + ExpressionConst(tp::int4 val); + ExpressionConst(tp::flt4 val); + ExpressionConst(tp::alnf val); + ExpressionConst(bool val); + }; + + struct ExpressionSelf : public Expression { + ExpressionSelf(); + }; + + ExpressionLocal* ExprLocal(tp::String id); + ExpressionSelf* ExprSelf(); + ExpressionFunc* ExprFunc(tp::String id); + ExpressionNew* ExprNew(tp::String id); + ExpressionAriphm* ExprAriphm(Expression* left, Expression* right, OpCode type); + ExpressionBoolean* ExprBool(Expression* left, Expression* right, OpCode type); + ExpressionBoolean* ExprBoolNot(Expression* invert); + template + ExpressionConst* ExprConst(ConstType val) { + return new ExpressionConst(val); + } + }; +}; \ No newline at end of file diff --git a/Objects/public/compiler/function.h b/Objects/public/compiler/function.h new file mode 100644 index 0000000..a54df26 --- /dev/null +++ b/Objects/public/compiler/function.h @@ -0,0 +1,47 @@ + +#pragma once + +#include "Strings.hpp" +#include "List.hpp" +#include "Map.hpp" + +#include "instruction.h" +#include "statement.h" +#include "constants.h" + +namespace obj { + struct MethodObject; + + namespace BCgen { + + struct FunctionDefinition { + + FunctionDefinition* mPrnt = NULL; + + // signature + tp::String mFunctionId; + tp::List mArgsOrder; + + ConstObjectsPool mConstants; + tp::Map mLocals; + tp::List mInstructions; + + FunctionDefinition(tp::String function_id, tp::Buffer args, FunctionDefinition* prnt); + FunctionDefinition() {} + + void generateByteCode(ByteCode& out); + + tp::List::Node* inst(Instruction inst); + + void EvalExpr(Expression* expr); + void EvalStatement(Statement* expr); + + ConstObject* defineLocal(tp::String id); + }; + + void init(); + void deinit(); + void Genereate(ByteCode& out, StatementScope* body); + bool Compile(MethodObject* obj); + }; +}; \ No newline at end of file diff --git a/Objects/public/compiler/instruction.h b/Objects/public/compiler/instruction.h new file mode 100644 index 0000000..d0047a8 --- /dev/null +++ b/Objects/public/compiler/instruction.h @@ -0,0 +1,52 @@ + +#pragma once + +#include "interpreter/opcodes.h" + +#include "core/object.h" + +#include "List.hpp" + +namespace obj { + namespace BCgen { + + struct ConstObject; + + struct Instruction { + + OpCode mOp = OpCode::NONE; + + enum class ArgType { + NO_ARG, + PARAM, + CONST, + } mArgType = ArgType::NO_ARG; + + enum class InstType { + NONE, + JUMP, + JUMP_IF, + JUMP_IF_NOT, + EXEC, + PURE_CONST, + } mInstType = InstType::NONE; + + tp::alni mParam = 0; + tp::alni mParamBytes = 1; + + ConstObject* mConstData = NULL; + ConstObject* mConstData2 = NULL; + + tp::alni mInstIdx = 0; + tp::List::Node* mInstTarget = NULL; + + Instruction(); + Instruction(ConstObject* constData); + Instruction(OpCode op); + Instruction(OpCode op, ConstObject* constData); + Instruction(OpCode op, ConstObject* constData, ConstObject* constData2); + Instruction(OpCode op, tp::alni param, tp::alni nBytes); + Instruction(tp::List::Node* inst, InstType jump_type); + }; + }; +}; \ No newline at end of file diff --git a/Objects/public/compiler/statement.h b/Objects/public/compiler/statement.h new file mode 100644 index 0000000..0e53a3c --- /dev/null +++ b/Objects/public/compiler/statement.h @@ -0,0 +1,116 @@ + +#pragma once + +#include "expression.h" + +namespace obj { + namespace BCgen { + struct Statement { + enum class Type { + NONE, + SCOPE, + DEF_FUNC, + DEF_LOCAL, + RET, + PRINT, + COPY, + IF, + WHILE, + IGNORE, + CALL, + CLASS_DEF, + } mType = Type::NONE; + + bool mValueUsed = false; + + Statement() {} + Statement(Type type); + }; + + struct StatementScope : public Statement { + tp::Buffer mStatements; + bool mPushToScopeStack = false; + + StatementScope(tp::init_list statements, bool aPushToScopeStack); + }; + + struct StatementFuncDef : public Statement { + tp::Buffer mArgs; + tp::String mFunctionId; + tp::Buffer mStatements; + + StatementFuncDef(tp::String function_id, tp::init_list args, tp::init_list statements); + }; + + struct StatementLocalDef : public Statement { + tp::String mLocalId; + Expression* mNewExpr = NULL; + ExpressionConst* mConstExpr = NULL; + bool mIsConstExpr = false; + + StatementLocalDef(tp::String id, Expression* value); + StatementLocalDef(tp::String id, ExpressionConst* value); + }; + + struct StatementCopy : public Statement { + Expression* mLeft = NULL; + Expression* mRight = NULL; + + StatementCopy(Expression* left, Expression* right); + }; + + struct StatementReturn : public Statement { + Expression* mRet = NULL; + + StatementReturn(Expression* ret); + StatementReturn(); + }; + + struct StatementPrint : public Statement { + Expression* mTarget = NULL; + + StatementPrint(Expression* mTarget); + }; + + struct StatementIgnore : public Statement { + Expression* mExpr = NULL; + + StatementIgnore(Expression* expr); + }; + + struct StatementIf : public Statement { + Expression* mCondition = NULL; + StatementScope* mOnTrue = NULL; + StatementScope* mOnFalse = NULL; + + StatementIf(Expression* condition, StatementScope* on_true, StatementScope* on_false); + }; + + struct StatementWhile : public Statement { + Expression* mCondition = NULL; + StatementScope* mScope = NULL; + + StatementWhile(Expression* condition, StatementScope* scope); + }; + + struct StatementClassDef : public Statement { + tp::String mClassId; + StatementScope* mScope = NULL; + + StatementClassDef(tp::String class_id, StatementScope* scope); + }; + + // Helpers + StatementFuncDef* StmDefFunc(tp::String id, tp::init_list args, tp::init_list stms); + StatementLocalDef* StmDefLocal(tp::String id, Expression* value); + StatementCopy* StmCopy(Expression* left, Expression* right); + StatementPrint* StmPrint(Expression* target); + StatementReturn* StmReturn(Expression* obj); + StatementReturn* StmReturn(); + StatementIf* StmIf(Expression* condition, StatementScope* on_true, StatementScope* on_false); + StatementScope* StmScope(tp::init_list statements, bool aPushToScopeStack); + StatementWhile* StmWhile(Expression* condition, StatementScope* scope); + StatementIgnore* StmIgnore(Expression* expr); + StatementClassDef* StmClassDef(tp::String id, StatementScope* scope); + }; +}; \ No newline at end of file diff --git a/Objects/public/core/object.h b/Objects/public/core/object.h new file mode 100644 index 0000000..9feeef6 --- /dev/null +++ b/Objects/public/core/object.h @@ -0,0 +1,226 @@ + +#pragma once + +#include "Common.hpp" +#include "Map.hpp" +#include "List.hpp" +#include "Buffer.hpp" +#include "Strings.hpp" +#include "LocalConnection.hpp" + +#include "core/typegroups.h" +#include "core/typemethods.h" + +//#include "interpreter/interpreter.h" + +/* Steps to create custom Object: +define name of object +define base type +define struct members +implement construct, destruct and copy methods */ + +#define OBJECT_REF_COUNT + +#ifdef _DEBUG +#define NDO_CAST(cast_type, ptr) ((cast_type*)ndo_cast(ptr, &cast_type::TypeData)) +#define NDO_CAST_ASSERT(cast_type, ptr) {assert(ndo_cast(ptr, &cast_type::TypeData))} +#else +#define NDO_CAST_ASSERT(cast_type, ptr) {assert(ndo_cast(ptr, &cast_type::TypeData))} +#define NDO_CAST(cast_type, ptr) ((cast_type*)ndo_cast(ptr, &cast_type::TypeData)) +#endif + +#define NDO_CASTV(cast_type, ptr, var_name) cast_type* var_name = NDO_CAST(cast_type, ptr); var_name + +#define NDO_MEMH_FROM_NDO(ndo_ptr) (((ObjectMemHead*)ndo_ptr) - 1) +#define NDO_FROM_MEMH(ndo_ptr) ((Object*)(ndo_ptr + 1)) + +namespace obj { + + class Archiver : public tp::LocalConnection { + public: + enum Type { SAVE, LOAD }; + + Archiver() = default; + Archiver(const char*, Type) {}; + + bool opened; + + tp::ualni adress{}; + + // not yet writen address + // always offsets on write without specific address + tp::ualni avl_adress{}; + + void write_bytes(const tp::int1* in, tp::alni size, tp::alni adress = -1) {} + + template + void write(Type* in, tp::alni adress = -1) { + write_bytes((tp::int1*) in, sizeof(Type), adress); + } + + void read_bytes(tp::int1* in, tp::alni size, tp::alni adress = -1) {} + + template + void read(Type* in, tp::alni adress = -1) { + read_bytes((tp::int1*) in, sizeof(Type), adress); + } + }; + + extern tp::ModuleManifest gModuleObjects; + + extern struct objects_api* NDO; + + struct ObjectMemHead { + ObjectMemHead* up; + ObjectMemHead* down; + tp::alni flags; + #ifdef OBJECT_REF_COUNT + tp::alni refc; + #endif + }; + + struct Object { + const struct ObjectType* type; + }; + + typedef void (*object_from_int)(Object* self, tp::alni in); + typedef void (*object_from_float)(Object* self, tp::alnf in); + typedef void (*object_from_string)(Object* self, tp::String in); + typedef tp::String(*object_to_string)(Object* self); + typedef tp::alni(*object_to_int)(Object* self); + typedef tp::alnf(*object_to_float)(Object* self); + + struct ObjectTypeConversions { + object_from_int from_int; + object_from_float from_float; + object_from_string from_string; + object_to_string to_string; + object_to_int to_int; + object_to_float to_float; + }; + + typedef void (*object_add)(Object* self, Object* operand); + typedef void (*object_sub)(Object* self, Object* operand); + typedef void (*object_mul)(Object* self, Object* operand); + typedef void (*object_div)(Object* self, Object* operand); + + struct ObjectTypeAriphmetics { + object_add add; + object_sub sub; + object_mul mul; + object_div div; + }; + + typedef void (*object_constructor)(Object* self); + typedef void (*object_destructor)(Object* self); + typedef void (*object_copy)(Object* self, const Object* target); + + typedef tp::alni(*object_save_size)(Object* self); + typedef void (*object_save)(Object*, Archiver&); + typedef void (*object_load)(Archiver&, Object*); + + typedef bool (*object_compare)(Object*, Object*); + + typedef tp::Buffer (*object_debug_all_childs_retrival)(Object*); + typedef tp::alni (*object_allocated_size)(Object*); // default value = type->size - sizeof(ObjectType*) + typedef tp::alni (*object_allocated_size_recursive)(Object*); // default value = object_allocated_size + + struct ObjectType { + const ObjectType* base = NULL; + object_constructor constructor = NULL; + object_destructor destructor = NULL; + object_copy copy = NULL; + tp::alni size = NULL; + const char* name; + const ObjectTypeConversions* convesions = NULL; + const ObjectTypeAriphmetics* ariphmetics = NULL; + object_save_size save_size = NULL; + object_save save = NULL; + object_load load = NULL; + object_compare comparison = NULL; + void* vtable = NULL; + const char* description = NULL; + object_debug_all_childs_retrival childs_retrival = NULL; + object_allocated_size allocated_size = NULL; + object_allocated_size_recursive allocated_size_recursive = NULL; + TypeMethods type_methods; + }; + + + #define SAVE_LOAD_MAX_CALLBACK_SLOTS 100 + typedef void (pre_save_callback)(void* self, Archiver&); + typedef void (pre_load_callback)(void* self, Archiver&); + typedef void (post_save_callback)(void* self, Archiver&); + typedef void (post_load_callback)(void* self, Archiver&); + typedef tp::alni (slcb_size_callback)(void* self, Archiver&); + + struct save_load_callbacks { + void* self; + pre_save_callback* pre_save; + slcb_size_callback* size; + pre_load_callback* pre_load; + post_save_callback* post_save; + post_load_callback* post_load; + }; + + + struct objects_api { + + tp::Map types; + obj::TypeGroups type_groups; + Interpreter* interp = NULL; + + objects_api(); + ~objects_api(); + + void define(ObjectType* type); + Object* create(const tp::String& name); + Object* copy(Object* self, const Object* in); + bool compare(Object* first, Object* second); + Object* instatiate(Object*); + void set(Object* self, tp::alni val); + void set(Object* self, tp::alnf val); + void set(Object* self, tp::String val); + + tp::alni toInt(Object* self); + tp::alnf toFloat(Object* self); + bool toBool(Object* self); + tp::String toString(Object* self); + + void clear_object_flags(); + + void destroy(Object* in); + + #ifdef OBJECT_REF_COUNT + void refinc(Object* in); + tp::halni getrefc(Object* in); + private: + void setrefc(Object* in, tp::halni refc); + public: + #endif + + save_load_callbacks* sl_callbacks[SAVE_LOAD_MAX_CALLBACK_SLOTS]; + tp::alni sl_callbacks_load_idx = 0; + + void add_sl_callbacks(save_load_callbacks*); + + tp::alni objsize_file(Object* self); + tp::alni objsize_file_recursive(Object* self); + + tp::alni objsize_ram(Object* self); + tp::alni objsize_ram_recursive_util(Object* self, const ObjectType* type, bool different_object = true); + tp::alni objsize_ram_recursive(Object* self); + + bool save(Object*, tp::String path, bool compressed = true); + Object* load(tp::String path); + tp::alni save(Archiver&, Object*); + Object* load(Archiver&, tp::alni file_adress); + }; + + Object* ndo_cast(const Object* in, const ObjectType* to_type); + + template + Type* create() { + return (Type*)obj::NDO->create(Type::TypeData.name); + } +}; \ No newline at end of file diff --git a/Objects/public/core/scriptsection.h b/Objects/public/core/scriptsection.h new file mode 100644 index 0000000..56efcf7 --- /dev/null +++ b/Objects/public/core/scriptsection.h @@ -0,0 +1,36 @@ +#pragma once + +#include "primitives/methodobject.h" + +namespace obj { + + // global singleton API for method object to manage the script + struct ScriptSection { + + tp::List mScripts; + + Script* createScript(); + void changeScript(Script** current_script, Script** new_script); + void abandonScript(Script* script); + + tp::alni get_script_file_adress(Script* in); + Script* get_scritp_from_file_adress(tp::alni file_adress); + + ~ScriptSection(); + + static void initialize(); + static void uninitialize(); + static ScriptSection* globalHandle(); + + private: + + static obj::save_load_callbacks slcb_script_section; + + void delete_script(Script* script); + void reference_script(Script* script); + + static void save_script_table_to_file(ScriptSection* self, Archiver& file); + static void load_script_table_from_file(ScriptSection* self, Archiver& file); + static tp::alni save_script_table_to_file_size(ScriptSection* self, Archiver& file); + }; +}; \ No newline at end of file diff --git a/Objects/public/core/typegroups.h b/Objects/public/core/typegroups.h new file mode 100644 index 0000000..1dcb138 --- /dev/null +++ b/Objects/public/core/typegroups.h @@ -0,0 +1,40 @@ + +#pragma once + +#include "Map.hpp" +#include "Strings.hpp" + +namespace obj { + + struct ObjectType; + struct objects_api; + + class TypeGroups { + + public: + + typedef tp::Map Dict; + + TypeGroups(); + + friend struct obj::objects_api; + + TypeGroups(bool is_group); + + void addType(ObjectType* type, tp::init_list path, tp::alni cur_arg = 0); + void setType(ObjectType* type); + bool isGroup(); + Dict* getChilds(); + const obj::ObjectType* getType(); + ~TypeGroups(); + + private: + + bool is_group; + union { + Dict childs; + const obj::ObjectType* type; + }; + }; + +}; \ No newline at end of file diff --git a/Objects/public/core/typemethods.h b/Objects/public/core/typemethods.h new file mode 100644 index 0000000..d485aa4 --- /dev/null +++ b/Objects/public/core/typemethods.h @@ -0,0 +1,63 @@ + +#pragma once + +#include "Buffer.hpp" +#include "Strings.hpp" + +namespace obj { + + struct Interpreter; + struct Object; + struct ObjectType; + + struct TypeMethod { + enum { MAX_ARGS = 8 }; + struct Arg { + const char* descr = NULL; + mutable Object* obj = NULL; + }; + + const char* nameid = NULL; + const char* descr = NULL; + + mutable Object* self = NULL; + Arg args[MAX_ARGS]; + + tp::int1 mNargs = NULL; + + void (*exec)(const TypeMethod* tm) = NULL; + + mutable Arg ret; + + void operator()(Interpreter* interp) const; + + void init(); + }; + + extern TypeMethod gDefaultTypeMethods[3]; + + struct TypeMethods { + enum : tp::int2 { MAX_TYPE_METHODS = 128 }; + + TypeMethod* methods[MAX_TYPE_METHODS]; + tp::halni mNMethods = NULL; + + struct LookupKey { + tp::int2 key = -1; + tp::int2 type_depth = -1; + operator bool() { return key != -1; } + }; + + static LookupKey presents(const ObjectType*, tp::String); + static const TypeMethod* getMethod(const ObjectType*, LookupKey); + + void init(); + + tp::halni nMethods() const; + + private: + tp::int2 presents(tp::String) const; + const TypeMethod* getMethod(tp::int2) const; + }; + +}; \ No newline at end of file diff --git a/Objects/public/interpreter/bytecode.h b/Objects/public/interpreter/bytecode.h new file mode 100644 index 0000000..6453959 --- /dev/null +++ b/Objects/public/interpreter/bytecode.h @@ -0,0 +1,28 @@ + +#pragma once + +#include "opcodes.h" + +#include "primitives/intobject.h" +#include "primitives/stringobject.h" + +#include "Buffer.hpp" +#include "Strings.hpp" + +namespace obj { + + typedef Object* ConstData; + + struct ByteCode { + tp::Buffer mConstants; + tp::Buffer mInstructions; + tp::ualni mInstructionIdx = 0; + tp::ualni mArgumentsLoaded = 0; + + ~ByteCode() { + for (auto const_obj : mConstants) { + NDO->destroy(const_obj.data()); + } + } + }; +}; \ No newline at end of file diff --git a/Objects/public/interpreter/callstack.h b/Objects/public/interpreter/callstack.h new file mode 100644 index 0000000..afb97df --- /dev/null +++ b/Objects/public/interpreter/callstack.h @@ -0,0 +1,32 @@ +#pragma once + +#include "core/object.h" +#include "primitives/classobject.h" + +#include "Map.hpp" + +namespace obj { + struct MethodObject; +}; + +namespace obj { + + struct ByteCode; + + struct CallStack { + + struct CallFrame { + enum { CALL_DEPTH = 1024 }; + obj::Object* mSelf = NULL; + obj::MethodObject* mMethod = NULL; + tp::ualni mIp = 0; + }; + + void enter(const CallFrame& frame); + void leave(); + ByteCode* getBytecode(); + tp::halni len() const; + + tp::ConstSizeBuffer mStack; + }; +}; \ No newline at end of file diff --git a/Objects/public/interpreter/interpreter.h b/Objects/public/interpreter/interpreter.h new file mode 100644 index 0000000..eeab2cd --- /dev/null +++ b/Objects/public/interpreter/interpreter.h @@ -0,0 +1,29 @@ +#pragma once + +#include "operandsstack.h" +#include "scopestack.h" +#include "callstack.h" + +namespace obj { + struct Interpreter { + OperandStack mOperandsStack; + ScopeStack mScopeStack; + CallStack mCallStack; + + obj::Object* mLastParent = NULL; + bool mIsTypeMethod = false; + const TypeMethod* mTypeMethod = NULL; + + typedef struct { obj::Object* obj; tp::String id; } GlobalDef; + + void exec(obj::MethodObject* method, obj::ClassObject* self = NULL, obj::DictObject* globals = NULL, tp::init_list globals2 = {}); + + void stepBytecode(); + void stepBytecodeIn(); + void stepBytecodeOut(); + + bool finished(); + + void execAll(obj::MethodObject* method, obj::ClassObject* self = NULL, obj::DictObject* globals = NULL, tp::init_list globals2 = {}); + }; +}; \ No newline at end of file diff --git a/Objects/public/interpreter/opcodes.h b/Objects/public/interpreter/opcodes.h new file mode 100644 index 0000000..54fe22e --- /dev/null +++ b/Objects/public/interpreter/opcodes.h @@ -0,0 +1,158 @@ + +#pragma once + +#include "Common.hpp" + +// No Nested Scopes + +// Opcodes: +// Opcode input can be: +// 0) No Input +// 1) operands from OperandsStack (Operand) +// 2) Index of bytecode->ConstData from bytecode->Instruction (ConstData) +// 3) Raw Bytes from bytecode->Instruction (Param) + +namespace obj { + + extern struct OpcodeInfos gOpcodeInfos; + + enum class OpCode : tp::uint1 { + + NONE = 0x00, + HALT, + TERMINATE, + + DEF_LOCAL, + // Operand : String : local_id + // Operand : Any : object to be local + + LOAD_CONST, + LOAD_LOCAL, + // ConstData : idx of const object + + IGNORE, + + SCOPE_IN, + SCOPE_OUT, + + CALL, + RETURN_OBJ, + // Operand : Base : returned object + + RETURN, + + CHILD, + // Operand : String : child_id + // Operand : Base : parent + // Param : 1 bytes : is method? + + PUSH_ARGS, + SAVE_ARGS, + // Param : nubber of args + + OBJ_CREATE_LOCAL, + // Operand : String : type + // Operand : String : id + + OBJ_CREATE, + // Operand : String : type + + OBJ_COPY, + // Operand : Base: target + // Operand : Base: blueprint + + OBJ_SAVE, + OBJ_LOAD, + // Operand : String : path + // Operand : Base : target + + OBJ_ADD, + OBJ_SUB, + OBJ_MUL, + OBJ_DIV, + + AND, + OR, + EQUAL, + NOT_EQUAL, + MORE, + LESS, + EQUAL_OR_MORE, + EQUAL_OR_LESS, + // Operand : Base: left + // Operand : Base: right + + NOT, + // Operand : Base: inv + + JUMP, + JUMP_R, + // Param : 2 bytes : offset + + JUMP_IF, + JUMP_IF_R, + JUMP_IF_NOT, + JUMP_IF_NOT_R, + // Operand : Base: condition + // Param : 2 bytes : offset + + + PRINT, + // Operand : Base: target + + CLASS_CONSTRUCT, + SELF, + + // ... + + END_OPCODES + }; + + struct OpcodeInfos { + + struct OperandsInfo { + struct Operand { + const char* obj_type = nullptr; + const char* desc = nullptr; + }; + + enum { MAX_OPERANDS = 5 }; + Operand buff[MAX_OPERANDS]; + tp::halni len = 0; + + OperandsInfo(); + OperandsInfo(tp::init_list list); + }; + + struct ParamsInfo { + struct Param { + const char* desc = nullptr; + tp::halni bytes = 1; + }; + + enum { MAX_PARAMS = 5 }; + Param buff[MAX_PARAMS]; + tp::halni len = 0; + + ParamsInfo(); + ParamsInfo(tp::init_list list); + }; + + struct OpInfo { + const char* name = nullptr; + const char* desc = nullptr; + OperandsInfo operands; + ParamsInfo params; + + tp::uint1 opsize(); + }; + + OpcodeInfos(); + OpInfo fetch(OpCode code); + + private: + OpInfo buff[(tp::alni)OpCode::END_OPCODES]; + + void add(OpCode code, const OpInfo& info); + }; +} \ No newline at end of file diff --git a/Objects/public/interpreter/operandsstack.h b/Objects/public/interpreter/operandsstack.h new file mode 100644 index 0000000..7300f21 --- /dev/null +++ b/Objects/public/interpreter/operandsstack.h @@ -0,0 +1,39 @@ +#pragma once + +#include "bytecode.h" +#include "core/object.h" + +namespace obj { + + // can be other aligned value as well + typedef obj::Object* Operand; + + class OperandStack { + + enum : tp::alni { + MAX_STACK_SIZE = 512 + }; + + public: + + Operand* mBuff; + tp::ualni mIdx; + + OperandStack(); + void push(Operand operand); + void pop(); + + Operand getOperand(); + + template + ObjectType* getOperand() { + auto operand = getOperand(); + auto ret = NDO_CAST(ObjectType, operand); + ASSERT(ret && "Operand Has Invalid Object Type"); + return ret; + } + + ~OperandStack(); + }; + +}; \ No newline at end of file diff --git a/Objects/public/interpreter/scopestack.h b/Objects/public/interpreter/scopestack.h new file mode 100644 index 0000000..9e1aae9 --- /dev/null +++ b/Objects/public/interpreter/scopestack.h @@ -0,0 +1,46 @@ +#pragma once + +#include "core/object.h" +#include "Map.hpp" + +namespace obj { + + struct Scope { + typedef tp::Map ObjDict; + typedef tp::List ObjList; + + ObjDict mLocals; + ObjList mTemps; + bool mChildReachable = true; + + ~Scope(); + }; + + class ScopeStack { + + enum : tp::alni { + MAX_STACK_SIZE = 1024 * 4 + }; + + public: + + Scope* mBuff; + tp::ualni mIdx; + tp::ualni mIterIdx; + + ScopeStack(); + void enterScope(bool aChildReachable); + void leaveScope(); + void addLocal(obj::Object* local, tp::String id); + void addTemp(obj::Object* tmp); + void popTemp(); + void addTempReturn(obj::Object* ret); + obj::Object* getLocal(tp::String& str); + Scope* getCurrentScope(); + ~ScopeStack(); + + private: + obj::Object* getLocalUtil(Scope& scope, tp::String* id); + }; + +}; \ No newline at end of file diff --git a/Objects/public/interpreter/script.h b/Objects/public/interpreter/script.h new file mode 100644 index 0000000..e89474e --- /dev/null +++ b/Objects/public/interpreter/script.h @@ -0,0 +1,12 @@ +#pragma once + +#include "interpreter/bytecode.h" + +namespace obj { + struct Script { + obj::StringObject* mReadable; + ByteCode mBytecode; + + void compile(); + }; +}; \ No newline at end of file diff --git a/Objects/public/parser/parser.h b/Objects/public/parser/parser.h new file mode 100644 index 0000000..7e53411 --- /dev/null +++ b/Objects/public/parser/parser.h @@ -0,0 +1,195 @@ +#pragma once +#include "NewPlacement.hpp" +#include "compiler/statement.h" +#include "compiler/expression.h" + +#include "Tokenizer.hpp" + +namespace obj { + + class Parser { + + struct Token { + + tp::String token; + + tp::alni integer; + tp::alnf floating; + bool boolean; + tp::String str; + + enum TokType : tp::alni { + __START__ = 0, + ID, + CONST_INT, + CONST_FLOAT, + CONST_STRING, + SCOPE_IN, + SCOPE_OUT, + ASSIGN, + DEF_FUNC, + PRINT, + IF, + ELSE, + WHILE, + BRACKET_IN, + BRACKET_OUT, + COMMA, + NEW, + CHILD, + RETURN, + EQUAL, + NOT_EQUAL, + MORE, + LESS, + QE_OR_MORE, + QE_OR_LESS, + BOOL_NOT, + BOOL_AND, + BOOL_OR, + ADD, + MUL, + SUB, + DIV, + QUOTES, + CONST_TRUE, + CONST_FALSE, + STM_END, + SPACE, + VAR, + CLASS_DEF, + SELF, + COMMENT_BLOCK, + __END__, + NO_TOKEN, + FAILED, + SOURCE_END_TOKEN, + } type; + + operator TokType() { + return type; + } + + bool isAriphm(); + bool isBoolean(); + }; + + typedef tp::SimpleTokenizer Tokenizer; + Tokenizer mTok; + + enum class ExprType { + BOOLEAN_NOT = 0, + BOOLEAN, + Ariphm, + NEW, + LOCAL, + CONST, + Compound + }; + + enum class StmType { + DefFunc = 0, + DefLocal, + Return, + Print, + If, + While, + Copy, + Call, + CLASS_DEF + }; + + public: + + Parser(); + + struct Error { + tp::String mDescr = "No Description"; + tp::alni mAdvanecedIdx = NULL; + + Error() {} + Error(tp::String descr, tp::alni idx) { + mDescr = descr; + mAdvanecedIdx = idx; + } + + tp::Pair get_err_location(const char* stream) { + tp::alni line = 1; + tp::alni colomn = 1; + + //assert(mAdvanecedIdx); + + for (auto i : tp::Range(mAdvanecedIdx)) { + if (stream[i] == '\n') { + colomn = 0; + line++; + } + colomn++; + } + + return { line, colomn }; + } + }; + + struct Resault { + Error* err = NULL; + obj::BCgen::StatementScope* scope = NULL; + } mRes; + + Resault parse(const tp::String& stream); + + private: + + Token tokRead(); + Token tokLookup(); + void tokSkip(); + bool tokInputLeft(); + Tokenizer::Cursor tokGetCursor(); + void tokSetCursor(Tokenizer::Cursor); + + BCgen::Expression* parseExprCompound(); + BCgen::Expression* parseExprNEW(); + BCgen::Expression* parseExprLOCAL(); + BCgen::Expression* parseExprCONST(); + BCgen::Expression* parseExprCHILD(BCgen::Expression* prnt); + BCgen::Expression* parseExprCALL(BCgen::Expression* prnt); + BCgen::Expression* parseExprAriphm(); + BCgen::Expression* parseExprBOOLEAN(); + BCgen::Expression* parseExprBOOLEAN_NOT(); + BCgen::Expression* parseExprFUNC(); + BCgen::Expression* parseExprChain(BCgen::Expression* prnt); + + BCgen::Expression* parseExpr(tp::init_list expressions = { + ExprType::BOOLEAN_NOT, + ExprType::BOOLEAN, + ExprType::Ariphm, + ExprType::NEW, + ExprType::LOCAL, + ExprType::CONST, + }); + + BCgen::Statement* parseStmCall(); + BCgen::Statement* parseStmDefFunc(); + BCgen::Statement* parseStmDefLocal(); + BCgen::Statement* parseStmReturn(); + BCgen::Statement* parseStmPrint(); + BCgen::Statement* parseStmIf(); + BCgen::Statement* parseStmWhile(); + BCgen::Statement* parseStmCopy(); + BCgen::Statement* parseStmClassDef(); + + BCgen::Statement* parseStm(tp::init_list stm_types = { + StmType::DefFunc, + StmType::DefLocal, + StmType::Return, + StmType::Print, + StmType::If, + StmType::While, + StmType::Copy, + StmType::Call, + StmType::CLASS_DEF + }); + + BCgen::StatementScope* parseScope(bool aPushToScopeStack); + }; +}; \ No newline at end of file diff --git a/Objects/public/primitives/boolobject.h b/Objects/public/primitives/boolobject.h new file mode 100644 index 0000000..f669d6d --- /dev/null +++ b/Objects/public/primitives/boolobject.h @@ -0,0 +1,24 @@ + +#pragma once + +#include "core/object.h" + +namespace obj { + + struct BoolObject : Object { + tp::alni val; + + static ObjectType TypeData; + static void constructor(BoolObject* self); + static void copy(BoolObject* self, const BoolObject* in); + + static BoolObject* create(bool in); + + static void from_int(BoolObject* self, tp::alni in); + static void from_float(BoolObject* self, tp::alnf in); + static void from_string(BoolObject* self, tp::String in); + static tp::String to_string(BoolObject* self); + static tp::alni to_int(BoolObject* self); + static tp::alnf to_float(BoolObject* self); + }; +}; \ No newline at end of file diff --git a/Objects/public/primitives/classobject.h b/Objects/public/primitives/classobject.h new file mode 100644 index 0000000..2778972 --- /dev/null +++ b/Objects/public/primitives/classobject.h @@ -0,0 +1,49 @@ +#pragma once + +#include "primitives/dictobject.h" + +namespace obj { + + struct ClassObject : Object { + + static ObjectType TypeData; + static void copy(ClassObject* self, const ClassObject* in); + static void destructor(ClassObject* self); + static void constructor(ClassObject* self); + static tp::alni save_size(ClassObject* self); + static void save(ClassObject* self, Archiver& file_self); + static void load(Archiver& file_self, ClassObject* self); + + DictObject* members; + + void addMember(Object* obj, tp::String id); + void createMember(tp::String type, tp::String id); + + template + Type* createMember(tp::String id) { + auto out = NDO->create(Type::TypeData.name); + addMember(out, id); +#ifdef OBJECT_REF_COUNT + NDO->destroy(out); +#endif // OBJECT_REF_COUNT + + return (Type*) out; + } + + template + Type* getMember(const tp::String& id) { + auto idx = members->presents(id); + if (idx) { + return ((Type*)obj::ndo_cast(members->getSlotVal(idx), &Type::TypeData)); + } + return NULL; + } + + template + Type* getMemberAssert(const tp::String& id) { + auto out = getMember(id); + assert(out && "invalid member access"); + return out; + } + }; +}; \ No newline at end of file diff --git a/Objects/public/primitives/colorobject.h b/Objects/public/primitives/colorobject.h new file mode 100644 index 0000000..831c761 --- /dev/null +++ b/Objects/public/primitives/colorobject.h @@ -0,0 +1,24 @@ + +#pragma once + +#include "core/object.h" +#include "Color.hpp" + +namespace obj { + + struct ColorObject : Object { + tp::RGBA mCol; + + static ObjectType TypeData; + static ObjectTypeAriphmetics TypeAriphm; + + static void constructor(Object* self); + static void copy(ColorObject* self, const ColorObject* in); + + static void from_int(ColorObject* self, tp::alni in); + static void from_float(ColorObject* self, tp::alnf in); + static tp::String to_string(ColorObject* self); + + static ColorObject* create(tp::RGBA in); + }; +}; \ No newline at end of file diff --git a/Objects/public/primitives/dictobject.h b/Objects/public/primitives/dictobject.h new file mode 100644 index 0000000..6445196 --- /dev/null +++ b/Objects/public/primitives/dictobject.h @@ -0,0 +1,31 @@ +#pragma once + +#include "core/object.h" + +namespace obj { + + struct DictObject : Object { + static ObjectType TypeData; + static void copy(Object* self, const Object* in); + static void destructor(Object* self); + static void constructor(Object* self); + + static tp::alni save_size(DictObject* self); + static void save(DictObject* self, Archiver& file_self); + static void load(Archiver& file_self, DictObject* self); + static tp::Buffer childs_retrival(DictObject* self); + static tp::alni allocated_size(DictObject* self); + static tp::alni allocated_size_recursive(DictObject* self); + + void put(tp::String, Object*); + void remove(tp::String); + Object* get(tp::String); + tp::Map::Idx presents(tp::String); + Object* getSlotVal(tp::alni); + + const tp::Map& getItems() const; + + private: + tp::Map items; + }; +}; \ No newline at end of file diff --git a/Objects/public/primitives/enumobject.h b/Objects/public/primitives/enumobject.h new file mode 100644 index 0000000..13aebef --- /dev/null +++ b/Objects/public/primitives/enumobject.h @@ -0,0 +1,34 @@ + +#pragma once + +#include "core/object.h" + +namespace obj { + + struct EnumObject : Object { + + // one entry is 2 * sizeof(alni) in size + tp::uhalni active; + tp::uhalni nentries; + tp::alni* entries; + + static ObjectType TypeData; + static void constructor(EnumObject* self); + static void destructor(EnumObject* self); + static void copy(EnumObject* self, const EnumObject* in); + + void init(tp::init_list list); + const char* getActiveName(); + const char* getItemName(tp::uhalni idx); + + static void from_int(EnumObject* self, tp::alni in); + static void from_float(EnumObject* self, tp::alnf in); + static void from_string(EnumObject* self, tp::String in); + static tp::String to_string(EnumObject* self); + static tp::alni to_int(EnumObject* self); + static tp::alnf to_float(EnumObject* self); + + static bool compare(EnumObject* first, EnumObject* second); + static EnumObject* create(tp::init_list list); + }; +}; \ No newline at end of file diff --git a/Objects/public/primitives/floatobject.h b/Objects/public/primitives/floatobject.h new file mode 100644 index 0000000..5013383 --- /dev/null +++ b/Objects/public/primitives/floatobject.h @@ -0,0 +1,26 @@ + +#pragma once + +#include "core/object.h" + +namespace obj { + + struct FloatObject : Object { + tp::alnf val; + + static ObjectType TypeData; + static ObjectTypeAriphmetics TypeAriphm; + + + static void constructor(FloatObject* self); + static void copy(FloatObject* self, const FloatObject* in); + static FloatObject* create(tp::alnf in); + + static void from_int(FloatObject* self, tp::alni in); + static void from_float(FloatObject* self, tp::alnf in); + static void from_string(FloatObject* self, tp::String in); + static tp::String to_string(FloatObject* self); + static tp::alni to_int(FloatObject* self); + static tp::alnf to_float(FloatObject* self); + }; +}; \ No newline at end of file diff --git a/Objects/public/primitives/interpreterobject.h b/Objects/public/primitives/interpreterobject.h new file mode 100644 index 0000000..5710924 --- /dev/null +++ b/Objects/public/primitives/interpreterobject.h @@ -0,0 +1,19 @@ +#pragma once + +#include "interpreter/interpreter.h" +#include "primitives/classobject.h" + +namespace obj { + struct InterpreterObject : ClassObject { + static ObjectType TypeData; + Interpreter mInterpreter; + + static void destructor(InterpreterObject* self); + static void constructor(InterpreterObject* self); + static void load(Archiver& file_self, InterpreterObject* self); + + void exec(obj::ClassObject* self = NULL, tp::init_list globals = {}); + void debug(); + bool running(); + }; +}; \ No newline at end of file diff --git a/Objects/public/primitives/intobject.h b/Objects/public/primitives/intobject.h new file mode 100644 index 0000000..0f26799 --- /dev/null +++ b/Objects/public/primitives/intobject.h @@ -0,0 +1,25 @@ + +#pragma once + +#include "core/object.h" + +namespace obj { + + struct IntObject : Object { + tp::alni val; + + static ObjectType TypeData; + static ObjectTypeAriphmetics TypeAriphm; + + static void constructor(Object* self); + static void copy(IntObject* self, const IntObject* in); + static IntObject* create(tp::alni in); + + static void from_int(Object* self, tp::alni in); + static void from_float(Object* self, tp::alnf in); + static void from_string(Object* self, tp::String in); + static tp::String to_string(Object* self); + static tp::alni to_int(Object* self); + static tp::alnf to_float(Object* self); + }; +}; \ No newline at end of file diff --git a/Objects/public/primitives/linkobject.h b/Objects/public/primitives/linkobject.h new file mode 100644 index 0000000..52b7129 --- /dev/null +++ b/Objects/public/primitives/linkobject.h @@ -0,0 +1,29 @@ + +#pragma once + +#include "core/object.h" + +namespace obj { + + struct LinkObject : Object { + static ObjectType TypeData; + static void constructor(Object* self); + static void destructor(LinkObject* self); + static void copy(Object* self, const Object* in); + static LinkObject* create(Object* in); + + static tp::alni save_size(LinkObject* self); + static void save(LinkObject* self, Archiver& file_self); + static void load(Archiver& file_self, LinkObject* self); + static tp::alni allocated_size(LinkObject* self); + static tp::alni allocated_size_recursive(LinkObject* self); + static tp::Buffer childs_retrival(LinkObject* self); + + Object* getLink(); + void setLink(Object* obj); + + private: + Object* link; + }; + +}; \ No newline at end of file diff --git a/Objects/public/primitives/listobject.h b/Objects/public/primitives/listobject.h new file mode 100644 index 0000000..bd17841 --- /dev/null +++ b/Objects/public/primitives/listobject.h @@ -0,0 +1,36 @@ + +#pragma once + +#include "core/object.h" + +namespace obj { + + enum ListMethods { + LISTOBJECT_PUSH_BACK, + LISTOBJECT_GET_LENGTH, + }; + + struct ListObject : Object { + static ObjectType TypeData; + static void constructor(Object* self); + static void copy(Object* self, const Object* in); + static void destructor(Object* self); + + static tp::alni allocated_size_recursive(ListObject* self); + static tp::alni allocated_size(ListObject* self); + static tp::Buffer childs_retrival(ListObject* self); + static void load(Archiver& file_self, ListObject* self); + static void save(ListObject* self, Archiver& file_self); + static tp::alni save_size(ListObject* self); + + const tp::List& getItems() const; + + void pushBack(Object* obj); + void pushFront(Object* obj); + void popBack(); + void delNode(tp::List::Node*); + + private: + tp::List items; + }; +}; \ No newline at end of file diff --git a/Objects/public/primitives/methodobject.h b/Objects/public/primitives/methodobject.h new file mode 100644 index 0000000..e4aedf3 --- /dev/null +++ b/Objects/public/primitives/methodobject.h @@ -0,0 +1,28 @@ +#pragma once + +#include "primitives/stringobject.h" +#include "interpreter/script.h" + +namespace obj { + + struct MethodObject : Object { + + static ObjectType TypeData; + + Script* mScript; + + static void constructor(MethodObject* self); + static void copy(MethodObject* self, MethodObject* in); + static void destructor(MethodObject* self); + static tp::alni save_size(MethodObject* self); + static void save(MethodObject* self,Archiver& file_self); + static void load(Archiver& file_self, obj::MethodObject* self); + + static void Initialize(); + static void UnInitialize(); + + void compile(); + + static MethodObject* create(tp::String script); + }; +}; \ No newline at end of file diff --git a/Objects/public/primitives/nullobject.h b/Objects/public/primitives/nullobject.h new file mode 100644 index 0000000..0d71524 --- /dev/null +++ b/Objects/public/primitives/nullobject.h @@ -0,0 +1,32 @@ + +#pragma once + +#include "core/object.h" + +namespace obj { + + extern struct NullObject* NdoNull_globalInstance; + + struct NullObject : Object { + + static void destructor(Object* self); + static ObjectType TypeData; + static void uninit(); + static Object* null_return() { + if (!NdoNull_globalInstance) { + NdoNull_globalInstance = (NullObject*) NDO->create("null"); + obj::NDO->refinc(NdoNull_globalInstance); + } + return (Object*) NdoNull_globalInstance; + } + + static Object* null_return_ref() { + obj::NDO->refinc(null_return()); + return NdoNull_globalInstance; + } + }; + + #define NDO_NULL obj::NullObject::null_return() + #define NDO_NULL_REF obj::NullObject::null_return_ref() + +}; \ No newline at end of file diff --git a/Objects/public/primitives/primitives.h b/Objects/public/primitives/primitives.h new file mode 100644 index 0000000..e659765 --- /dev/null +++ b/Objects/public/primitives/primitives.h @@ -0,0 +1,22 @@ + +#pragma once + +#include "primitives/dictobject.h" +#include "primitives/intobject.h" +#include "primitives/linkobject.h" +#include "primitives/listobject.h" +#include "primitives/nullobject.h" +#include "primitives/stringobject.h" +#include "primitives/boolobject.h" +#include "primitives/floatobject.h" +#include "primitives/enumobject.h" +#include "primitives/classobject.h" +#include "primitives/colorobject.h" +#include "primitives/methodobject.h" +#include "primitives/interpreterobject.h" +#include "primitives/typeobject.h" + +namespace obj { + void primitives_define_types(); + void primitives_uninitialize(); +}; \ No newline at end of file diff --git a/Objects/public/primitives/stringobject.h b/Objects/public/primitives/stringobject.h new file mode 100644 index 0000000..6f0b841 --- /dev/null +++ b/Objects/public/primitives/stringobject.h @@ -0,0 +1,24 @@ + +#pragma once + +#include "core/object.h" + +namespace obj { + + struct StringObject : Object { + tp::String val; + + static ObjectType TypeData; + static void constructor(Object* self); + static void destructor(StringObject* self); + static void copy(Object* self, const Object* in); + static StringObject* create(tp::String in); + + static void from_int(StringObject* self, tp::alni in); + static void from_float(StringObject* self, tp::alnf in); + static void from_string(StringObject* self, tp::String in); + static tp::String to_string(StringObject* self); + static tp::alni to_int(StringObject* self); + static tp::alnf to_float(StringObject* self); + }; +}; \ No newline at end of file diff --git a/Objects/public/primitives/typeobject.h b/Objects/public/primitives/typeobject.h new file mode 100644 index 0000000..53b1f5a --- /dev/null +++ b/Objects/public/primitives/typeobject.h @@ -0,0 +1,13 @@ + +#pragma once + +#include "core/object.h" + +namespace obj { + + struct TypeObject : Object { + static ObjectType TypeData; + const ObjectType* mTypeRef; + static TypeObject* create(const ObjectType* type); + }; +}; \ No newline at end of file diff --git a/Objects/rsc/script.osc b/Objects/rsc/script.osc new file mode 100644 index 0000000..da04039 --- /dev/null +++ b/Objects/rsc/script.osc @@ -0,0 +1,15 @@ + +class A { + var string = "hello"; + def log(name) { + << self.string; + << name; + } +} + +def main() { + var a = new A(); + a.log("user"); +} + +main(); \ No newline at end of file diff --git a/Objects/tests/TestEntry.cpp b/Objects/tests/TestEntry.cpp new file mode 100644 index 0000000..c625e7e --- /dev/null +++ b/Objects/tests/TestEntry.cpp @@ -0,0 +1,90 @@ + + +#include "MethodObject/methodobject.h" +#include "primitives/primitives.h" + +#include "Interpreter/Interpreter.h" + +#include "log.h" + +#include "ByteCodeGen/Function.h" + +using namespace osc; +using namespace tp; +using namespace obj; + +void TestCompile(ByteCode& bytecode) { + using namespace BCgen; + + Genereate(bytecode, + StmScope({ + + StmDefFunc("main", {}, { + StmDefLocal("i1", ExprConst(1)), + StmDefLocal("i2", ExprConst(2)), + + StmDefFunc("add", {"first", "second"}, { + StmReturn(ExprAdd(ExprLocal("first"), ExprLocal("second"))) + }), + + StmPrint(ExprLocal("i1")), + StmPrint(ExprConst(" + ")), + StmPrint(ExprLocal("i2")), + StmPrint(ExprConst(" = ")), + + StmPrint(ExprFunc("add")->ExprCall({ ExprLocal("i1"), ExprLocal("i2") })), + + StmPrint(ExprConst("\n")), + }), + + StmPrint(ExprBoolNot(ExprConst(0))), + + StmWhile(ExprConst(false), StmScope({ + StmIgnore(ExprFunc("main")->ExprCall({})) + }) + ), + + StmIf(ExprConst(true), + StmScope({ + //StmIgnore(ExprFunc("main")->ExprCall({})), + //StmPrint(ExprConst("true")), + }), + StmScope({ + //StmPrint(ExprConst("false")), + }) + ) + }) + ); +} + +int main(int argc, char* argv[]) { + + tp::alloc_init(); + string::Initialize(); + Logger::init(); + + objects_init(); + primitives_define_types(); + MethodObject::Initialize(); + + { + Interpreter interp; + + ByteCode bytecode; + TestCompile(bytecode); + + GLog->write(" >> Exec: start \n"); + auto start = get_time(); + interp.exec(&bytecode); + auto end = get_time(); + GLog->write(sfmt("\n >> Exec time %i ms", end - start)); + } + + MethodObject::UnInitialize(); + objects_finalize(); + primitives_uninitialize(); + + Logger::deinit(); + string::UnInitialize(); + tp::alloc_uninit(); +} \ No newline at end of file diff --git a/Objects/tests/test.cpp b/Objects/tests/test.cpp new file mode 100644 index 0000000..6ed1c96 --- /dev/null +++ b/Objects/tests/test.cpp @@ -0,0 +1,75 @@ + +#include "primitives/primitives.h" + +#include "compiler/function.h" +#include "interpreter/interpreter.h" + +#include "CmdArgParser.h" + +void compile(char argc, const char* argv[]) { + tp::CmdArgParser args = { + { "script", tp::CmdArgParser::Arg::FILE_IN }, + { "out", "out.mo" } + }; + + if (!args.parse(argc, argv, true)) { + return; + } + + auto& script_file = args.getFile("script"); + auto outpath = args.getString("out"); + + tp::string script; + script.loadFile(&script_file); + + auto method = obj::MethodObject::create(script); + + obj::NDO->save(method, outpath); +} + +void execute(char argc, const char* argv[]) { + tp::CmdArgParser args = { + { "object_path", tp::CmdArgParser::Arg::STR }, + { "debug", false } + }; + + if (!args.parse(argc, argv, true)) { + return; + } + + auto object_path = args.getString("object_path"); + auto debug = args.getBool("debug"); + + auto obj = obj::NDO->load(object_path); + if (!obj) { + printf("Invalid Object File\n"); + return; + } + + NDO_CASTV(obj::MethodObject, obj, method); + if (!method) { + printf("Object Is Not A Method\n"); + return; + } + + obj::Interpreter interpreter; + interpreter.execAll(method); +} + + +int main(char argc, const char* argv[]) { + + tp::ModuleManifest* ModuleDependencies[] = { &obj::gModuleObjects, NULL }; + tp::ModuleManifest TestModule("Test", NULL, NULL, ModuleDependencies); + if (!TestModule.initialize()) { + return 1; + } + +#ifdef OBC + compile(argc, argv); +#elif OBVM + execute(argc, argv); +#endif // OBC + + TestModule.deinitialize(); +} \ No newline at end of file diff --git a/TODO b/TODO index 25baf47..cf4062f 100644 --- a/TODO +++ b/TODO @@ -2,7 +2,19 @@ Testing ! Serialization ! Objects: - Implement ! + Serialization + Alloc Size queries + Compile !! + parser print error + write tests before refactor !! + remove obj_ref_count macro + fix all clang-tidy notices + write archiver + replace all strings with const string ref + replace all type usages with typedefs + remove tp:: + rename classes + move functions around Storage: Finish networking diff --git a/Tokenizer/public/Tokenizer.hpp b/Tokenizer/public/Tokenizer.hpp index 3a041c5..cdee460 100644 --- a/Tokenizer/public/Tokenizer.hpp +++ b/Tokenizer/public/Tokenizer.hpp @@ -111,7 +111,7 @@ namespace tp { if (!mSource) { return false; } - if (mSource[mAdvancedOffset] == nullptr) { + if (mSource[mAdvancedOffset] == 0) { return false; } return true; diff --git a/Utils/private/Utils.cpp b/Utils/private/Utils.cpp index 48e351b..11f2011 100644 --- a/Utils/private/Utils.cpp +++ b/Utils/private/Utils.cpp @@ -87,6 +87,9 @@ namespace tp { return 0; } + bool memEqual(const void* left, const void* right, uhalni len) { + return memCompare(left, right, len) == 0; + } int1 memCompareVal(const void* left, uhalni len, uint1 val) { MODULE_SANITY_CHECK(gModuleBase) diff --git a/Utils/public/Utils.hpp b/Utils/public/Utils.hpp index 740f4d0..0cef950 100644 --- a/Utils/public/Utils.hpp +++ b/Utils/public/Utils.hpp @@ -12,6 +12,7 @@ namespace tp { void memSetVal(void* p, uhalni byteSize, uint1 val); void memCopy(void* left, const void* right, uhalni len); int1 memCompare(const void* left, const void* right, uhalni len); + bool memEqual(const void* left, const void* right, uhalni len); int1 memCompareVal(const void* left, uhalni len, uint1 val); }