Objects Initial
This commit is contained in:
parent
00bc875846
commit
803ce23169
76 changed files with 7895 additions and 17 deletions
|
|
@ -24,3 +24,5 @@ add_subdirectory(Externals)
|
||||||
|
|
||||||
add_subdirectory(Connection)
|
add_subdirectory(Connection)
|
||||||
add_subdirectory(Graphics)
|
add_subdirectory(Graphics)
|
||||||
|
|
||||||
|
#add_subdirectory(Objects)
|
||||||
|
|
|
||||||
|
|
@ -20,42 +20,111 @@ namespace tp {
|
||||||
|
|
||||||
template<typename tType, ualni tSize>
|
template<typename tType, ualni tSize>
|
||||||
class ConstSizeBuffer {
|
class ConstSizeBuffer {
|
||||||
SelCopyArg<tType> Arg;
|
typedef SelCopyArg<tType> Arg;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
tType mBuff[tSize];
|
tType mBuff[tSize];
|
||||||
|
ualni mLoad = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ConstSizeBuffer() = default;
|
ConstSizeBuffer() = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] ualni size() const { return tSize; }
|
[[nodiscard]] ualni size() const { return mLoad; }
|
||||||
|
[[nodiscard]] ualni getBuffSize() const { return tSize; }
|
||||||
|
|
||||||
tType& first() {
|
tType& first() {
|
||||||
|
DEBUG_ASSERT(mLoad)
|
||||||
return *mBuff;
|
return *mBuff;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tType& first() const {
|
const tType& first() const {
|
||||||
|
DEBUG_ASSERT(mLoad)
|
||||||
return *mBuff;
|
return *mBuff;
|
||||||
}
|
}
|
||||||
|
|
||||||
tType& last() {
|
tType& last() {
|
||||||
return mBuff[tSize - 1];
|
DEBUG_ASSERT(mLoad)
|
||||||
|
return mBuff[mLoad - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
const tType& last() const {
|
const tType& last() const {
|
||||||
return mBuff[tSize - 1];
|
DEBUG_ASSERT(mLoad)
|
||||||
|
return mBuff[mLoad - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
tType& operator[](ualni aIdx) {
|
tType& operator[](ualni aIdx) {
|
||||||
DEBUG_ASSERT(aIdx >= 0 && aIdx < tSize)
|
DEBUG_ASSERT(aIdx >= 0 && aIdx < mLoad)
|
||||||
return mBuff[aIdx];
|
return mBuff[aIdx];
|
||||||
}
|
}
|
||||||
|
|
||||||
const tType& operator[](ualni aIdx) const {
|
const tType& operator[](ualni aIdx) const {
|
||||||
DEBUG_ASSERT(aIdx >= 0 && aIdx < tSize)
|
DEBUG_ASSERT(aIdx >= 0 && aIdx < mLoad)
|
||||||
return mBuff[aIdx];
|
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<tType>& 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<TypeTraits<tType>::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<
|
template<
|
||||||
|
|
@ -150,6 +219,14 @@ namespace tp {
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
Buffer& operator=(const tp::init_list<tType>& init) {
|
||||||
|
// TODO : optimize
|
||||||
|
for (auto arg : init) {
|
||||||
|
append(arg);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
void append(Arg data) {
|
void append(Arg data) {
|
||||||
if (mLoad == mSize) resizeBuffer(tResizePolicy(mSize));
|
if (mLoad == mSize) resizeBuffer(tResizePolicy(mSize));
|
||||||
new (&mBuff[mLoad]) tType(data);
|
new (&mBuff[mLoad]) tType(data);
|
||||||
|
|
@ -183,6 +260,53 @@ namespace tp {
|
||||||
for (ualni i = 0; i < mLoad; i++) new (mBuff + i) tType();
|
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<TypeTraits<tType>::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:
|
private:
|
||||||
void resizeBuffer(ualni newSize) {
|
void resizeBuffer(ualni newSize) {
|
||||||
DEBUG_ASSERT(newSize >= mLoad)
|
DEBUG_ASSERT(newSize >= mLoad)
|
||||||
|
|
|
||||||
31
Objects/CMakeLists.txt
Normal file
31
Objects/CMakeLists.txt
Normal file
|
|
@ -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)
|
||||||
20
Objects/README.md
Normal file
20
Objects/README.md
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
Objects
|
||||||
|
|
||||||
|
Objects are simple structures with run-time type information attached. <br>
|
||||||
|
|
||||||
|
## 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"
|
||||||
|
```
|
||||||
49
Objects/applications/Compiler.cpp
Normal file
49
Objects/applications/Compiler.cpp
Normal file
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
58
Objects/applications/Interpreter.cpp
Normal file
58
Objects/applications/Interpreter.cpp
Normal file
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
148
Objects/private/compiler/constants.cpp
Normal file
148
Objects/private/compiler/constants.cpp
Normal file
|
|
@ -0,0 +1,148 @@
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
#include "compiler/constants.h"
|
||||||
|
#include "primitives/primitives.h"
|
||||||
|
#include "primitives/methodobject.h"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
using namespace tp;
|
||||||
|
using namespace BCgen;
|
||||||
|
|
||||||
|
ConstObject::ConstObject() {}
|
||||||
|
ConstObject::ConstObject(obj::Object* mObj) : mObj(mObj) {}
|
||||||
|
|
||||||
|
ConstObjectsPool::~ConstObjectsPool() {
|
||||||
|
if (mDelete) {
|
||||||
|
for (auto obj : mStrings) {
|
||||||
|
obj::NDO->destroy(obj->val->mObj);
|
||||||
|
}
|
||||||
|
for (auto obj : mIntegers) {
|
||||||
|
obj::NDO->destroy(obj->val->mObj);
|
||||||
|
}
|
||||||
|
for (auto obj : mFloats) {
|
||||||
|
obj::NDO->destroy(obj->val->mObj);
|
||||||
|
}
|
||||||
|
for (auto obj : mMethods) {
|
||||||
|
obj::NDO->destroy(obj->val->mObj);
|
||||||
|
}
|
||||||
|
if (mBoolFalse.mObj) {
|
||||||
|
obj::NDO->destroy(mBoolFalse.mObj);
|
||||||
|
}
|
||||||
|
if (mBoolTrue.mObj) {
|
||||||
|
obj::NDO->destroy(mBoolTrue.mObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto obj : mStrings) {
|
||||||
|
delete obj->val;
|
||||||
|
}
|
||||||
|
for (auto obj : mIntegers) {
|
||||||
|
delete obj->val;
|
||||||
|
}
|
||||||
|
for (auto obj : mFloats) {
|
||||||
|
delete obj->val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstObject* ConstObjectsPool::registerObject(obj::Object* obj) {
|
||||||
|
ConstObject* out = new ConstObject(obj);
|
||||||
|
mTotalObjects++;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstObject* ConstObjectsPool::get(tp::alni val) {
|
||||||
|
auto idx = mIntegers.presents(val);
|
||||||
|
ConstObject* const_obj = NULL;
|
||||||
|
if (idx) {
|
||||||
|
const_obj = mIntegers.getSlotVal(idx);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const_obj = registerObject(IntObject::create(val));
|
||||||
|
mIntegers.put(val, const_obj);
|
||||||
|
}
|
||||||
|
return const_obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstObject* ConstObjectsPool::get(tp::String val) {
|
||||||
|
auto idx = mStrings.presents(val);
|
||||||
|
ConstObject* const_obj = NULL;
|
||||||
|
if (idx) {
|
||||||
|
const_obj = mStrings.getSlotVal(idx);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const_obj = registerObject(StringObject::create(val));
|
||||||
|
mStrings.put(val, const_obj);
|
||||||
|
}
|
||||||
|
return const_obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstObject* ConstObjectsPool::get(tp::alnf val) {
|
||||||
|
auto idx = mFloats.presents(val);
|
||||||
|
ConstObject* const_obj = NULL;
|
||||||
|
if (idx) {
|
||||||
|
const_obj = mFloats.getSlotVal(idx);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const_obj = registerObject(FloatObject::create(val));
|
||||||
|
mFloats.put(val, const_obj);
|
||||||
|
}
|
||||||
|
return const_obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstObject* ConstObjectsPool::get(bool val) {
|
||||||
|
if (val) {
|
||||||
|
if (!mBoolTrue.mObj) {
|
||||||
|
mBoolTrue.mObj = BoolObject::create(val);
|
||||||
|
mTotalObjects++;
|
||||||
|
}
|
||||||
|
return &mBoolTrue;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!mBoolFalse.mObj) {
|
||||||
|
mBoolFalse.mObj = BoolObject::create(val);
|
||||||
|
mTotalObjects++;
|
||||||
|
}
|
||||||
|
return &mBoolFalse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstObject* ConstObjectsPool::addMethod(tp::String method_id, obj::Object* method) {
|
||||||
|
ASSERT(NDO_CAST(MethodObject, method) && "Object is not a method object");
|
||||||
|
ASSERT(!mMethods.presents(method_id) && "Method Redefinition");
|
||||||
|
auto out = registerObject(method);
|
||||||
|
mMethods.put(method_id, out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConstObjectsPool::save(tp::Buffer<ConstData>& out) {
|
||||||
|
out.reserve(mTotalObjects);
|
||||||
|
tp::alni data_idx = 0;
|
||||||
|
for (auto obj : mMethods) {
|
||||||
|
out[data_idx] = obj->val->mObj;
|
||||||
|
obj->val->mConstIdx = data_idx;
|
||||||
|
data_idx++;
|
||||||
|
}
|
||||||
|
for (auto obj : mStrings) {
|
||||||
|
out[data_idx] = obj->val->mObj;
|
||||||
|
obj->val->mConstIdx = data_idx;
|
||||||
|
data_idx++;
|
||||||
|
}
|
||||||
|
for (auto obj : mIntegers) {
|
||||||
|
out[data_idx] = obj->val->mObj;
|
||||||
|
obj->val->mConstIdx = data_idx;
|
||||||
|
data_idx++;
|
||||||
|
}
|
||||||
|
for (auto obj : mFloats) {
|
||||||
|
out[data_idx] = obj->val->mObj;
|
||||||
|
obj->val->mConstIdx = data_idx;
|
||||||
|
data_idx++;
|
||||||
|
}
|
||||||
|
if (mBoolFalse.mObj) {
|
||||||
|
out[data_idx] = mBoolFalse.mObj;
|
||||||
|
mBoolFalse.mConstIdx = data_idx;
|
||||||
|
data_idx++;
|
||||||
|
}
|
||||||
|
if (mBoolTrue.mObj) {
|
||||||
|
out[data_idx] = mBoolTrue.mObj;
|
||||||
|
mBoolTrue.mConstIdx = data_idx;
|
||||||
|
}
|
||||||
|
mDelete = false;
|
||||||
|
}
|
||||||
70
Objects/private/compiler/expression.cpp
Normal file
70
Objects/private/compiler/expression.cpp
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
#include "compiler/expression.h"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
using namespace BCgen;
|
||||||
|
|
||||||
|
Expression::Expression() {}
|
||||||
|
Expression::Expression(Type type) : mType(type) {}
|
||||||
|
|
||||||
|
ExpressionChild* Expression::ExprChild(tp::String id) {
|
||||||
|
return new ExpressionChild(this, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionCall* Expression::ExprCall(tp::init_list<Expression*> args) {
|
||||||
|
return new ExpressionCall(this, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionLocal* obj::BCgen::ExprLocal(tp::String id) {
|
||||||
|
return new ExpressionLocal(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionSelf* obj::BCgen::ExprSelf() {
|
||||||
|
return new ExpressionSelf();
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionNew* obj::BCgen::ExprNew(tp::String type) {
|
||||||
|
return new ExpressionNew(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionAriphm* obj::BCgen::ExprAriphm(Expression* left, Expression* right, OpCode type) {
|
||||||
|
return new ExpressionAriphm(left, right, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionFunc* obj::BCgen::ExprFunc(tp::String id) {
|
||||||
|
return new ExpressionFunc(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionBoolean* obj::BCgen::ExprBool(Expression* left, Expression* right, obj::OpCode type) {
|
||||||
|
return new ExpressionBoolean(left, right, ExpressionBoolean::BoolType(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionBoolean* obj::BCgen::ExprBoolNot(Expression* invert) {
|
||||||
|
return new ExpressionBoolean(invert);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionBoolean::ExpressionBoolean(Expression* left, Expression* right, BoolType type)
|
||||||
|
: Expression(Type::BOOLEAN), mLeft(left), mRight(right), mBoolType(type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionBoolean::ExpressionBoolean(Expression* invert)
|
||||||
|
: Expression(Type::BOOLEAN), mLeft(invert), mBoolType(BoolType::NOT){
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionCall::ExpressionCall(Expression * mParent, tp::init_list<Expression*> args) : Expression(Type::CALL), mParent(mParent) {
|
||||||
|
mArgs = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionNew::ExpressionNew(tp::String type) : Expression(Type::NEW), mNewType(type) {}
|
||||||
|
ExpressionLocal::ExpressionLocal(tp::String id) : Expression(Type::LOCAL), mLocalId(id) {}
|
||||||
|
ExpressionSelf::ExpressionSelf() : Expression(Type::SELF) {}
|
||||||
|
ExpressionChild::ExpressionChild(Expression* mParent, tp::String id) : Expression(Type::CHILD), mParent(mParent), mLocalId(id) {}
|
||||||
|
ExpressionAriphm::ExpressionAriphm(Expression* left, Expression* right, OpCode type) : Expression(Type::ARIPHM), mLeft(left), mRight(right), mOpType(type) {}
|
||||||
|
ExpressionFunc::ExpressionFunc(tp::String id) : Expression(Type::FUNC), mFuncId(id) {}
|
||||||
|
ExpressionConst::ExpressionConst(tp::String val) : Expression(Type::CONST), mConstType(STR), str(val) {}
|
||||||
|
ExpressionConst::ExpressionConst(const char* val) : Expression(Type::CONST), mConstType(STR), str(val) {}
|
||||||
|
ExpressionConst::ExpressionConst(tp::int4 val) : Expression(Type::CONST), mConstType(INT), integer(val) {}
|
||||||
|
ExpressionConst::ExpressionConst(tp::flt4 val) : Expression(Type::CONST), mConstType(FLT), floating(val) {}
|
||||||
|
ExpressionConst::ExpressionConst(tp::alni val) : Expression(Type::CONST), mConstType(INT), integer(val) {}
|
||||||
|
ExpressionConst::ExpressionConst(tp::alnf val) : Expression(Type::CONST), mConstType(FLT), floating(val) {}
|
||||||
|
ExpressionConst::ExpressionConst(bool val) : Expression(Type::CONST), mConstType(BOOL), boolean(val) {}
|
||||||
556
Objects/private/compiler/function.cpp
Normal file
556
Objects/private/compiler/function.cpp
Normal file
|
|
@ -0,0 +1,556 @@
|
||||||
|
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
|
||||||
|
#include "compiler/function.h"
|
||||||
|
|
||||||
|
#include "primitives/primitives.h"
|
||||||
|
#include "primitives/methodobject.h"
|
||||||
|
|
||||||
|
#include "Logging.hpp"
|
||||||
|
|
||||||
|
#include "parser/parser.h"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
using namespace tp;
|
||||||
|
using namespace obj;
|
||||||
|
using namespace BCgen;
|
||||||
|
|
||||||
|
void obj::BCgen::Genereate(ByteCode& out, StatementScope* body) {
|
||||||
|
auto root = FunctionDefinition();
|
||||||
|
|
||||||
|
root.inst(Instruction(OpCode::SCOPE_IN));
|
||||||
|
|
||||||
|
for (auto child_stm : body->mStatements) {
|
||||||
|
root.EvalStatement(child_stm.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
root.inst(Instruction(OpCode::SCOPE_OUT));
|
||||||
|
|
||||||
|
root.generateByteCode(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstObject* FunctionDefinition::defineLocal(tp::String id) {
|
||||||
|
auto idx = mLocals.presents(id);
|
||||||
|
//RelAssert(!idx && "Local Redefinition");
|
||||||
|
auto const_str_id = mConstants.get(id);
|
||||||
|
mLocals.put(id, const_str_id);
|
||||||
|
return const_str_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionDefinition::FunctionDefinition(tp::String function_id, tp::Buffer<tp::String> args, FunctionDefinition* prnt) {
|
||||||
|
mFunctionId = function_id;
|
||||||
|
inst(Instruction(OpCode::SAVE_ARGS, args.size(), 1));
|
||||||
|
for (auto id : args) {
|
||||||
|
ASSERT(!mLocals.presents(id.data()) && "Argument Redefinition");
|
||||||
|
auto const_data = mConstants.get(id.data());
|
||||||
|
mArgsOrder.pushBack(const_data);
|
||||||
|
mLocals.put(id.data(), const_data);
|
||||||
|
inst(Instruction(const_data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FunctionDefinition::EvalStatement(Statement* stm) {
|
||||||
|
switch (stm->mType) {
|
||||||
|
case Statement::Type::IGNORE: {
|
||||||
|
auto stm_ignore = (StatementIgnore*)stm;
|
||||||
|
EvalExpr(stm_ignore->mExpr);
|
||||||
|
inst(OpCode::IGNORE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Statement::Type::WHILE: {
|
||||||
|
auto stm_while = (StatementWhile*)stm;
|
||||||
|
|
||||||
|
auto check_mark = inst(Instruction());
|
||||||
|
|
||||||
|
EvalExpr(stm_while->mCondition);
|
||||||
|
|
||||||
|
auto jump_if_inst = inst(Instruction(NULL, Instruction::InstType::JUMP_IF_NOT));
|
||||||
|
|
||||||
|
if (stm_while->mScope) {
|
||||||
|
EvalStatement(stm_while->mScope);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto jump_inst = inst(Instruction(NULL, Instruction::InstType::JUMP));
|
||||||
|
auto end_mark = inst(Instruction());
|
||||||
|
|
||||||
|
jump_if_inst->data.mInstTarget = end_mark;
|
||||||
|
jump_inst->data.mInstTarget = check_mark;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Statement::Type::IF: {
|
||||||
|
auto stm_if = (StatementIf*)stm;
|
||||||
|
|
||||||
|
EvalExpr(stm_if->mCondition);
|
||||||
|
|
||||||
|
auto jump_if_inst = inst(Instruction(NULL, Instruction::InstType::JUMP_IF_NOT));
|
||||||
|
|
||||||
|
if (stm_if->mOnTrue) {
|
||||||
|
EvalStatement(stm_if->mOnTrue);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto jump_inst = inst(Instruction(NULL, Instruction::InstType::JUMP));
|
||||||
|
auto else_mark = inst(Instruction());
|
||||||
|
|
||||||
|
if (stm_if->mOnFalse) {
|
||||||
|
EvalStatement(stm_if->mOnFalse);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto end_mark = inst(Instruction());
|
||||||
|
|
||||||
|
jump_if_inst->data.mInstTarget = else_mark;
|
||||||
|
jump_inst->data.mInstTarget = end_mark;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Statement::Type::SCOPE: {
|
||||||
|
auto stm_scope = (StatementScope*)stm;
|
||||||
|
if (stm_scope->mPushToScopeStack) {
|
||||||
|
inst(Instruction(OpCode::SCOPE_IN));
|
||||||
|
}
|
||||||
|
for (auto child_stm : stm_scope->mStatements) {
|
||||||
|
EvalStatement(child_stm.data());
|
||||||
|
}
|
||||||
|
if (stm_scope->mPushToScopeStack) {
|
||||||
|
inst(Instruction(OpCode::SCOPE_OUT));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Statement::Type::DEF_FUNC: {
|
||||||
|
auto stm_func_def = (StatementFuncDef*) stm;
|
||||||
|
|
||||||
|
FunctionDefinition func(stm_func_def->mFunctionId, stm_func_def->mArgs, this);
|
||||||
|
|
||||||
|
// define method as local
|
||||||
|
auto idx = mLocals.presents(func.mFunctionId);
|
||||||
|
ASSERT(!idx && "Local Redefinition with function name");
|
||||||
|
mLocals.put(func.mFunctionId, mConstants.get(func.mFunctionId));
|
||||||
|
|
||||||
|
// create and register const func object
|
||||||
|
auto function_obj = NDO_CAST(MethodObject, NDO->create("method"));
|
||||||
|
auto method_const_obj = mConstants.addMethod(func.mFunctionId, function_obj);
|
||||||
|
|
||||||
|
for (auto child_stm : stm_func_def->mStatements) {
|
||||||
|
func.EvalStatement(child_stm.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
func.generateByteCode(function_obj->mScript->mBytecode);
|
||||||
|
|
||||||
|
inst(Instruction(OpCode::LOAD_CONST, method_const_obj));
|
||||||
|
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(func.mFunctionId)));
|
||||||
|
inst(Instruction(OpCode::DEF_LOCAL));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Statement::Type::CLASS_DEF: {
|
||||||
|
|
||||||
|
// do the function definition
|
||||||
|
auto stm_class_def = (StatementClassDef*)stm;
|
||||||
|
|
||||||
|
FunctionDefinition func(stm_class_def->mClassId, {}, this);
|
||||||
|
|
||||||
|
// define method as local
|
||||||
|
auto idx = mLocals.presents(func.mFunctionId);
|
||||||
|
ASSERT(!idx && "Local Redefinition with function name");
|
||||||
|
mLocals.put(func.mFunctionId, mConstants.get(func.mFunctionId));
|
||||||
|
|
||||||
|
// create and register const func object
|
||||||
|
auto function_obj = NDO_CAST(MethodObject, NDO->create("method"));
|
||||||
|
auto method_const_obj = mConstants.addMethod(func.mFunctionId, function_obj);
|
||||||
|
|
||||||
|
// compile function
|
||||||
|
for (auto child_stm : stm_class_def->mScope->mStatements) {
|
||||||
|
// check for return statements
|
||||||
|
ASSERT(child_stm.data()->mType != Statement::Type::RET && "return statements are not allowed in class definition");
|
||||||
|
func.EvalStatement(child_stm.data());
|
||||||
|
}
|
||||||
|
// create one last instruction - constructing class from function execution state
|
||||||
|
func.inst(Instruction(OpCode::CLASS_CONSTRUCT));
|
||||||
|
func.generateByteCode(function_obj->mScript->mBytecode);
|
||||||
|
|
||||||
|
inst(Instruction(OpCode::LOAD_CONST, method_const_obj));
|
||||||
|
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(func.mFunctionId)));
|
||||||
|
inst(Instruction(OpCode::DEF_LOCAL));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Statement::Type::DEF_LOCAL: {
|
||||||
|
auto stm_local_def = (StatementLocalDef*)stm;
|
||||||
|
|
||||||
|
if (!stm_local_def->mIsConstExpr) {
|
||||||
|
auto const_id = defineLocal(stm_local_def->mLocalId);
|
||||||
|
EvalExpr(stm_local_def->mNewExpr);
|
||||||
|
inst(Instruction(OpCode::LOAD_CONST, const_id));
|
||||||
|
inst(Instruction(OpCode::DEF_LOCAL));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
tp::String type;
|
||||||
|
switch (stm_local_def->mConstExpr->mConstType) {
|
||||||
|
case ExpressionConst::BOOL: {
|
||||||
|
type = "bool";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ExpressionConst::INT: {
|
||||||
|
type = "int";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ExpressionConst::FLT: {
|
||||||
|
type = "float";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ExpressionConst::STR: {
|
||||||
|
type = "str";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
ASSERT(0 && "Cantbe");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto new_expr = new ExpressionNew(type);
|
||||||
|
|
||||||
|
EvalStatement(StmDefLocal(stm_local_def->mLocalId, new_expr));
|
||||||
|
EvalExpr(stm_local_def->mConstExpr);
|
||||||
|
inst(Instruction(OpCode::LOAD_LOCAL, mConstants.get(stm_local_def->mLocalId)));
|
||||||
|
inst(Instruction(OpCode::OBJ_COPY));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Statement::Type::COPY: {
|
||||||
|
auto stm_cp = (StatementCopy*)stm;
|
||||||
|
EvalExpr(stm_cp->mRight);
|
||||||
|
EvalExpr(stm_cp->mLeft);
|
||||||
|
inst(Instruction(OpCode::OBJ_COPY));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Statement::Type::PRINT: {
|
||||||
|
auto stm_prnt = (StatementPrint*)stm;
|
||||||
|
EvalExpr(stm_prnt->mTarget);
|
||||||
|
inst(Instruction(OpCode::PRINT));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Statement::Type::RET: {
|
||||||
|
auto stm_ret = (StatementReturn*)stm;
|
||||||
|
if (stm_ret->mRet) {
|
||||||
|
EvalExpr(stm_ret->mRet);
|
||||||
|
inst(Instruction(OpCode::RETURN_OBJ));
|
||||||
|
} else {
|
||||||
|
inst(Instruction(OpCode::RETURN));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
ASSERT(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
delete stm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FunctionDefinition::EvalExpr(Expression* expr) {
|
||||||
|
switch (expr->mType) {
|
||||||
|
case Expression::Type::BOOLEAN: {
|
||||||
|
auto boolean = (ExpressionBoolean*)expr;
|
||||||
|
if (boolean->mBoolType == ExpressionBoolean::BoolType::NOT) {
|
||||||
|
EvalExpr(boolean->mLeft);
|
||||||
|
inst(OpCode::NOT);
|
||||||
|
} else {
|
||||||
|
EvalExpr(boolean->mRight);
|
||||||
|
EvalExpr(boolean->mLeft);
|
||||||
|
inst(OpCode(boolean->mBoolType));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Expression::Type::FUNC: {
|
||||||
|
auto func = (ExpressionFunc*)expr;
|
||||||
|
|
||||||
|
//RelAssert(mConstants.mMethods.presents(func->mFuncId) && "No such function");
|
||||||
|
inst(Instruction(OpCode::LOAD_LOCAL, mConstants.get(func->mFuncId)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Expression::Type::ARIPHM: {
|
||||||
|
auto ariphm = (ExpressionAriphm*)expr;
|
||||||
|
EvalExpr(ariphm->mRight);
|
||||||
|
EvalExpr(ariphm->mLeft);
|
||||||
|
inst(Instruction(ariphm->mOpType));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Expression::Type::NEW: {
|
||||||
|
auto create_new = (ExpressionNew*)expr;
|
||||||
|
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(create_new->mNewType)));
|
||||||
|
inst(Instruction(OpCode::OBJ_CREATE));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Expression::Type::LOCAL: {
|
||||||
|
auto local = (ExpressionLocal*)expr;
|
||||||
|
// RelAssert(mLocals.presents(local->mLocalId) && "undefined local");
|
||||||
|
inst(Instruction(OpCode::LOAD_LOCAL, mConstants.get(local->mLocalId)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Expression::Type::CONST: {
|
||||||
|
auto constobj = (ExpressionConst*)expr;
|
||||||
|
switch (constobj->mConstType) {
|
||||||
|
case ExpressionConst::STR: {
|
||||||
|
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(constobj->str)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ExpressionConst::INT: {
|
||||||
|
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(constobj->integer)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ExpressionConst::FLT: {
|
||||||
|
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(constobj->floating)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ExpressionConst::BOOL: {
|
||||||
|
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(constobj->boolean)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Expression::Type::CHILD: {
|
||||||
|
auto child = (ExpressionChild*)expr;
|
||||||
|
EvalExpr(child->mParent);
|
||||||
|
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(child->mLocalId)));
|
||||||
|
inst(Instruction(OpCode::CHILD, child->mMethod, 1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Expression::Type::SELF: {
|
||||||
|
inst(Instruction(OpCode::SELF));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Expression::Type::CALL: {
|
||||||
|
auto call = (ExpressionCall*)expr;
|
||||||
|
inst(Instruction(OpCode::PUSH_ARGS, call->mArgs.size(), 1));
|
||||||
|
for (auto arg : call->mArgs) {
|
||||||
|
EvalExpr(arg.data());
|
||||||
|
}
|
||||||
|
EvalExpr(call->mParent);
|
||||||
|
inst(Instruction(OpCode::CALL));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
ASSERT(0)
|
||||||
|
}
|
||||||
|
delete expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::alni instSize(const Instruction& inst) {
|
||||||
|
switch (inst.mInstType) {
|
||||||
|
case Instruction::InstType::JUMP:
|
||||||
|
case Instruction::InstType::JUMP_IF_NOT:
|
||||||
|
case Instruction::InstType::JUMP_IF: {
|
||||||
|
// 2 bytes for offset 1 byte for instrtuction
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
case Instruction::InstType::PURE_CONST: {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
case Instruction::InstType::EXEC: {
|
||||||
|
tp::alni out = 1;
|
||||||
|
switch (inst.mArgType) {
|
||||||
|
case Instruction::ArgType::PARAM: {
|
||||||
|
out += inst.mParamBytes;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
case Instruction::ArgType::CONST: {
|
||||||
|
out += 2;
|
||||||
|
if (inst.mConstData2) {
|
||||||
|
out += 2;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
case Instruction::ArgType::NO_ARG: {
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
ASSERT(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case Instruction::InstType::NONE: {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
ASSERT(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeConst(ByteCode& out, tp::alni& idx, tp::uint2 data) {
|
||||||
|
for (auto byte : tp::Range(sizeof(tp::uint2))) {
|
||||||
|
out.mInstructions[idx] = OpCode((tp::int1)(data >> byte * 8));
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeParam(ByteCode& out, tp::alni& idx, tp::int1* data, tp::alni size) {
|
||||||
|
for (auto byte : tp::Range(size)) {
|
||||||
|
out.mInstructions[idx] = OpCode(data[byte]);
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::alni calcOffset(tp::List<Instruction>::Node* jump_inst, tp::List<Instruction>::Node* to) {
|
||||||
|
tp::alni offset = 0;
|
||||||
|
bool reversed = jump_inst->data.mInstIdx > to->data.mInstIdx;
|
||||||
|
auto iter_node = reversed ? jump_inst : jump_inst->next;
|
||||||
|
while (iter_node != to) {
|
||||||
|
offset += instSize(iter_node->data);
|
||||||
|
iter_node = reversed ? iter_node->prev : iter_node->next;
|
||||||
|
}
|
||||||
|
if (reversed) {
|
||||||
|
offset += instSize(iter_node->data);
|
||||||
|
}
|
||||||
|
return reversed ? -offset : offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FunctionDefinition::generateByteCode(ByteCode& out) {
|
||||||
|
|
||||||
|
out.~ByteCode();
|
||||||
|
new (&out) ByteCode();
|
||||||
|
|
||||||
|
mConstants.save(out.mConstants);
|
||||||
|
|
||||||
|
tp::alni inst_len = 0;
|
||||||
|
for (auto inst_iter : mInstructions) {
|
||||||
|
inst_len += instSize(inst_iter.data());
|
||||||
|
}
|
||||||
|
out.mInstructions.reserve(inst_len);
|
||||||
|
|
||||||
|
tp::alni idx = 0;
|
||||||
|
for (auto inst_iter : mInstructions) {
|
||||||
|
auto inst = inst_iter.data();
|
||||||
|
|
||||||
|
switch (inst.mInstType) {
|
||||||
|
case Instruction::InstType::JUMP_IF:
|
||||||
|
case Instruction::InstType::JUMP_IF_NOT:
|
||||||
|
case Instruction::InstType::JUMP: {
|
||||||
|
tp::alni offset = calcOffset(inst_iter.node(), inst.mInstTarget);
|
||||||
|
|
||||||
|
if (offset == 0) {
|
||||||
|
out.mInstructions[idx] = OpCode::NONE;
|
||||||
|
idx += 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inst.mInstType == Instruction::InstType::JUMP_IF) {
|
||||||
|
if (offset > 0) {
|
||||||
|
out.mInstructions[idx] = OpCode::JUMP_IF;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out.mInstructions[idx] = OpCode::JUMP_IF_R;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (inst.mInstType == Instruction::InstType::JUMP_IF_NOT) {
|
||||||
|
if (offset > 0) {
|
||||||
|
out.mInstructions[idx] = OpCode::JUMP_IF_NOT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out.mInstructions[idx] = OpCode::JUMP_IF_NOT_R;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (offset > 0) {
|
||||||
|
out.mInstructions[idx] = OpCode::JUMP;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out.mInstructions[idx] = OpCode::JUMP_R;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
idx++;
|
||||||
|
|
||||||
|
tp::alni offset_mod = abs(offset);
|
||||||
|
tp::uint2 offset_param = (tp::uint2)offset_mod;
|
||||||
|
writeParam(out, idx, (tp::int1*)&offset_param, 2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Instruction::InstType::PURE_CONST: {
|
||||||
|
writeConst(out, idx, (tp::uint2)inst.mConstData->mConstIdx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Instruction::InstType::EXEC: {
|
||||||
|
out.mInstructions[idx] = inst.mOp;
|
||||||
|
idx++;
|
||||||
|
switch (inst.mArgType) {
|
||||||
|
case Instruction::ArgType::PARAM: {
|
||||||
|
writeParam(out, idx, (tp::int1*) &inst.mParam, inst.mParamBytes);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Instruction::ArgType::CONST: {
|
||||||
|
writeConst(out, idx, (tp::uint2)inst.mConstData->mConstIdx);
|
||||||
|
if (inst.mConstData2) {
|
||||||
|
writeConst(out, idx, (tp::uint2)inst.mConstData2->mConstIdx);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Instruction::ArgType::NO_ARG: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:{
|
||||||
|
ASSERT(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
ASSERT(0);
|
||||||
|
}
|
||||||
|
case Instruction::InstType::NONE: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::List<Instruction>::Node* FunctionDefinition::inst(Instruction inst) {
|
||||||
|
mInstructions.pushBack(inst);
|
||||||
|
auto out = &mInstructions.last()->data;
|
||||||
|
out->mInstIdx = mInstructions.length() - 1;
|
||||||
|
return mInstructions.last();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Parser* sParger = NULL;
|
||||||
|
|
||||||
|
void obj::BCgen::init() {
|
||||||
|
ASSERT(!sParger);
|
||||||
|
if (!sParger) {
|
||||||
|
sParger = new Parser();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void obj::BCgen::deinit() {
|
||||||
|
ASSERT(sParger);
|
||||||
|
if (sParger) {
|
||||||
|
delete sParger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool obj::BCgen::Compile(obj::MethodObject* method) {
|
||||||
|
|
||||||
|
ASSERT(method);
|
||||||
|
ASSERT(sParger);
|
||||||
|
|
||||||
|
if (!sParger) return false;
|
||||||
|
|
||||||
|
auto script = method->mScript->mReadable->val;
|
||||||
|
auto res = sParger->parse(script);
|
||||||
|
|
||||||
|
if (res.err) {
|
||||||
|
auto loc = res.err->get_err_location(script.read());
|
||||||
|
// TODO : print parse error
|
||||||
|
// tp::gLogeer->write(tp::sfmt("Parser Error (%i,%i): \n", loc.head, loc.tail), true, tp::Logger::LogEntry::ERR);
|
||||||
|
// tp::GLog->write(res.err->mDescr, true, tp::Logger::LogEntry::ERR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BCgen::Genereate(method->mScript->mBytecode, res.scope);
|
||||||
|
|
||||||
|
delete res.scope;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
29
Objects/private/compiler/instruction.cpp
Normal file
29
Objects/private/compiler/instruction.cpp
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
|
||||||
|
#include "compiler/instruction.h"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
using namespace tp;
|
||||||
|
using namespace BCgen;
|
||||||
|
|
||||||
|
Instruction::Instruction(OpCode op) : mOp(op), mArgType(ArgType::NO_ARG), mInstType(InstType::EXEC) {}
|
||||||
|
|
||||||
|
Instruction::Instruction() : mInstType(InstType::NONE) {}
|
||||||
|
|
||||||
|
Instruction::Instruction(ConstObject* constData)
|
||||||
|
: mConstData(constData), mInstType(InstType::PURE_CONST) {}
|
||||||
|
|
||||||
|
Instruction::Instruction(OpCode op, ConstObject* constData)
|
||||||
|
: mOp(op), mConstData(constData), mArgType(ArgType::CONST), mInstType(InstType::EXEC) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction::Instruction(OpCode op, ConstObject* constData, ConstObject* constData2)
|
||||||
|
: mOp(op), mConstData(constData), mConstData2(constData2), mArgType(ArgType::CONST), mInstType(InstType::EXEC) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction::Instruction(OpCode op, tp::alni param, tp::alni nBytes)
|
||||||
|
: mOp(op), mParam(param), mArgType(ArgType::PARAM), mParamBytes(nBytes), mInstType(InstType::EXEC) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction::Instruction(tp::List<Instruction>::Node* inst, InstType jump_type): mInstTarget(inst) {
|
||||||
|
mInstType = jump_type;
|
||||||
|
}
|
||||||
116
Objects/private/compiler/statement.cpp
Normal file
116
Objects/private/compiler/statement.cpp
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
#include "compiler/statement.h"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
using namespace BCgen;
|
||||||
|
|
||||||
|
|
||||||
|
StatementFuncDef::StatementFuncDef(tp::String function_id, tp::init_list<tp::String> args, tp::init_list<Statement*> statements) {
|
||||||
|
mType = Type::DEF_FUNC;
|
||||||
|
mArgs = args;
|
||||||
|
mStatements = statements;
|
||||||
|
mFunctionId = function_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementLocalDef::StatementLocalDef(tp::String id, Expression* value) : mLocalId(id), mNewExpr(value) {
|
||||||
|
mType = Type::DEF_LOCAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementLocalDef::StatementLocalDef(tp::String id, ExpressionConst* value) : mLocalId(id), mConstExpr(value), mIsConstExpr(true) {
|
||||||
|
mType = Type::DEF_LOCAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementCopy::StatementCopy(Expression* left, Expression* right) : mLeft(left), mRight(right) {
|
||||||
|
mType = Type::COPY;
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementReturn::StatementReturn() {
|
||||||
|
mType = Type::RET;
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementReturn::StatementReturn(Expression* ret) : mRet(ret) {
|
||||||
|
mType = Type::RET;
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementPrint::StatementPrint(Expression* target) : mTarget(target) {
|
||||||
|
mType = Type::PRINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementScope::StatementScope(tp::init_list<Statement*> statements, bool aPushToScopeStack) {
|
||||||
|
mType = Type::SCOPE;
|
||||||
|
mStatements = statements;
|
||||||
|
mPushToScopeStack = aPushToScopeStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementIf::StatementIf(Expression* condition, StatementScope* on_true, StatementScope* on_false) {
|
||||||
|
mType = Type::IF;
|
||||||
|
mOnFalse = on_false;
|
||||||
|
mOnTrue = on_true;
|
||||||
|
mCondition = condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementWhile::StatementWhile(Expression* condition, StatementScope* scope) {
|
||||||
|
mType = Type::WHILE;
|
||||||
|
mScope = scope;
|
||||||
|
mCondition = condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementIgnore::StatementIgnore(Expression* expr) {
|
||||||
|
mType = Type::IGNORE;
|
||||||
|
mExpr = expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementClassDef::StatementClassDef(tp::String class_id, StatementScope* scope) {
|
||||||
|
mClassId = class_id;
|
||||||
|
mScope = scope;
|
||||||
|
mType = Type::CLASS_DEF;
|
||||||
|
}
|
||||||
|
// helpers
|
||||||
|
|
||||||
|
StatementFuncDef* obj::BCgen::StmDefFunc(tp::String id, tp::init_list<tp::String> args, tp::init_list<Statement*> stms) {
|
||||||
|
return new StatementFuncDef(id, args, stms);
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementLocalDef* obj::BCgen::StmDefLocal(tp::String id, Expression* value) {
|
||||||
|
if (value->mType == Expression::Type::CONST) {
|
||||||
|
return new StatementLocalDef(id, (ExpressionConst*)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new StatementLocalDef(id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementCopy* obj::BCgen::StmCopy(Expression* left, Expression* right) {
|
||||||
|
return new StatementCopy(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementPrint* obj::BCgen::StmPrint(Expression* target) {
|
||||||
|
return new StatementPrint(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementReturn* obj::BCgen::StmReturn() {
|
||||||
|
return new StatementReturn();
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementReturn* obj::BCgen::StmReturn(Expression* obj) {
|
||||||
|
return new StatementReturn(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementIf* obj::BCgen::StmIf(Expression* condition, StatementScope* on_true, StatementScope* on_false) {
|
||||||
|
return new StatementIf(condition, on_true, on_false);
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementScope* obj::BCgen::StmScope(tp::init_list<Statement*> statements, bool aPushToScopeStack = false) {
|
||||||
|
return new StatementScope(statements, aPushToScopeStack);
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementWhile* obj::BCgen::StmWhile(Expression* condition, StatementScope* scope) {
|
||||||
|
return new StatementWhile(condition, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementIgnore* obj::BCgen::StmIgnore(Expression* expr) {
|
||||||
|
return new StatementIgnore(expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementClassDef* obj::BCgen::StmClassDef(tp::String id, StatementScope* scope) {
|
||||||
|
return new StatementClassDef(id, scope);
|
||||||
|
}
|
||||||
250
Objects/private/core/object.cpp
Normal file
250
Objects/private/core/object.cpp
Normal file
|
|
@ -0,0 +1,250 @@
|
||||||
|
|
||||||
|
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
|
||||||
|
#include "core/object.h"
|
||||||
|
|
||||||
|
#include "primitives/nullobject.h"
|
||||||
|
#include "primitives/classobject.h"
|
||||||
|
#include "primitives/methodobject.h"
|
||||||
|
|
||||||
|
#include "interpreter/interpreter.h"
|
||||||
|
#include "compiler/function.h"
|
||||||
|
|
||||||
|
namespace obj {
|
||||||
|
|
||||||
|
Object* ObjectMemAllocate(const ObjectType* type);
|
||||||
|
void ObjectMemDeallocate(Object* in);
|
||||||
|
|
||||||
|
objects_api* NDO = NULL;
|
||||||
|
|
||||||
|
void hierarchy_copy(Object* self, const Object* in, const ObjectType* type);
|
||||||
|
void hierarchy_construct(Object* self, const ObjectType* type);
|
||||||
|
|
||||||
|
objects_api::objects_api() {
|
||||||
|
tp::memSetVal(sl_callbacks, SAVE_LOAD_MAX_CALLBACK_SLOTS * sizeof(save_load_callbacks*), 0);
|
||||||
|
interp = new Interpreter();
|
||||||
|
}
|
||||||
|
|
||||||
|
objects_api::~objects_api() {
|
||||||
|
delete interp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void objects_api::define(ObjectType* type) {
|
||||||
|
MODULE_SANITY_CHECK(gModuleObjects);
|
||||||
|
|
||||||
|
DEBUG_ASSERT(NDO && "using uninitialize objects api");
|
||||||
|
DEBUG_ASSERT(!types.presents(type->name) && "Type Redefinition");
|
||||||
|
types.put(type->name, type);
|
||||||
|
|
||||||
|
type->type_methods.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
Object* objects_api::create(const tp::String& name) {
|
||||||
|
MODULE_SANITY_CHECK(gModuleObjects);
|
||||||
|
|
||||||
|
const ObjectType* type = types.get(name);
|
||||||
|
|
||||||
|
Object* obj_instance = ObjectMemAllocate(type);
|
||||||
|
|
||||||
|
if (!obj_instance) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
hierarchy_construct(obj_instance, obj_instance->type);
|
||||||
|
|
||||||
|
setrefc(obj_instance, 0);
|
||||||
|
|
||||||
|
NDO_CASTV(ClassObject, obj_instance, classobj);
|
||||||
|
if (classobj) {
|
||||||
|
auto idx = classobj->members->presents("__init__");
|
||||||
|
DEBUG_ASSERT(idx);
|
||||||
|
if (idx) {
|
||||||
|
auto constructor_obj = classobj->members->getSlotVal(idx);
|
||||||
|
NDO_CASTV(MethodObject, constructor_obj, constructor_method);
|
||||||
|
if (constructor_method) {
|
||||||
|
interp->execAll(constructor_method, classobj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object* objects_api::copy(Object* self, const Object* in) {
|
||||||
|
if (self->type != in->type) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
hierarchy_copy(self, in, self->type);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool objects_api::compare(Object* first, Object* second) {
|
||||||
|
if (first->type == second->type) {
|
||||||
|
if (first->type->comparison) {
|
||||||
|
return first->type->comparison(first, second);
|
||||||
|
}
|
||||||
|
|
||||||
|
// raw data comparison
|
||||||
|
return tp::memCompare(first, second, first->type->size) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object* objects_api::instatiate(Object* in) {
|
||||||
|
obj::Object* obj = NDO->create(in->type->name);
|
||||||
|
NDO->copy(obj, in);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
void objects_api::set(Object* self, tp::alni val) {
|
||||||
|
if (self->type->convesions && self->type->convesions->from_int) {
|
||||||
|
self->type->convesions->from_int(self, val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void objects_api::set(Object* self, tp::alnf val) {
|
||||||
|
if (self->type->convesions && self->type->convesions->from_float) {
|
||||||
|
self->type->convesions->from_float(self, val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void objects_api::set(Object* self, tp::String val) {
|
||||||
|
if (self->type->convesions && self->type->convesions->from_string) {
|
||||||
|
self->type->convesions->from_string(self, val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::alni objects_api::toInt(Object* self) {
|
||||||
|
DEBUG_ASSERT(self->type->convesions && self->type->convesions->to_int);
|
||||||
|
return self->type->convesions->to_int(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::alnf objects_api::toFloat(Object* self) {
|
||||||
|
DEBUG_ASSERT(self->type->convesions && self->type->convesions->to_float);
|
||||||
|
return self->type->convesions->to_float(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool objects_api::toBool(Object* self) {
|
||||||
|
if (self->type->convesions && self->type->convesions->to_int) {
|
||||||
|
return (bool) self->type->convesions->to_int(self);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::String objects_api::toString(Object* self) {
|
||||||
|
DEBUG_ASSERT(self->type->convesions && self->type->convesions->to_string);
|
||||||
|
return self->type->convesions->to_string(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
void objects_api::destroy(Object* in) {
|
||||||
|
|
||||||
|
if (!in) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef OBJECT_REF_COUNT
|
||||||
|
ObjectMemHead* mh = NDO_MEMH_FROM_NDO(in);
|
||||||
|
if (mh->refc > 1) {
|
||||||
|
mh->refc--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NDO_CASTV(ClassObject, in, classobj);
|
||||||
|
if (classobj) {
|
||||||
|
auto idx = classobj->members->presents("__del__");
|
||||||
|
DEBUG_ASSERT(idx);
|
||||||
|
if (idx) {
|
||||||
|
auto constructor_obj = classobj->members->getSlotVal(idx);
|
||||||
|
NDO_CASTV(MethodObject, constructor_obj, constructor_method);
|
||||||
|
if (constructor_method) {
|
||||||
|
interp->execAll(constructor_method, classobj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const ObjectType* iter = in->type; iter; iter = iter->base) {
|
||||||
|
if (iter->destructor) {
|
||||||
|
iter->destructor(in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectMemDeallocate(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef OBJECT_REF_COUNT
|
||||||
|
tp::halni objects_api::getrefc(Object* in) {
|
||||||
|
ObjectMemHead* mh = NDO_MEMH_FROM_NDO(in);
|
||||||
|
return (tp::halni)mh->refc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void objects_api::refinc(Object* in) {
|
||||||
|
ObjectMemHead* mh = NDO_MEMH_FROM_NDO(in);
|
||||||
|
mh->refc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void objects_api::setrefc(Object* in, tp::halni refc) {
|
||||||
|
ObjectMemHead* mh = NDO_MEMH_FROM_NDO(in);
|
||||||
|
mh->refc = refc;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void hierarchy_copy(Object* self, const Object* in, const ObjectType* type) {
|
||||||
|
if (type->base) {
|
||||||
|
hierarchy_copy(self, in, type->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type->copy) {
|
||||||
|
type->copy(self, in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hierarchy_construct(Object* self, const ObjectType* type) {
|
||||||
|
if (type->base) {
|
||||||
|
hierarchy_construct(self, type->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type->constructor) {
|
||||||
|
type->constructor(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object* ndo_cast(const Object* in, const ObjectType* to_type) {
|
||||||
|
const ObjectType* typeiter = in->type;
|
||||||
|
while (typeiter) {
|
||||||
|
if (typeiter == to_type) {
|
||||||
|
return (Object*) in;
|
||||||
|
}
|
||||||
|
typeiter = typeiter->base;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
objects_api* objects_init() {
|
||||||
|
if (!NDO) {
|
||||||
|
NDO = new objects_api();
|
||||||
|
}
|
||||||
|
|
||||||
|
obj::BCgen::init();
|
||||||
|
|
||||||
|
return NDO;
|
||||||
|
}
|
||||||
|
|
||||||
|
void objects_finalize() {
|
||||||
|
|
||||||
|
if (NDO) {
|
||||||
|
delete NDO;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj::BCgen::deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
411
Objects/private/core/objectsave.cpp
Normal file
411
Objects/private/core/objectsave.cpp
Normal file
|
|
@ -0,0 +1,411 @@
|
||||||
|
|
||||||
|
|
||||||
|
#include "core/object.h"
|
||||||
|
|
||||||
|
#include "HeapAllocatorGlobal.hpp"
|
||||||
|
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
namespace obj {
|
||||||
|
|
||||||
|
ObjectMemHead* bottom = nullptr;
|
||||||
|
|
||||||
|
struct ObjectsFileHeader {
|
||||||
|
char name[10] = {0};
|
||||||
|
char version[10] = {0};
|
||||||
|
|
||||||
|
ObjectsFileHeader(bool default_val = true) {
|
||||||
|
if (default_val) {
|
||||||
|
tp::memCopy(&name, "objects", tp::String::Logic::calcLength("objects") + 1);
|
||||||
|
tp::memCopy(&version, "0", tp::String::Logic::calcLength("0") + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Object* ObjectMemAllocate(const ObjectType* type) {
|
||||||
|
ObjectMemHead* memh = (ObjectMemHead*) tp::HeapAllocGlobal::allocate(type->size + sizeof(ObjectMemHead));
|
||||||
|
if (!memh) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memh->down = NULL;
|
||||||
|
memh->flags = NULL;
|
||||||
|
|
||||||
|
#ifdef OBJECT_REF_COUNT
|
||||||
|
memh->refc = (tp::alni) 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (bottom) {
|
||||||
|
bottom->down = memh;
|
||||||
|
}
|
||||||
|
memh->up = bottom;
|
||||||
|
bottom = memh;
|
||||||
|
|
||||||
|
NDO_FROM_MEMH(memh)->type = type;
|
||||||
|
return NDO_FROM_MEMH(memh);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectMemDeallocate(Object* in) {
|
||||||
|
ObjectMemHead* memh = ((ObjectMemHead*) in) - 1;
|
||||||
|
|
||||||
|
if (memh->up) {
|
||||||
|
memh->up->down = memh->down;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memh->down) {
|
||||||
|
memh->down->up = memh->up;
|
||||||
|
} else {
|
||||||
|
bottom = memh->up;
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::HeapAllocGlobal::deallocate(memh);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ObjectFileHead {
|
||||||
|
Object* load_head_adress = 0;
|
||||||
|
tp::halni refc = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
tp::int1* loaded_file = nullptr;
|
||||||
|
|
||||||
|
|
||||||
|
void objects_api::clear_object_flags() {
|
||||||
|
// clear all object flags
|
||||||
|
for (ObjectMemHead* iter = bottom; iter; iter = iter->up) {
|
||||||
|
iter->flags = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::alni& getObjectFlags(Object* in) {
|
||||||
|
return NDO_MEMH_FROM_NDO(in)->flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::alni objsize_ram_util(Object* self, const ObjectType* type) {
|
||||||
|
tp::alni out = 0;
|
||||||
|
|
||||||
|
if (type->allocated_size) {
|
||||||
|
out += type->allocated_size(self);
|
||||||
|
} else {
|
||||||
|
out += type->size - sizeof(ObjectType*);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type->base) {
|
||||||
|
out += objsize_ram_util(self, type->base);
|
||||||
|
} else {
|
||||||
|
out += sizeof(ObjectType*);
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::alni objects_api::objsize_ram(Object* self) {
|
||||||
|
return objsize_ram_util(self, self->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::alni objects_api::objsize_ram_recursive_util(Object* self, const ObjectType* type, bool different_object) {
|
||||||
|
tp::alni out = 0;
|
||||||
|
|
||||||
|
if (different_object) {
|
||||||
|
if (getObjectFlags(self) == 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
getObjectFlags(self) = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type->allocated_size_recursive) {
|
||||||
|
out += type->allocated_size_recursive(self);
|
||||||
|
} else {
|
||||||
|
if (type->allocated_size) {
|
||||||
|
out += type->allocated_size(self);
|
||||||
|
} else {
|
||||||
|
out += type->size - sizeof(ObjectType*);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type->base) {
|
||||||
|
out += objsize_ram_recursive_util(self, type->base, false);
|
||||||
|
} else {
|
||||||
|
out += sizeof(ObjectType*);
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::alni objects_api::objsize_ram_recursive(Object* self) {
|
||||||
|
clear_object_flags();
|
||||||
|
return objsize_ram_recursive_util(self, self->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::alni objsize_file_util(Object* self, const ObjectType* type) {
|
||||||
|
tp::alni out = 0;
|
||||||
|
|
||||||
|
if (type->save_size) {
|
||||||
|
out += type->save_size(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type->base) {
|
||||||
|
out += objsize_file_util(self, type->base);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::alni objects_api::objsize_file(Object* self) {
|
||||||
|
return objsize_file_util(self, self->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::alni objsize_file_recursive_util(Object* self, const ObjectType* type) {
|
||||||
|
tp::alni out = 0;
|
||||||
|
|
||||||
|
getObjectFlags(self) = 1;
|
||||||
|
|
||||||
|
if (type->save_size) {
|
||||||
|
out += type->save_size(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type->childs_retrival) {
|
||||||
|
tp::Buffer<Object*> childs = type->childs_retrival(self);
|
||||||
|
for (auto child : childs) {
|
||||||
|
if (getObjectFlags(child.data()) != 1) {
|
||||||
|
out += objsize_file_recursive_util(child.data(), child.data()->type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type->base) {
|
||||||
|
out += objsize_file_recursive_util(self, type->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::alni objects_api::objsize_file_recursive(Object* self) {
|
||||||
|
clear_object_flags();
|
||||||
|
return objsize_file_recursive_util(self, self->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void object_recursive_save(Archiver& ndf, Object* self, const ObjectType* type) {
|
||||||
|
if (type->base) {
|
||||||
|
object_recursive_save(ndf, self, type->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
// automatically offsets for parent type to write
|
||||||
|
if (type->save) {
|
||||||
|
type->save(self, ndf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::alni objects_api::save(Archiver& ndf, Object* in) {
|
||||||
|
// if already saved return file_adress
|
||||||
|
if (NDO_MEMH_FROM_NDO(in)->flags != -1) {
|
||||||
|
return NDO_MEMH_FROM_NDO(in)->flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
// save write adress for parent save function call
|
||||||
|
tp::alni tmp_adress = ndf.adress;
|
||||||
|
|
||||||
|
// save requested object to first available adress
|
||||||
|
tp::alni save_adress = ndf.avl_adress;
|
||||||
|
|
||||||
|
// save file_adress in memhead
|
||||||
|
NDO_MEMH_FROM_NDO(in)->flags = save_adress;
|
||||||
|
|
||||||
|
// update write adress
|
||||||
|
ndf.adress = save_adress;
|
||||||
|
|
||||||
|
// save file object header
|
||||||
|
ObjectFileHead ofh = { 0, getrefc(in) };
|
||||||
|
ndf.write(&ofh);
|
||||||
|
tp::String(in->type->name).save(&ndf);
|
||||||
|
|
||||||
|
// allocate for object file header
|
||||||
|
ndf.avl_adress += sizeof(ObjectFileHead) + tp::String::Logic::calcLength(in->type->name) + 1;
|
||||||
|
|
||||||
|
// calc max size needed for saving all hierarchy of types
|
||||||
|
tp::alni file_alloc_size = objsize_file_util(in, in->type);
|
||||||
|
|
||||||
|
// offes first available adress
|
||||||
|
ndf.avl_adress += file_alloc_size;
|
||||||
|
|
||||||
|
object_recursive_save(ndf, in, in->type);
|
||||||
|
|
||||||
|
// restore adress for parent save function
|
||||||
|
ndf.adress = tmp_adress;
|
||||||
|
|
||||||
|
// return addres of saved object in file space
|
||||||
|
return save_adress;
|
||||||
|
}
|
||||||
|
|
||||||
|
void object_recursive_load(Archiver& ndf, Object* out, const ObjectType* type) {
|
||||||
|
if (type->base) {
|
||||||
|
object_recursive_load(ndf, out, type->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
// automatically offsets for parent type to read
|
||||||
|
if (type->load) {
|
||||||
|
type->load(ndf, out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object* objects_api::load(Archiver& ndf, tp::alni file_adress) {
|
||||||
|
// check if already saved
|
||||||
|
if (((ObjectFileHead*) (loaded_file + file_adress))->load_head_adress) {
|
||||||
|
return ((ObjectFileHead*) (loaded_file + file_adress))->load_head_adress;
|
||||||
|
}
|
||||||
|
|
||||||
|
// save read adress
|
||||||
|
tp::alni parent_file_adress = ndf.adress;
|
||||||
|
|
||||||
|
// set read adress
|
||||||
|
ndf.adress = file_adress;
|
||||||
|
|
||||||
|
ObjectFileHead ofh;
|
||||||
|
ndf.read<ObjectFileHead>(&ofh);
|
||||||
|
tp::String type_name;
|
||||||
|
type_name.load(&ndf);
|
||||||
|
|
||||||
|
const ObjectType* object_type = NDO->types.get(type_name);
|
||||||
|
Object* out = ObjectMemAllocate(object_type);
|
||||||
|
|
||||||
|
if (!out) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
setrefc(out, ofh.refc);
|
||||||
|
|
||||||
|
// save heap adress in "loaded_file"
|
||||||
|
((ObjectFileHead*) (loaded_file + file_adress))->load_head_adress = out;
|
||||||
|
|
||||||
|
// loads recursivelly
|
||||||
|
object_recursive_load(ndf, out, object_type);
|
||||||
|
|
||||||
|
// restore read adress for parent call to continue
|
||||||
|
ndf.adress = parent_file_adress;
|
||||||
|
|
||||||
|
// return heap memory adress
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool objects_api::save(Object* in, tp::String path, bool compressed) {
|
||||||
|
Archiver ndf(path.read(), Archiver::SAVE);
|
||||||
|
|
||||||
|
if (!ndf.opened) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_object_flags();
|
||||||
|
|
||||||
|
// save vesion info
|
||||||
|
ObjectsFileHeader header;
|
||||||
|
ndf.write(&header);
|
||||||
|
|
||||||
|
ndf.avl_adress = ndf.adress;
|
||||||
|
|
||||||
|
// pre allocate
|
||||||
|
for (tp::alni i = 0; i < SAVE_LOAD_MAX_CALLBACK_SLOTS; i++) {
|
||||||
|
if (sl_callbacks[i]) {
|
||||||
|
DEBUG_ASSERT(sl_callbacks[i]->size);
|
||||||
|
ndf.avl_adress += sl_callbacks[i]->size(sl_callbacks[i]->self, ndf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// presave
|
||||||
|
for (tp::alni i = 0; i < SAVE_LOAD_MAX_CALLBACK_SLOTS; i++) {
|
||||||
|
if (sl_callbacks[i] && sl_callbacks[i]->pre_save) {
|
||||||
|
sl_callbacks[i]->pre_save(sl_callbacks[i]->self, ndf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
save(ndf, in);
|
||||||
|
|
||||||
|
// postsave
|
||||||
|
for (tp::alni i = 0; i < SAVE_LOAD_MAX_CALLBACK_SLOTS; i++) {
|
||||||
|
if (sl_callbacks[i] && sl_callbacks[i]->post_save) {
|
||||||
|
sl_callbacks[i]->post_save(sl_callbacks[i]->self, ndf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ndf.disconnect();
|
||||||
|
|
||||||
|
// TODO : add compression
|
||||||
|
/*
|
||||||
|
if (compressed) {
|
||||||
|
auto temp = path + ".bz2";
|
||||||
|
tp::compressF2F(path.read(), temp.cstr());
|
||||||
|
|
||||||
|
File::remove(path.read());
|
||||||
|
File::rename(temp.cstr(), path.read());
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object* objects_api::load(tp::String path) {
|
||||||
|
/*
|
||||||
|
auto temp_file_name = path + ".unz";
|
||||||
|
bool unz_res = tp::decompressF2F(path.cstr(), temp_file_name.cstr());
|
||||||
|
|
||||||
|
if (!unz_res) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
File ndf(temp_file_name.cstr(), tp::osfile_openflags::LOAD);
|
||||||
|
*/
|
||||||
|
|
||||||
|
Archiver ndf(path.read(), Archiver::LOAD);
|
||||||
|
|
||||||
|
if (!ndf.opened) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for compability
|
||||||
|
ObjectsFileHeader current_header;
|
||||||
|
ObjectsFileHeader loaded_header(false);
|
||||||
|
ndf.read(&loaded_header);
|
||||||
|
if (!tp::memEqual(¤t_header, &loaded_header, sizeof(ObjectsFileHeader))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ndf.adress = 0;
|
||||||
|
loaded_file = (tp::int1*) malloc(ndf.size());
|
||||||
|
ndf.read_bytes(loaded_file, ndf.size());
|
||||||
|
ndf.adress = sizeof(ObjectsFileHeader);
|
||||||
|
|
||||||
|
// preload
|
||||||
|
for (tp::alni i = 0; i < SAVE_LOAD_MAX_CALLBACK_SLOTS; i++) {
|
||||||
|
if (sl_callbacks[i] && sl_callbacks[i]->pre_load) {
|
||||||
|
sl_callbacks[i]->pre_load(sl_callbacks[i]->self, ndf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object* out = load(ndf, ndf.adress);
|
||||||
|
|
||||||
|
// post
|
||||||
|
for (tp::alni i = 0; i < SAVE_LOAD_MAX_CALLBACK_SLOTS; i++) {
|
||||||
|
if (sl_callbacks[i] && sl_callbacks[i]->post_save) {
|
||||||
|
sl_callbacks[i]->post_load(sl_callbacks[i]->self, ndf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(loaded_file);
|
||||||
|
|
||||||
|
/*
|
||||||
|
ndf.close();
|
||||||
|
|
||||||
|
if (unz_res == NULL) {
|
||||||
|
File::remove(temp_file_name.cstr());
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
setrefc(out, 0);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void objects_api::add_sl_callbacks(save_load_callbacks* in) {
|
||||||
|
sl_callbacks[sl_callbacks_load_idx] = in;
|
||||||
|
sl_callbacks_load_idx++;
|
||||||
|
}
|
||||||
|
};
|
||||||
265
Objects/private/core/scriptsection.cpp
Normal file
265
Objects/private/core/scriptsection.cpp
Normal file
|
|
@ -0,0 +1,265 @@
|
||||||
|
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
#include "HeapAllocatorGlobal.hpp"
|
||||||
|
|
||||||
|
#include "core/scriptsection.h"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
|
||||||
|
ScriptSection* gScriptSection = NULL;
|
||||||
|
|
||||||
|
struct script_data_head {
|
||||||
|
tp::alni refc = 0;
|
||||||
|
tp::alni store_adress = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void set_script_head_store_adress(Script* in, tp::alni address) {
|
||||||
|
((script_data_head*)in - 1)->store_adress = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::alni get_script_head_store_adress(Script* in) {
|
||||||
|
return ((script_data_head*)in - 1)->store_adress;
|
||||||
|
}
|
||||||
|
|
||||||
|
Script* ScriptSection::createScript() {
|
||||||
|
auto sdhead = (script_data_head*)tp::HeapAllocGlobal::allocate(sizeof(script_data_head) + sizeof(Script));
|
||||||
|
auto out = (Script*)(sdhead + 1);
|
||||||
|
|
||||||
|
if (!sdhead) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sdhead->refc = 1;
|
||||||
|
sdhead->store_adress = -1;
|
||||||
|
|
||||||
|
mScripts.pushBack(out);
|
||||||
|
|
||||||
|
new (out) Script();
|
||||||
|
out->mReadable = obj::StringObject::create("");
|
||||||
|
obj::NDO->refinc(out->mReadable);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptSection::delete_script(Script* script) {
|
||||||
|
script->~Script();
|
||||||
|
obj::NDO->destroy(script->mReadable);
|
||||||
|
|
||||||
|
tp::HeapAllocGlobal::deallocate((((script_data_head*)script) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptSection::reference_script(Script* script) {
|
||||||
|
(((script_data_head*)script) - 1)->refc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptSection::abandonScript(Script* script) {
|
||||||
|
if ((((script_data_head*)script) - 1)->refc > 1) {
|
||||||
|
(((script_data_head*)script) - 1)->refc--;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// ISSUE : on delete list structure is outdated
|
||||||
|
// FIXME : use pool alloc with ref count
|
||||||
|
// forwarding to global destruction
|
||||||
|
//delete_script(script);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptSection::changeScript(Script** current_script, Script** new_script) {
|
||||||
|
abandonScript(*current_script);
|
||||||
|
reference_script(*new_script);
|
||||||
|
|
||||||
|
*current_script = *new_script;
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::alni ScriptSection::get_script_file_adress(Script* in) {
|
||||||
|
return get_script_head_store_adress(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::alni ScriptSection::save_script_table_to_file_size(ScriptSection* self, Archiver& file) {
|
||||||
|
tp::alni size = 0;
|
||||||
|
size += 5; // header
|
||||||
|
size += sizeof(tp::alni); // scripts length
|
||||||
|
|
||||||
|
for (auto iter : self->mScripts) {
|
||||||
|
|
||||||
|
set_script_head_store_adress(iter.data(), file.adress + size);
|
||||||
|
|
||||||
|
size += sizeof(tp::alni); // scripts string obj ref
|
||||||
|
size += sizeof(tp::alni); // constants length
|
||||||
|
|
||||||
|
for (auto const_obj : iter->mBytecode.mConstants) {
|
||||||
|
size += sizeof(tp::alni); // constant object addres
|
||||||
|
}
|
||||||
|
|
||||||
|
// instructions
|
||||||
|
size += iter->mBytecode.mInstructions.saveSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
size += sizeof(tp::alni); // objects mem offset
|
||||||
|
size += 5; // header
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptSection::save_script_table_to_file(ScriptSection* self, Archiver& file) {
|
||||||
|
// header
|
||||||
|
file.write_bytes("/scr/", 5);
|
||||||
|
|
||||||
|
// scripts length
|
||||||
|
tp::alni scripts_count = self->mScripts.length();
|
||||||
|
file.write<tp::alni>(&scripts_count);
|
||||||
|
|
||||||
|
for (auto iter : self->mScripts) {
|
||||||
|
|
||||||
|
// scripts string obj ref
|
||||||
|
auto obj_addres = obj::NDO->save(file, iter->mReadable);
|
||||||
|
file.write(&obj_addres);
|
||||||
|
|
||||||
|
// constants length
|
||||||
|
tp::alni consts_count = iter->mBytecode.mConstants.size();
|
||||||
|
file.write<tp::alni>(&consts_count);
|
||||||
|
|
||||||
|
for (auto const_obj : iter->mBytecode.mConstants) {
|
||||||
|
// constant object addres
|
||||||
|
auto obj_addres = obj::NDO->save(file, const_obj.data());
|
||||||
|
file.write(&obj_addres);
|
||||||
|
}
|
||||||
|
|
||||||
|
// mInstructions
|
||||||
|
iter->mBytecode.mInstructions.save(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
// header
|
||||||
|
file.write_bytes("/scr/", 5);
|
||||||
|
|
||||||
|
tp::alni objects_mem_offset = file.avl_adress;
|
||||||
|
file.write<tp::alni>(&objects_mem_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_constants(ScriptSection* self, Archiver& file, tp::alni start_addr) {
|
||||||
|
auto addres = file.adress;
|
||||||
|
|
||||||
|
file.adress = start_addr;
|
||||||
|
file.adress += 5; // header
|
||||||
|
|
||||||
|
tp::alni scripts_count;
|
||||||
|
file.read<tp::alni>(&scripts_count);
|
||||||
|
|
||||||
|
for (tp::alni i = 0; i < scripts_count; i++) {
|
||||||
|
|
||||||
|
auto script = self->get_scritp_from_file_adress(file.adress);
|
||||||
|
|
||||||
|
// script text
|
||||||
|
tp::alni str_addr;
|
||||||
|
file.read<tp::alni>(&str_addr);
|
||||||
|
script->mReadable = NDO_CAST(obj::StringObject, obj::NDO->load(file, str_addr));
|
||||||
|
|
||||||
|
file.adress += sizeof(tp::alni); // constants length
|
||||||
|
|
||||||
|
for (auto const_obj : script->mBytecode.mConstants) {
|
||||||
|
tp::alni consts_addr;
|
||||||
|
file.read<tp::alni>(&consts_addr);
|
||||||
|
const_obj.data() = obj::NDO->load(file, consts_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// instructions
|
||||||
|
file.adress += script->mBytecode.mInstructions.saveSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
file.adress = addres;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptSection::load_script_table_from_file(ScriptSection* self, Archiver& file) {
|
||||||
|
for (auto iter : self->mScripts) {
|
||||||
|
set_script_head_store_adress(iter.data(), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto section_start_addr = file.adress;
|
||||||
|
|
||||||
|
// header
|
||||||
|
file.adress += 5;
|
||||||
|
|
||||||
|
// scripts length
|
||||||
|
tp::alni scripts_count;
|
||||||
|
file.read<tp::alni>(&scripts_count);
|
||||||
|
|
||||||
|
for (tp::alni i = 0; i < scripts_count; i++) {
|
||||||
|
|
||||||
|
auto new_script = self->createScript();
|
||||||
|
set_script_head_store_adress(new_script, file.adress);
|
||||||
|
|
||||||
|
// scripts text
|
||||||
|
file.adress += sizeof(tp::alni);
|
||||||
|
|
||||||
|
// constants length
|
||||||
|
tp::alni consts_count;
|
||||||
|
file.read<tp::alni>(&consts_count);
|
||||||
|
|
||||||
|
new_script->mBytecode.mConstants.reserve(consts_count);
|
||||||
|
|
||||||
|
for (tp::alni j = 0; j < consts_count; j++) {
|
||||||
|
// constant object addres
|
||||||
|
tp::alni consts_addr;
|
||||||
|
file.read<tp::alni>(&consts_addr);
|
||||||
|
|
||||||
|
// skiping
|
||||||
|
//new_script->mBytecode.mConstants[j] = obj::NDO->load(file, consts_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// mInstructions
|
||||||
|
new_script->mBytecode.mInstructions.load(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
load_constants(self, file, section_start_addr);
|
||||||
|
|
||||||
|
// header
|
||||||
|
file.adress += 5;
|
||||||
|
|
||||||
|
tp::alni objects_mem_offset;
|
||||||
|
file.read<tp::alni>(&objects_mem_offset);
|
||||||
|
|
||||||
|
file.adress = objects_mem_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
Script* ScriptSection::get_scritp_from_file_adress(tp::alni file_adress) {
|
||||||
|
for (auto iter : mScripts) {
|
||||||
|
if (get_script_head_store_adress(iter.data()) == file_adress) {
|
||||||
|
return iter.data();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptSection::~ScriptSection() {
|
||||||
|
for (auto iter : mScripts) {
|
||||||
|
delete_script(iter.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obj::save_load_callbacks ScriptSection::slcb_script_section = {
|
||||||
|
.self = gScriptSection,
|
||||||
|
.pre_save = (obj::pre_save_callback*)ScriptSection::save_script_table_to_file,
|
||||||
|
.size = (obj::slcb_size_callback*)ScriptSection::save_script_table_to_file_size,
|
||||||
|
.pre_load = (obj::pre_load_callback*)ScriptSection::load_script_table_from_file,
|
||||||
|
.post_save = NULL,
|
||||||
|
.post_load = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void ScriptSection::initialize() {
|
||||||
|
ASSERT(!gScriptSection);
|
||||||
|
gScriptSection = new ScriptSection();
|
||||||
|
|
||||||
|
ASSERT(obj::NDO && "Forgot to initialize objects?");
|
||||||
|
|
||||||
|
slcb_script_section.self = gScriptSection;
|
||||||
|
obj::NDO->add_sl_callbacks(&slcb_script_section);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptSection::uninitialize() {
|
||||||
|
ASSERT(gScriptSection);
|
||||||
|
delete gScriptSection;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptSection* ScriptSection::globalHandle() {
|
||||||
|
return gScriptSection;
|
||||||
|
}
|
||||||
|
|
||||||
81
Objects/private/core/typegroups.cpp
Normal file
81
Objects/private/core/typegroups.cpp
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
|
||||||
|
#include "core/typegroups.h"
|
||||||
|
|
||||||
|
#include "core/object.h"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
|
||||||
|
obj::TypeGroups::TypeGroups() : is_group(true) {
|
||||||
|
new (&childs) Dict();
|
||||||
|
}
|
||||||
|
|
||||||
|
obj::TypeGroups::TypeGroups(bool is_group) : is_group(is_group) {
|
||||||
|
if (is_group) {
|
||||||
|
new (&childs) Dict();
|
||||||
|
} else {
|
||||||
|
type = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool obj::TypeGroups::isGroup() { return is_group; }
|
||||||
|
|
||||||
|
obj::TypeGroups::Dict* obj::TypeGroups::getChilds() {
|
||||||
|
DEBUG_ASSERT(is_group);
|
||||||
|
return &childs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void obj::TypeGroups::setType(ObjectType* type) {
|
||||||
|
DEBUG_ASSERT(!is_group);
|
||||||
|
this->type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void obj::TypeGroups::addType(ObjectType* type, tp::init_list<const char*> path, tp::alni cur_dir_idx) {
|
||||||
|
DEBUG_ASSERT(is_group);
|
||||||
|
|
||||||
|
tp::alni dir_len = (tp::alni) path.size();
|
||||||
|
|
||||||
|
if (dir_len == cur_dir_idx) {
|
||||||
|
TypeGroups* type_ref = new TypeGroups(false);
|
||||||
|
type_ref->setType(type);
|
||||||
|
childs.put(type->name, type_ref);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeGroups* group = NULL;
|
||||||
|
tp::alni index = 0;
|
||||||
|
|
||||||
|
for (auto dir : path) {
|
||||||
|
if (index != cur_dir_idx) {
|
||||||
|
index++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto child_idx = childs.presents(dir);
|
||||||
|
if (child_idx) {
|
||||||
|
group = childs.getSlotVal(child_idx);
|
||||||
|
} else {
|
||||||
|
group = new TypeGroups(true);
|
||||||
|
childs.put(dir, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
group->addType(type, path, cur_dir_idx + 1);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const obj::ObjectType* obj::TypeGroups::getType() {
|
||||||
|
DEBUG_ASSERT(!is_group);
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj::TypeGroups::~TypeGroups() {
|
||||||
|
if (is_group) {
|
||||||
|
for (auto& child : childs) {
|
||||||
|
delete child->val;
|
||||||
|
}
|
||||||
|
childs.~Map();
|
||||||
|
}
|
||||||
|
}
|
||||||
138
Objects/private/core/typemethods.cpp
Normal file
138
Objects/private/core/typemethods.cpp
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
|
||||||
|
#include "core/typemethods.h"
|
||||||
|
|
||||||
|
#include "primitives/nullobject.h"
|
||||||
|
#include "primitives/typeobject.h"
|
||||||
|
#include "primitives/floatobject.h"
|
||||||
|
|
||||||
|
#include "interpreter/interpreter.h"
|
||||||
|
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
|
||||||
|
TypeMethod obj::gDefaultTypeMethods[] = {
|
||||||
|
{
|
||||||
|
.nameid = "type",
|
||||||
|
.descr = "retrieves typeobject",
|
||||||
|
.exec = [](const TypeMethod* tm) {
|
||||||
|
tm->ret.obj = TypeObject::create(tm->self->type);
|
||||||
|
},
|
||||||
|
.ret = { "typeobject", NULL },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.nameid = "to_str",
|
||||||
|
.descr = "converts to string",
|
||||||
|
.exec = [](const TypeMethod* tm) {
|
||||||
|
if (tm->self->type->convesions && tm->self->type->convesions->to_string) {
|
||||||
|
tm->ret.obj = StringObject::create(NDO->toString(tm->self));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.ret = { "string object", NULL },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.nameid = "to_float",
|
||||||
|
.descr = "converts to float",
|
||||||
|
.exec = [](const TypeMethod* tm) {
|
||||||
|
if (tm->self->type->convesions && tm->self->type->convesions->to_float) {
|
||||||
|
tm->ret.obj = FloatObject::create(NDO->toFloat(tm->self));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.ret = { "string object", NULL },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
tp::int2 TypeMethods::presents(tp::String id) const {
|
||||||
|
for (tp::int2 idx = 0; idx < mNMethods; idx++) {
|
||||||
|
if (id == methods[idx]->nameid) {
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::int2 idx = 0;
|
||||||
|
for (auto& tm : gDefaultTypeMethods) {
|
||||||
|
if (id == tm.nameid) {
|
||||||
|
return { tp::int2(idx + MAX_TYPE_METHODS) };
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeMethods::LookupKey TypeMethods::presents(const ObjectType* type, tp::string id) {
|
||||||
|
|
||||||
|
tp::int2 depth = 0;
|
||||||
|
tp::int2 idx = 0;
|
||||||
|
|
||||||
|
for (auto iter_type = type; iter_type; iter_type = iter_type->base) {
|
||||||
|
idx = iter_type->type_methods.presents(id);
|
||||||
|
if (idx != -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
depth++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { idx, depth};
|
||||||
|
}
|
||||||
|
|
||||||
|
const TypeMethod* TypeMethods::getMethod(tp::int2 key) const {
|
||||||
|
if (key < MAX_TYPE_METHODS) {
|
||||||
|
return methods[key];
|
||||||
|
}
|
||||||
|
return &gDefaultTypeMethods[key - MAX_TYPE_METHODS];
|
||||||
|
}
|
||||||
|
|
||||||
|
const TypeMethod* TypeMethods::getMethod(const ObjectType* type, LookupKey key) {
|
||||||
|
auto type_iter = type;
|
||||||
|
for (auto idx = 0; idx < key.type_depth; idx++) {
|
||||||
|
type_iter = type_iter->base;
|
||||||
|
}
|
||||||
|
return type_iter->type_methods.getMethod(key.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TypeMethods::init() {
|
||||||
|
while (methods[mNMethods]) {
|
||||||
|
mNMethods++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (tp::int1 i = 0; i < mNMethods; i++) {
|
||||||
|
methods[i]->init();
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize and use finate state automata to lookup methods
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::halni TypeMethods::nMethods() const {
|
||||||
|
return mNMethods;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TypeMethod::operator()(Interpreter* interp) const{
|
||||||
|
for (auto i = 1; i <= mNargs; i++) {
|
||||||
|
args[mNargs - i].obj = interp->mOperandsStack.getOperand();
|
||||||
|
//NDO->refinc(args[i].obj);
|
||||||
|
ASSERT(args[mNargs - i].obj && "expected an argument");
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(!interp->mOperandsStack.getOperand() && "args remained");
|
||||||
|
interp->mOperandsStack.getOperand();
|
||||||
|
|
||||||
|
self = interp->mLastParent;
|
||||||
|
|
||||||
|
exec(this);
|
||||||
|
|
||||||
|
if (ret.obj) {
|
||||||
|
interp->mOperandsStack.push(ret.obj);
|
||||||
|
interp->mScopeStack.addTempReturn(ret.obj);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
interp->mOperandsStack.push(NDO_NULL_REF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TypeMethod::init() {
|
||||||
|
while (args[mNargs].descr) {
|
||||||
|
mNargs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
40
Objects/private/interpreter/callstack.cpp
Normal file
40
Objects/private/interpreter/callstack.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
|
||||||
|
#include "interpreter/callstack.h"
|
||||||
|
|
||||||
|
#include "interpreter/bytecode.h"
|
||||||
|
#include "primitives/methodobject.h"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
|
||||||
|
void CallStack::enter(const CallStack::CallFrame& frame) {
|
||||||
|
if (mStack.size()) {
|
||||||
|
auto& last_frame = mStack.last();
|
||||||
|
last_frame.mIp = last_frame.mMethod->mScript->mBytecode.mInstructionIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.mMethod->mScript->mBytecode.mArgumentsLoaded = 0;
|
||||||
|
frame.mMethod->mScript->mBytecode.mInstructionIdx = 0;
|
||||||
|
obj::NDO->refinc(frame.mMethod);
|
||||||
|
mStack.append(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CallStack::leave() {
|
||||||
|
auto frame = mStack.last();
|
||||||
|
obj::NDO->destroy(frame.mMethod);
|
||||||
|
mStack.pop();
|
||||||
|
|
||||||
|
if (mStack.size()) {
|
||||||
|
auto& last_frame = mStack.last();
|
||||||
|
last_frame.mMethod->mScript->mBytecode.mInstructionIdx = last_frame.mIp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteCode* CallStack::getBytecode() {
|
||||||
|
return &mStack.last().mMethod->mScript->mBytecode;
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::halni CallStack::len() const {
|
||||||
|
return mStack.size();
|
||||||
|
}
|
||||||
573
Objects/private/interpreter/interpreter.cpp
Normal file
573
Objects/private/interpreter/interpreter.cpp
Normal file
|
|
@ -0,0 +1,573 @@
|
||||||
|
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
|
||||||
|
#include "interpreter/interpreter.h"
|
||||||
|
|
||||||
|
#include "primitives/primitives.h"
|
||||||
|
|
||||||
|
#include "Logging.hpp"
|
||||||
|
|
||||||
|
#include "Timing.hpp"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
|
||||||
|
inline tp::uint1 read_byte(ByteCode* bytecode) {
|
||||||
|
auto out = (tp::uint1)bytecode->mInstructions[bytecode->mInstructionIdx];
|
||||||
|
bytecode->mInstructionIdx++;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// exeption for opcodes
|
||||||
|
// reads 2 bytes from instructions in order to load constant onto operands stack
|
||||||
|
tp::uint2 loadConstDataIdx(ByteCode* bytecode) {
|
||||||
|
tp::uint2 out = 0;
|
||||||
|
out |= ((tp::uint2) read_byte(bytecode));
|
||||||
|
out |= ((tp::uint2) read_byte(bytecode) << 8);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// exeption for opcodes
|
||||||
|
// reads 2 bytes from instructions in order to load constant onto operands stack
|
||||||
|
void skip_param(ByteCode* bytecode) {
|
||||||
|
bytecode->mInstructionIdx += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::uint2 param(ByteCode* bytecode) {
|
||||||
|
return loadConstDataIdx(bytecode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interpreter::exec(obj::MethodObject* method, obj::ClassObject* self, obj::DictObject* globals, tp::init_list<GlobalDef> globals2) {
|
||||||
|
if (!method->mScript->mBytecode.mInstructions.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mCallStack.enter({ NULL, method, 0 });
|
||||||
|
mCallStack.mStack.last().mSelf = self;
|
||||||
|
|
||||||
|
stepBytecodeIn();
|
||||||
|
|
||||||
|
if (globals) {
|
||||||
|
for (auto glb : globals->getItems()) {
|
||||||
|
mScopeStack.addLocal(glb->val, glb->key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto global_def : globals2) {
|
||||||
|
mScopeStack.addLocal(global_def.obj, global_def.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Interpreter::finished() {
|
||||||
|
return !mCallStack.len();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interpreter::stepBytecode() {
|
||||||
|
tp::halni call_depth = mCallStack.len();
|
||||||
|
do {
|
||||||
|
stepBytecodeIn();
|
||||||
|
if (finished()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} while (call_depth != mCallStack.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interpreter::stepBytecodeOut() {
|
||||||
|
if (finished()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::halni call_depth = mCallStack.len();
|
||||||
|
if (!call_depth) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
stepBytecodeIn();
|
||||||
|
if (finished()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} while (call_depth - 1 != mCallStack.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interpreter::stepBytecodeIn() {
|
||||||
|
using namespace obj;
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
DEBUG_BREAK(finished());
|
||||||
|
|
||||||
|
auto bytecode = mCallStack.getBytecode();
|
||||||
|
|
||||||
|
if (bytecode->mInstructionIdx >= (tp::ualni) bytecode->mInstructions.size()) {
|
||||||
|
// just return
|
||||||
|
if (mScopeStack.mIdx) {
|
||||||
|
mScopeStack.leaveScope();
|
||||||
|
}
|
||||||
|
|
||||||
|
mCallStack.leave();
|
||||||
|
|
||||||
|
if (mCallStack.len()) {
|
||||||
|
mOperandsStack.push(NDO_NULL_REF);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto opcode = bytecode->mInstructions[bytecode->mInstructionIdx];
|
||||||
|
bytecode->mInstructionIdx++;
|
||||||
|
|
||||||
|
switch (opcode) {
|
||||||
|
|
||||||
|
case OpCode::NONE: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::HALT: {
|
||||||
|
while (true) {
|
||||||
|
tp::sleep(3);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::TERMINATE: {
|
||||||
|
//tp::terminate(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::IGNORE: {
|
||||||
|
NDO->destroy(mOperandsStack.getOperand());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::LOAD_CONST: {
|
||||||
|
auto idx = loadConstDataIdx(bytecode);
|
||||||
|
auto const_obj = bytecode->mConstants[idx];
|
||||||
|
mOperandsStack.push(const_obj);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::LOAD_LOCAL: {
|
||||||
|
auto idx = loadConstDataIdx(bytecode);
|
||||||
|
auto const_obj = bytecode->mConstants[idx];
|
||||||
|
NDO_CASTV(StringObject, const_obj, local_id);
|
||||||
|
ASSERT(local_id && "Invalid Object Type");
|
||||||
|
auto local = mScopeStack.getLocal(local_id->val);
|
||||||
|
mOperandsStack.push(local);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::SCOPE_IN: {
|
||||||
|
mScopeStack.enterScope(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::JUMP: {
|
||||||
|
bytecode->mInstructionIdx += param(bytecode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::JUMP_IF: {
|
||||||
|
auto cond = mOperandsStack.getOperand();
|
||||||
|
if (NDO->toBool(cond)) {
|
||||||
|
bytecode->mInstructionIdx += param(bytecode);
|
||||||
|
} else {
|
||||||
|
skip_param(bytecode);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::JUMP_IF_NOT: {
|
||||||
|
auto cond = mOperandsStack.getOperand();
|
||||||
|
if (!NDO->toBool(cond)) {
|
||||||
|
bytecode->mInstructionIdx += param(bytecode);
|
||||||
|
} else {
|
||||||
|
skip_param(bytecode);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::JUMP_R: {
|
||||||
|
bytecode->mInstructionIdx -= param(bytecode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::JUMP_IF_R: {
|
||||||
|
auto cond = mOperandsStack.getOperand();
|
||||||
|
if (NDO->toBool(cond)) {
|
||||||
|
bytecode->mInstructionIdx -= param(bytecode);
|
||||||
|
} else {
|
||||||
|
skip_param(bytecode);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::JUMP_IF_NOT_R: {
|
||||||
|
auto cond = mOperandsStack.getOperand();
|
||||||
|
if (!NDO->toBool(cond)) {
|
||||||
|
bytecode->mInstructionIdx -= param(bytecode);
|
||||||
|
} else {
|
||||||
|
skip_param(bytecode);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::SCOPE_OUT: {
|
||||||
|
mScopeStack.leaveScope();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::PRINT: {
|
||||||
|
auto obj = mOperandsStack.getOperand();
|
||||||
|
if (obj->type->convesions && obj->type->convesions->to_string) {
|
||||||
|
auto str = NDO->toString(obj);
|
||||||
|
gLogger->write(str, true);
|
||||||
|
} else {
|
||||||
|
gLogger->write(String(obj->type->name), true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::OBJ_CREATE_LOCAL: {
|
||||||
|
auto type = mOperandsStack.getOperand<StringObject>();
|
||||||
|
auto id = mOperandsStack.getOperand<StringObject>();
|
||||||
|
mScopeStack.addLocal(NDO->create(type->val), id->val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::DEF_LOCAL: {
|
||||||
|
auto id = mOperandsStack.getOperand<StringObject>();
|
||||||
|
auto obj = mOperandsStack.getOperand();
|
||||||
|
mScopeStack.addLocal(obj, id->val);
|
||||||
|
NDO->refinc(obj);
|
||||||
|
//mScopeStack.popTemp();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::OBJ_CREATE: {
|
||||||
|
auto type = mOperandsStack.getOperand<StringObject>();
|
||||||
|
Object* new_obj = NULL;
|
||||||
|
|
||||||
|
// basic types
|
||||||
|
auto idx = NDO->types.presents(type->val);
|
||||||
|
if (idx) {
|
||||||
|
auto new_obj = NDO->create(type->val);
|
||||||
|
|
||||||
|
mOperandsStack.push(new_obj);
|
||||||
|
mScopeStack.addTemp(new_obj);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// class creation
|
||||||
|
auto local_class = mScopeStack.getLocal(type->val);
|
||||||
|
NDO_CASTV(MethodObject, local_class, method);
|
||||||
|
ASSERT(method);
|
||||||
|
|
||||||
|
// class is a function - execute it as a constructor
|
||||||
|
|
||||||
|
// PUSH_ARGS protocol
|
||||||
|
tp::uint2 len = 0;
|
||||||
|
mOperandsStack.push((Object*)len);
|
||||||
|
mOperandsStack.push(NULL);
|
||||||
|
|
||||||
|
// CALL protocol
|
||||||
|
mScopeStack.enterScope(false);
|
||||||
|
mCallStack.enter({ NULL, method, 0 });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::CLASS_CONSTRUCT: {
|
||||||
|
auto class_obj = (ClassObject*)NDO->create("class");
|
||||||
|
|
||||||
|
for (auto local : mScopeStack.getCurrentScope()->mLocals) {
|
||||||
|
class_obj->addMember(local->val, local->key);
|
||||||
|
}
|
||||||
|
|
||||||
|
mOperandsStack.push(class_obj);
|
||||||
|
mScopeStack.addTempReturn(class_obj);
|
||||||
|
|
||||||
|
mScopeStack.leaveScope();
|
||||||
|
mCallStack.leave();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::RETURN: {
|
||||||
|
//mScopeStack.addTempReturn(NDO_NULL_REF);
|
||||||
|
mScopeStack.leaveScope();
|
||||||
|
mCallStack.leave();
|
||||||
|
if (mCallStack.len()) {
|
||||||
|
mOperandsStack.push(NDO_NULL_REF);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::PUSH_ARGS: {
|
||||||
|
|
||||||
|
// Layout of OperandsStack:
|
||||||
|
// ....
|
||||||
|
// +1) length : to chech number of args
|
||||||
|
// +2) NULL : stop saving args
|
||||||
|
// +3) object1
|
||||||
|
// +4) object2
|
||||||
|
// ...
|
||||||
|
|
||||||
|
tp::uint2 len = read_byte(bytecode);
|
||||||
|
mOperandsStack.push((Object*) len);
|
||||||
|
mOperandsStack.push(NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::SAVE_ARGS: {
|
||||||
|
tp::uint2 args_len = read_byte(bytecode);
|
||||||
|
auto argument = mOperandsStack.getOperand();
|
||||||
|
|
||||||
|
while (argument) {
|
||||||
|
NDO->refinc(argument);
|
||||||
|
|
||||||
|
auto argument_id = bytecode->mConstants[loadConstDataIdx(bytecode)];
|
||||||
|
NDO_CASTV(StringObject, argument_id, id);
|
||||||
|
DEBUG_ASSERT(id);
|
||||||
|
mScopeStack.addLocal(argument, id->val);
|
||||||
|
bytecode->mArgumentsLoaded++;
|
||||||
|
argument = mOperandsStack.getOperand();
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::uint2 saved_len = tp::uint2 (tp::ualni (mOperandsStack.getOperand()));
|
||||||
|
ASSERT(args_len == saved_len && "invalid number of arguments passefd");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::RETURN_OBJ: {
|
||||||
|
if (mCallStack.len() > 1) {
|
||||||
|
auto ret = mOperandsStack.getOperand();
|
||||||
|
mOperandsStack.push(ret);
|
||||||
|
mScopeStack.addTempReturn(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
mScopeStack.leaveScope();
|
||||||
|
mCallStack.leave();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::CALL: {
|
||||||
|
auto obj = mOperandsStack.getOperand();
|
||||||
|
|
||||||
|
if (!mIsTypeMethod) {
|
||||||
|
NDO_CASTV(MethodObject, obj, method);
|
||||||
|
|
||||||
|
mScopeStack.enterScope(false);
|
||||||
|
mCallStack.enter({ NULL, method, 0 });
|
||||||
|
|
||||||
|
// push self
|
||||||
|
mCallStack.mStack.last().mSelf = mLastParent;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*mTypeMethod)(this);
|
||||||
|
mIsTypeMethod = false;
|
||||||
|
mTypeMethod = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::OBJ_ADD: {
|
||||||
|
auto left = mOperandsStack.getOperand();
|
||||||
|
auto right = mOperandsStack.getOperand();
|
||||||
|
|
||||||
|
ASSERT(left->type == right->type && "addition of different types is not implemented");
|
||||||
|
ASSERT(left->type->ariphmetics && left->type->ariphmetics->add && "cannot add object of this type");
|
||||||
|
|
||||||
|
auto res = NDO->instatiate(left);
|
||||||
|
res->type->ariphmetics->add(res, right);
|
||||||
|
|
||||||
|
mScopeStack.addTemp(res);
|
||||||
|
mOperandsStack.push(res);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OpCode::OBJ_SUB: {
|
||||||
|
auto left = mOperandsStack.getOperand();
|
||||||
|
auto right = mOperandsStack.getOperand();
|
||||||
|
|
||||||
|
ASSERT(left->type == right->type && "addition of different types is not implemented");
|
||||||
|
ASSERT(left->type->ariphmetics && left->type->ariphmetics->add && "cannot add object of this type");
|
||||||
|
|
||||||
|
auto res = NDO->instatiate(left);
|
||||||
|
res->type->ariphmetics->sub(res, right);
|
||||||
|
|
||||||
|
mScopeStack.addTemp(res);
|
||||||
|
mOperandsStack.push(res);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OpCode::OBJ_MUL: {
|
||||||
|
auto left = mOperandsStack.getOperand();
|
||||||
|
auto right = mOperandsStack.getOperand();
|
||||||
|
|
||||||
|
ASSERT(left->type == right->type && "addition of different types is not implemented");
|
||||||
|
ASSERT(left->type->ariphmetics && left->type->ariphmetics->add && "cannot add object of this type");
|
||||||
|
|
||||||
|
auto res = NDO->instatiate(left);
|
||||||
|
res->type->ariphmetics->mul(res, right);
|
||||||
|
|
||||||
|
mScopeStack.addTemp(res);
|
||||||
|
mOperandsStack.push(res);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OpCode::OBJ_DIV: {
|
||||||
|
auto left = mOperandsStack.getOperand();
|
||||||
|
auto right = mOperandsStack.getOperand();
|
||||||
|
|
||||||
|
ASSERT(left->type == right->type && "addition of different types is not implemented");
|
||||||
|
ASSERT(left->type->ariphmetics && left->type->ariphmetics->add && "cannot add object of this type");
|
||||||
|
|
||||||
|
auto res = NDO->instatiate(left);
|
||||||
|
res->type->ariphmetics->div(res, right);
|
||||||
|
|
||||||
|
mScopeStack.addTemp(res);
|
||||||
|
mOperandsStack.push(res);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::OBJ_COPY: {
|
||||||
|
auto left = mOperandsStack.getOperand();
|
||||||
|
auto right = mOperandsStack.getOperand();
|
||||||
|
NDO->copy(left, right);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::CHILD: {
|
||||||
|
auto child_id = mOperandsStack.getOperand<StringObject>();
|
||||||
|
auto parent = mOperandsStack.getOperand();
|
||||||
|
bool is_method = read_byte(bytecode);
|
||||||
|
|
||||||
|
Object* child = NULL;
|
||||||
|
TypeMethods::LookupKey tm_key;
|
||||||
|
|
||||||
|
if (is_method) {
|
||||||
|
tm_key = TypeMethods::presents(parent->type, child_id->val);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tm_key) {
|
||||||
|
mTypeMethod = TypeMethods::getMethod(parent->type, tm_key);
|
||||||
|
mIsTypeMethod = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
NDO_CASTV(ClassObject, parent, class_obj);
|
||||||
|
ASSERT(class_obj && "not a class object");
|
||||||
|
auto idx = class_obj->members->presents(child_id->val);
|
||||||
|
ASSERT(idx && "No child with such id");
|
||||||
|
child = class_obj->members->getSlotVal(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
//mScopeStack.addTemp(obj);
|
||||||
|
mOperandsStack.push(child);
|
||||||
|
mLastParent = parent;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::SELF: {
|
||||||
|
//mScopeStack.addTemp(obj);
|
||||||
|
ASSERT(mCallStack.mStack.last().mSelf);
|
||||||
|
mOperandsStack.push(mCallStack.mStack.last().mSelf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::OBJ_LOAD: {
|
||||||
|
auto path = mOperandsStack.getOperand<StringObject>();
|
||||||
|
auto obj = NDO->load(path->val);
|
||||||
|
mScopeStack.addTemp(obj);
|
||||||
|
mOperandsStack.push(obj);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OpCode::OBJ_SAVE: {
|
||||||
|
auto path = mOperandsStack.getOperand<StringObject>();
|
||||||
|
auto target = mOperandsStack.getOperand();
|
||||||
|
NDO->save(target, path->val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::AND: {
|
||||||
|
auto left = NDO->toBool(mOperandsStack.getOperand());
|
||||||
|
auto right = NDO->toBool(mOperandsStack.getOperand());
|
||||||
|
auto out = BoolObject::create(left && right);
|
||||||
|
mScopeStack.addTemp(out);
|
||||||
|
mOperandsStack.push(out);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OpCode::OR: {
|
||||||
|
auto left = NDO->toBool(mOperandsStack.getOperand());
|
||||||
|
auto right = NDO->toBool(mOperandsStack.getOperand());
|
||||||
|
auto out = BoolObject::create(left || right);
|
||||||
|
mScopeStack.addTemp(out);
|
||||||
|
mOperandsStack.push(out);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OpCode::NOT: {
|
||||||
|
auto inv = NDO->toBool(mOperandsStack.getOperand());
|
||||||
|
auto out = BoolObject::create(!inv);
|
||||||
|
mScopeStack.addTemp(out);
|
||||||
|
mOperandsStack.push(out);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OpCode::NOT_EQUAL: {
|
||||||
|
auto left = mOperandsStack.getOperand();
|
||||||
|
auto right = mOperandsStack.getOperand();
|
||||||
|
auto out = BoolObject::create(!NDO->compare(left, right));
|
||||||
|
mScopeStack.addTemp(out);
|
||||||
|
mOperandsStack.push(out);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OpCode::EQUAL: {
|
||||||
|
auto left = mOperandsStack.getOperand();
|
||||||
|
auto right = mOperandsStack.getOperand();
|
||||||
|
auto out = BoolObject::create(NDO->compare(left, right));
|
||||||
|
mScopeStack.addTemp(out);
|
||||||
|
mOperandsStack.push(out);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::MORE: {
|
||||||
|
auto left = NDO->toFloat(mOperandsStack.getOperand());
|
||||||
|
auto right = NDO->toFloat(mOperandsStack.getOperand());
|
||||||
|
auto out = BoolObject::create(left > right);
|
||||||
|
mScopeStack.addTemp(out);
|
||||||
|
mOperandsStack.push(out);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OpCode::LESS: {
|
||||||
|
auto left = NDO->toFloat(mOperandsStack.getOperand());
|
||||||
|
auto right = NDO->toFloat(mOperandsStack.getOperand());
|
||||||
|
auto out = BoolObject::create(left < right);
|
||||||
|
mScopeStack.addTemp(out);
|
||||||
|
mOperandsStack.push(out);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OpCode::EQUAL_OR_MORE: {
|
||||||
|
auto left = NDO->toFloat(mOperandsStack.getOperand());
|
||||||
|
auto right = NDO->toFloat(mOperandsStack.getOperand());
|
||||||
|
auto out = BoolObject::create(left >= right);
|
||||||
|
mScopeStack.addTemp(out);
|
||||||
|
mOperandsStack.push(out);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OpCode::EQUAL_OR_LESS: {
|
||||||
|
auto left = NDO->toFloat(mOperandsStack.getOperand());
|
||||||
|
auto right = NDO->toFloat(mOperandsStack.getOperand());
|
||||||
|
auto out = BoolObject::create(left <= right);
|
||||||
|
mScopeStack.addTemp(out);
|
||||||
|
mOperandsStack.push(out);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
ASSERT("Invalid OpCode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interpreter::execAll(obj::MethodObject* method, obj::ClassObject* self, obj::DictObject* globals, tp::init_list<GlobalDef> globals2) {
|
||||||
|
if (!method->mScript->mBytecode.mInstructions.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
exec(method, self, globals, globals2);
|
||||||
|
while (!finished()) {
|
||||||
|
stepBytecodeIn();
|
||||||
|
}
|
||||||
|
}
|
||||||
384
Objects/private/interpreter/opcodes.cpp
Normal file
384
Objects/private/interpreter/opcodes.cpp
Normal file
|
|
@ -0,0 +1,384 @@
|
||||||
|
|
||||||
|
#include "Utils.hpp"
|
||||||
|
|
||||||
|
#include "interpreter/opcodes.h"
|
||||||
|
|
||||||
|
namespace obj {
|
||||||
|
OpcodeInfos gOpcodeInfos;
|
||||||
|
};
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
|
||||||
|
#define CONST_IDX_BYTES 2
|
||||||
|
|
||||||
|
#define OP(opcode, name, desc, ops, params) \
|
||||||
|
add(opcode, { #name, #desc, ops, params } );
|
||||||
|
|
||||||
|
OpcodeInfos::OperandsInfo::OperandsInfo() {}
|
||||||
|
OpcodeInfos::OperandsInfo::OperandsInfo(tp::init_list<Operand> list) {
|
||||||
|
DEBUG_ASSERT(MAX_OPERANDS >= list.size());
|
||||||
|
for (auto item : list) {
|
||||||
|
buff[len] = item;
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OpcodeInfos::ParamsInfo::ParamsInfo() {}
|
||||||
|
OpcodeInfos::ParamsInfo::ParamsInfo(tp::init_list<Param> list) {
|
||||||
|
DEBUG_ASSERT(MAX_PARAMS >= list.size());
|
||||||
|
for (auto item : list) {
|
||||||
|
buff[len] = item;
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::uint1 OpcodeInfos::OpInfo::opsize() {
|
||||||
|
tp::uint1 out = 1;
|
||||||
|
for (auto i = 0; i < params.len; i++) {
|
||||||
|
out += params.buff[i].bytes;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
OpcodeInfos::OpcodeInfos() {
|
||||||
|
|
||||||
|
add(OpCode::NONE, { "NONE", "Does Nothing" });
|
||||||
|
add(OpCode::HALT, { "HALT", "Halts for 3 sec" });
|
||||||
|
add(OpCode::TERMINATE, { "TERMINATE", "Terminates the process" });
|
||||||
|
add(OpCode::DEF_LOCAL, {
|
||||||
|
.name = "DEF LOCAL",
|
||||||
|
.desc = "Adds object to the locals",
|
||||||
|
.operands = {
|
||||||
|
{ "str", "local id" },
|
||||||
|
{ "any", "object to be local" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::LOAD_CONST, {
|
||||||
|
.name = "LOAD CONST",
|
||||||
|
.desc = "Loads const object from the const pool",
|
||||||
|
.params = {
|
||||||
|
{ "const obj idx", CONST_IDX_BYTES },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::LOAD_LOCAL, {
|
||||||
|
.name = "LOAD LOCAL",
|
||||||
|
.desc = "Loads local object from the locals",
|
||||||
|
.params = {
|
||||||
|
{ "idx of const StringObject - represents name id", CONST_IDX_BYTES },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::IGNORE, {
|
||||||
|
.name = "IGNORE",
|
||||||
|
.desc = "Ignores returned object by destroying it",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::SCOPE_IN, {
|
||||||
|
.name = "SCOPE IN",
|
||||||
|
.desc = "Enters new scope",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::SCOPE_OUT, {
|
||||||
|
.name = "SCOPE OUT",
|
||||||
|
.desc = "Leaves current scope",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::CALL, {
|
||||||
|
.name = "CALL",
|
||||||
|
.desc = "Leaves current scope",
|
||||||
|
.operands = {
|
||||||
|
{ "method", "method object" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::RETURN_OBJ, {
|
||||||
|
.name = "RETURN OBJ",
|
||||||
|
.desc = "Returns Operand",
|
||||||
|
.operands = {
|
||||||
|
{ "any", "object to be returned" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::RETURN, {
|
||||||
|
.name = "RETURN",
|
||||||
|
.desc = "Returns Null Object",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::CHILD, {
|
||||||
|
.name = "CHILD",
|
||||||
|
.desc = "Retrieves child from class",
|
||||||
|
.operands = {
|
||||||
|
{ "str", "child id" },
|
||||||
|
{ "class", "parent class" },
|
||||||
|
},
|
||||||
|
.params = {
|
||||||
|
{ "is method ?", 1 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::PUSH_ARGS, {
|
||||||
|
.name = "PUSH ARGS",
|
||||||
|
.desc = "Pushes Separator on the OperandsStack",
|
||||||
|
.params = {
|
||||||
|
{ "length to chech number of args", 1 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::SAVE_ARGS, {
|
||||||
|
.name = "SAVE ARGS",
|
||||||
|
.desc = "Pushes operands to locals",
|
||||||
|
.params = {
|
||||||
|
{ "number of arguments in function defenition", 1 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::OBJ_CREATE_LOCAL, {
|
||||||
|
.name = "CREATE LOCAL OBJ",
|
||||||
|
.desc = "creates object of given type and adds it to the locals",
|
||||||
|
.operands = {
|
||||||
|
{ "str", "types" },
|
||||||
|
{ "str", "name id" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::OBJ_CREATE, {
|
||||||
|
.name = "CREATE OBJ",
|
||||||
|
.desc = "creates object of given type",
|
||||||
|
.operands = {
|
||||||
|
{ "str", "types" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::OBJ_COPY, {
|
||||||
|
.name = "COPY",
|
||||||
|
.desc = "Copies objects",
|
||||||
|
.operands = {
|
||||||
|
{ "any", "self" },
|
||||||
|
{ "any", "target" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::OBJ_SAVE, {
|
||||||
|
.name = "SAVE",
|
||||||
|
.desc = "Saves object to a file",
|
||||||
|
.operands = {
|
||||||
|
{ "str", "path" },
|
||||||
|
{ "any", "self" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::OBJ_LOAD, {
|
||||||
|
.name = "LOAD",
|
||||||
|
.desc = "loads object from a file",
|
||||||
|
.operands = {
|
||||||
|
{ "str", "path" },
|
||||||
|
{ "any", "self" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::OBJ_ADD, {
|
||||||
|
.name = "ADD",
|
||||||
|
.desc = "Adds objects of the same type that supports ariphmetics",
|
||||||
|
.operands = {
|
||||||
|
{ "any", "left" },
|
||||||
|
{ "any", "right" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::OBJ_SUB, {
|
||||||
|
.name = "SUB",
|
||||||
|
.desc = "Subtruts objects of the same type that supports ariphmetics",
|
||||||
|
.operands = {
|
||||||
|
{ "any", "left" },
|
||||||
|
{ "any", "right" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::OBJ_MUL, {
|
||||||
|
.name = "MUL",
|
||||||
|
.desc = "Multiplies objects of the same type that supports ariphmetics",
|
||||||
|
.operands = {
|
||||||
|
{ "any", "left" },
|
||||||
|
{ "any", "right" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::OBJ_DIV, {
|
||||||
|
.name = "DIV",
|
||||||
|
.desc = "Divides objects of the same type that supports ariphmetics",
|
||||||
|
.operands = {
|
||||||
|
{ "any", "left" },
|
||||||
|
{ "any", "right" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::AND, {
|
||||||
|
.name = "AND",
|
||||||
|
.desc = "Logical AND of objects of the same type that supports boolean ariphmetics",
|
||||||
|
.operands = {
|
||||||
|
{ "any", "left" },
|
||||||
|
{ "any", "right" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::OR, {
|
||||||
|
.name = "OR",
|
||||||
|
.desc = "Logical OR of objects of the same type that supports boolean ariphmetics",
|
||||||
|
.operands = {
|
||||||
|
{ "any", "left" },
|
||||||
|
{ "any", "right" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::EQUAL, {
|
||||||
|
.name = "EQUAL",
|
||||||
|
.desc = "Compares objects",
|
||||||
|
.operands = {
|
||||||
|
{ "any", "left" },
|
||||||
|
{ "any", "right" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::NOT_EQUAL, {
|
||||||
|
.name = "NOT EQUAL",
|
||||||
|
.desc = "Compares objects and inverts the resault",
|
||||||
|
.operands = {
|
||||||
|
{ "any", "left" },
|
||||||
|
{ "any", "right" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::MORE, {
|
||||||
|
.name = "MORE",
|
||||||
|
.desc = " > ",
|
||||||
|
.operands = {
|
||||||
|
{ "any", "left" },
|
||||||
|
{ "any", "right" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::LESS, {
|
||||||
|
.name = "LESS",
|
||||||
|
.desc = " < ",
|
||||||
|
.operands = {
|
||||||
|
{ "any", "left" },
|
||||||
|
{ "any", "right" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::EQUAL_OR_MORE, {
|
||||||
|
.name = "GRATER OR EQUAL",
|
||||||
|
.desc = " >= ",
|
||||||
|
.operands = {
|
||||||
|
{ "any", "left" },
|
||||||
|
{ "any", "right" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::EQUAL_OR_LESS, {
|
||||||
|
.name = "LESS OR EQUAL",
|
||||||
|
.desc = " <= ",
|
||||||
|
.operands = {
|
||||||
|
{ "any", "left" },
|
||||||
|
{ "any", "right" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::NOT, {
|
||||||
|
.name = "NOT",
|
||||||
|
.desc = "Inverts the object bolean representation",
|
||||||
|
.operands = {
|
||||||
|
{ "any", "self" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::JUMP, {
|
||||||
|
.name = "JUMP",
|
||||||
|
.desc = "Offsets the instruction pointer",
|
||||||
|
.params = {
|
||||||
|
{ "ip offset unsigned", 2 },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::JUMP_R, {
|
||||||
|
.name = "JUMP R",
|
||||||
|
.desc = "Offsets the instruction pointer in reversed direction",
|
||||||
|
.params = {
|
||||||
|
{ "ip offset unsigned", 2 },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::JUMP_IF, {
|
||||||
|
.name = "JUMP IF",
|
||||||
|
.desc = "Offsets the instruction pointer if condition is met",
|
||||||
|
.operands = {
|
||||||
|
{ "any", "condition object" },
|
||||||
|
},
|
||||||
|
.params = {
|
||||||
|
{ "ip offset unsigned", 2 },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::JUMP_IF_R, {
|
||||||
|
.name = "JUMP IF R",
|
||||||
|
.desc = "Offsets the instruction pointer in reversed direction if condition is met",
|
||||||
|
.operands = {
|
||||||
|
{ "any", "condition object" },
|
||||||
|
},
|
||||||
|
.params = {
|
||||||
|
{ "ip offset unsigned", 2 },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::JUMP_IF_NOT, {
|
||||||
|
.name = "JUMP IF R",
|
||||||
|
.desc = "Offsets the instruction pointer if condition is NOT met",
|
||||||
|
.operands = {
|
||||||
|
{ "any", "condition object" },
|
||||||
|
},
|
||||||
|
.params = {
|
||||||
|
{ "ip offset unsigned", 2 },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::JUMP_IF_NOT_R, {
|
||||||
|
.name = "JUMP IF R",
|
||||||
|
.desc = "Offsets the instruction pointer in reversed direction if condition is NOT met",
|
||||||
|
.operands = {
|
||||||
|
{ "any", "condition object" },
|
||||||
|
},
|
||||||
|
.params = {
|
||||||
|
{ "ip offset unsigned", 2 },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::PRINT, {
|
||||||
|
.name = "PRINT",
|
||||||
|
.desc = "Prints the object string representation",
|
||||||
|
.operands = {
|
||||||
|
{ "any", "self" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::CLASS_CONSTRUCT, {
|
||||||
|
.name = "CLASS CONSTRUCT",
|
||||||
|
.desc = "Creates class from the function execution state",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add(OpCode::SELF, {
|
||||||
|
.name = "SELF",
|
||||||
|
.desc = "retrieves parent class of the current method",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
OpcodeInfos::OpInfo OpcodeInfos::fetch(OpCode code) {
|
||||||
|
DEBUG_ASSERT((tp::alni)code >= 0 && (tp::alni)code < (tp::alni)OpCode::END_OPCODES);
|
||||||
|
return buff[(tp::alni)code];
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpcodeInfos::add(OpCode code, const OpInfo& info) {
|
||||||
|
buff[(tp::alni)code] = info;
|
||||||
|
}
|
||||||
30
Objects/private/interpreter/operandsstack.cpp
Normal file
30
Objects/private/interpreter/operandsstack.cpp
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
|
||||||
|
#include "interpreter/operandsstack.h"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
|
||||||
|
OperandStack::OperandStack() {
|
||||||
|
mBuff = new Operand[MAX_STACK_SIZE];
|
||||||
|
mIdx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OperandStack::push(Operand operand) {
|
||||||
|
ASSERT(MAX_STACK_SIZE - 1 > mIdx && "stack overflow");
|
||||||
|
mBuff[mIdx] = operand;
|
||||||
|
mIdx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OperandStack::pop() {
|
||||||
|
ASSERT(mIdx != NULL && "stack overflow");
|
||||||
|
mIdx--;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand OperandStack::getOperand() {
|
||||||
|
auto ret = mBuff[mIdx - 1];
|
||||||
|
mIdx--;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
OperandStack::~OperandStack() {
|
||||||
|
delete[] mBuff;
|
||||||
|
}
|
||||||
90
Objects/private/interpreter/scopestack.cpp
Normal file
90
Objects/private/interpreter/scopestack.cpp
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
|
||||||
|
#include "interpreter/scopestack.h"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
|
||||||
|
Scope::~Scope() {
|
||||||
|
for (auto local : mLocals) {
|
||||||
|
obj::NDO->destroy(local->val);
|
||||||
|
}
|
||||||
|
for (auto tmp : mTemps) {
|
||||||
|
obj::NDO->destroy(tmp.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obj::Object* ScopeStack::getLocalUtil(Scope& scope, tp::String* id) {
|
||||||
|
|
||||||
|
auto idx = scope.mLocals.presents(*id);
|
||||||
|
|
||||||
|
if (idx) {
|
||||||
|
return scope.mLocals.getSlotVal(idx);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mIterIdx--;
|
||||||
|
Scope& parent_scope = mBuff[mIterIdx];
|
||||||
|
ASSERT(parent_scope.mChildReachable && "Undefined Local Reference");
|
||||||
|
return getLocalUtil(parent_scope, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopeStack::ScopeStack() {
|
||||||
|
mBuff = (Scope*) tp::HeapAllocGlobal::allocate(sizeof(Scope) * MAX_STACK_SIZE);
|
||||||
|
mIdx = 0;
|
||||||
|
mIterIdx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScopeStack::enterScope(bool aChildReachable) {
|
||||||
|
ASSERT(MAX_STACK_SIZE - 1 > mIdx && "stack overflow");
|
||||||
|
new (&mBuff[mIdx]) Scope();
|
||||||
|
mBuff[mIdx].mChildReachable = aChildReachable;
|
||||||
|
mIdx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScopeStack::leaveScope() {
|
||||||
|
ASSERT(mIdx != NULL && "stack overflow");
|
||||||
|
mBuff[mIdx - 1].~Scope();
|
||||||
|
mIdx--;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScopeStack::addTemp(obj::Object* tmp) {
|
||||||
|
obj::NDO->refinc(tmp);
|
||||||
|
mBuff[mIdx - 1].mTemps.pushBack(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScopeStack::popTemp() {
|
||||||
|
obj::NDO->destroy(mBuff[mIdx - 1].mTemps.last()->data);
|
||||||
|
mBuff[mIdx - 1].mTemps.popBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScopeStack::addTempReturn(obj::Object* ret) {
|
||||||
|
if (mIdx >= 2) {
|
||||||
|
obj::NDO->refinc(ret);
|
||||||
|
mBuff[mIdx - 2].mTemps.pushBack(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScopeStack::addLocal(obj::Object* local, tp::String id) {
|
||||||
|
DEBUG_ASSERT(mIdx != 0 && "No scope given");
|
||||||
|
Scope::ObjDict& locals = mBuff[mIdx - 1].mLocals;
|
||||||
|
auto idx = locals.presents(id);
|
||||||
|
if (idx) {
|
||||||
|
obj::NDO->destroy(locals.getSlotVal(idx));
|
||||||
|
}
|
||||||
|
obj::NDO->refinc(local);
|
||||||
|
locals.put(id, local);
|
||||||
|
}
|
||||||
|
|
||||||
|
obj::Object* ScopeStack::getLocal(tp::String& str) {
|
||||||
|
mIterIdx = mIdx - 1;
|
||||||
|
return getLocalUtil(mBuff[mIdx - 1], &str);
|
||||||
|
}
|
||||||
|
|
||||||
|
Scope* ScopeStack::getCurrentScope() {
|
||||||
|
return &mBuff[mIdx - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopeStack::~ScopeStack() {
|
||||||
|
tp::HeapAllocGlobal::deallocate(mBuff);
|
||||||
|
}
|
||||||
904
Objects/private/parser/parser.cpp
Normal file
904
Objects/private/parser/parser.cpp
Normal file
|
|
@ -0,0 +1,904 @@
|
||||||
|
|
||||||
|
#include "Logging.hpp"
|
||||||
|
#include "List.hpp"
|
||||||
|
|
||||||
|
#include "parser/parser.h"
|
||||||
|
#include "compiler/function.h"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#define MAX_STREAM_LENGTH 1024 * 8 * 200
|
||||||
|
|
||||||
|
#define REQUIRE(expr, desc, on_catch) DEBUG_BREAK(mRes.err); if (!(expr)) { mRes.err = new Error(desc, mTok.getCursorPrev().mAdvancedOffset); on_catch; return NULL; }
|
||||||
|
#define CHECK(expr, on_catch) if (!(expr)) { on_catch; return NULL; }
|
||||||
|
#define CHECK_ERROR(value, on_catch) if (mRes.err || !value) { on_catch; return NULL; }
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
using namespace obj;
|
||||||
|
using namespace BCgen;
|
||||||
|
|
||||||
|
bool Parser::Token::isAriphm() {
|
||||||
|
switch (type) {
|
||||||
|
case Token::ADD:
|
||||||
|
case Token::SUB:
|
||||||
|
case Token::DIV:
|
||||||
|
case Token::MUL:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Parser::Token::isBoolean() {
|
||||||
|
switch (type) {
|
||||||
|
case Token::EQUAL:
|
||||||
|
case Token::NOT_EQUAL:
|
||||||
|
case Token::BOOL_AND:
|
||||||
|
case Token::BOOL_OR:
|
||||||
|
case Token::MORE:
|
||||||
|
case Token::LESS:
|
||||||
|
case Token::QE_OR_MORE:
|
||||||
|
case Token::QE_OR_LESS:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Parser::Parser() {
|
||||||
|
mTok.build({
|
||||||
|
{ "\n|\t| |\r", Token::SPACE },
|
||||||
|
{ "var", Token::VAR },
|
||||||
|
{ "class", Token::CLASS_DEF },
|
||||||
|
{ "self", Token::SELF },
|
||||||
|
{ "\\{", Token::SCOPE_IN },
|
||||||
|
{ "\\}", Token::SCOPE_OUT },
|
||||||
|
{ "=", Token::ASSIGN },
|
||||||
|
{ "def", Token::DEF_FUNC },
|
||||||
|
{ "<<", Token::PRINT },
|
||||||
|
{ "if", Token::IF },
|
||||||
|
{ "else", Token::ELSE },
|
||||||
|
{ "while", Token::WHILE },
|
||||||
|
{ "\\(", Token::BRACKET_IN },
|
||||||
|
{ "\\)", Token::BRACKET_OUT },
|
||||||
|
{ ",", Token::COMMA },
|
||||||
|
{ "new", Token::NEW },
|
||||||
|
{ "\\.", Token::CHILD },
|
||||||
|
{ "return", Token::RETURN },
|
||||||
|
{ "==", Token::EQUAL },
|
||||||
|
{ "!=", Token::NOT_EQUAL },
|
||||||
|
{ ">", Token::MORE },
|
||||||
|
{ "<", Token::LESS },
|
||||||
|
{ ">=", Token::QE_OR_MORE },
|
||||||
|
{ "<=", Token::QE_OR_LESS },
|
||||||
|
{ "!", Token::BOOL_NOT },
|
||||||
|
{ "&&", Token::BOOL_AND },
|
||||||
|
{ "\\|\\|", Token::BOOL_OR },
|
||||||
|
{ "\\+", Token::ADD },
|
||||||
|
{ "\\*", Token::MUL },
|
||||||
|
{ "\\-", Token::SUB },
|
||||||
|
{ "/", Token::DIV },
|
||||||
|
{ ";", Token::STM_END },
|
||||||
|
{ "true", Token::CONST_TRUE },
|
||||||
|
{ "false", Token::CONST_FALSE },
|
||||||
|
{ "((\\-)|(\\+))?[0-9]+i?", Token::CONST_INT },
|
||||||
|
{ "((\\-)|(\\+))?([0-9]+)(\\.)([0-9]*)?f?", Token::CONST_FLOAT },
|
||||||
|
{ "(/\\*){\\*-\\*}*(\\*/)", Token::COMMENT_BLOCK },
|
||||||
|
{ "\"{\"-\"}*\"", Token::CONST_STRING },
|
||||||
|
{ "([a-z]|[A-Z]|_)+([a-z]|[A-Z]|[0-9]|_)*", Token::ID },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::String to_string(const char* stream, tp::alni len) {
|
||||||
|
tp::String out;
|
||||||
|
out.reserve(len + 1);
|
||||||
|
tp::memcp(out.get_writable(), stream, len);
|
||||||
|
out.get_writable()[len] = '\0';
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
Parser::Token Parser::tokRead() {
|
||||||
|
Token out;
|
||||||
|
|
||||||
|
if (!tokInputLeft()) {
|
||||||
|
Token out;
|
||||||
|
out.type = Token::NO_TOKEN;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto crs_start = mTok.getCursor();
|
||||||
|
out.type = mTok.readTok();
|
||||||
|
out.token = to_string(crs_start.str(), mTok.lastTokLEn());
|
||||||
|
|
||||||
|
switch (out.type) {
|
||||||
|
case Token::CONST_FALSE:
|
||||||
|
out.boolean = false;
|
||||||
|
break;
|
||||||
|
case Token::CONST_TRUE:
|
||||||
|
out.boolean = true;
|
||||||
|
break;
|
||||||
|
case Token::CONST_INT: {
|
||||||
|
char* p_end;
|
||||||
|
out.integer = std::strtol(out.token.read(), &p_end, 10);
|
||||||
|
DEBUG_ASSERT(out.token.read() != p_end);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Token::CONST_FLOAT: {
|
||||||
|
char* p_end;
|
||||||
|
out.floating = std::strtod(out.token.read(), &p_end);
|
||||||
|
DEBUG_ASSERT(out.token.read() != p_end);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Token::CONST_STRING: {
|
||||||
|
out.str = to_string(crs_start.str() + 1, mTok.lastTokLEn() - 2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
Parser::Token Parser::tokLookup() {
|
||||||
|
auto crs = mTok.getCursor();
|
||||||
|
auto out = tokRead();
|
||||||
|
mTok.setCursor(crs);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Parser::tokInputLeft() {
|
||||||
|
auto type = mTok.lookupTok();
|
||||||
|
|
||||||
|
while (mTok.isInputLeft() && type == Token::SPACE || (type >= Token::__END__ && type <= Token::__START__)) {
|
||||||
|
mTok.skipTok();
|
||||||
|
type = mTok.lookupTok();
|
||||||
|
}
|
||||||
|
|
||||||
|
return type != Token::SOURCE_END_TOKEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::tokSkip() {
|
||||||
|
if (!tokInputLeft()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mTok.skipTok();
|
||||||
|
}
|
||||||
|
|
||||||
|
Parser::Tokenizer::Cursor Parser::tokGetCursor() { return mTok.getCursor();}
|
||||||
|
void Parser::tokSetCursor(Tokenizer::Cursor crs) { mTok.setCursor(crs); }
|
||||||
|
|
||||||
|
Expression* Parser::parseExprCompound() {
|
||||||
|
CHECK(tokRead() == Token::BRACKET_IN, {});
|
||||||
|
auto ret = parseExpr();
|
||||||
|
CHECK_ERROR(ret, {});
|
||||||
|
REQUIRE(tokRead() == Token::BRACKET_OUT, "Expected Closing Bracket", {});
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression* Parser::parseExprNEW() {
|
||||||
|
CHECK(tokRead() == Token::NEW, {});
|
||||||
|
auto name = tokRead();
|
||||||
|
REQUIRE(name == Token::ID, "Expected Identifier", {});
|
||||||
|
|
||||||
|
REQUIRE(tokRead() == Token::BRACKET_IN, "Expected opening brackets", {});
|
||||||
|
REQUIRE(tokRead() == Token::BRACKET_OUT, "Expected closing brackets", {});
|
||||||
|
|
||||||
|
return ExprNew(name.token);
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression* Parser::parseExprLOCAL() {
|
||||||
|
auto local_id_tok = tokRead();
|
||||||
|
if (local_id_tok == Token::ID) {
|
||||||
|
return ExprLocal(local_id_tok.token);
|
||||||
|
}
|
||||||
|
else if (local_id_tok == Token::SELF) {
|
||||||
|
return ExprSelf();
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression* Parser::parseExprCONST() {
|
||||||
|
auto tok = tokRead();
|
||||||
|
switch (tok) {
|
||||||
|
case Token::CONST_FALSE:
|
||||||
|
return ExprConst(false);
|
||||||
|
case Token::CONST_TRUE:
|
||||||
|
return ExprConst(true);
|
||||||
|
case Token::CONST_INT:
|
||||||
|
return ExprConst(tok.integer);
|
||||||
|
case Token::CONST_FLOAT:
|
||||||
|
return ExprConst(tok.floating);
|
||||||
|
case Token::CONST_STRING:
|
||||||
|
return ExprConst(tok.str);
|
||||||
|
default:
|
||||||
|
REQUIRE(0, "not a const Expr", {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression* Parser::parseExprCHILD(Expression* prnt) {
|
||||||
|
CHECK(tokRead() == Token::CHILD, {});
|
||||||
|
auto id = tokRead();
|
||||||
|
REQUIRE(id == Token::ID, "Exprected Identifier", {});
|
||||||
|
return prnt->ExprChild(id.str);
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression* Parser::parseExprCALL(Expression* prnt) {
|
||||||
|
CHECK(tokRead() == Token::BRACKET_IN, {});
|
||||||
|
|
||||||
|
List<Expression*> args;
|
||||||
|
|
||||||
|
READ_ARG:
|
||||||
|
Expression* expr = NULL;
|
||||||
|
auto tok = tokLookup();
|
||||||
|
REQUIRE(tok != Token::NO_TOKEN, "Missing Closing Bracket", {});
|
||||||
|
|
||||||
|
if (tok != Token::BRACKET_OUT) {
|
||||||
|
|
||||||
|
expr = parseExpr();
|
||||||
|
CHECK_ERROR(expr, {
|
||||||
|
for (auto arg : args) {
|
||||||
|
delete arg.data();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
args.pushBack(expr);
|
||||||
|
|
||||||
|
tok = tokLookup();
|
||||||
|
if (tok == Token::COMMA) {
|
||||||
|
tokSkip();
|
||||||
|
goto READ_ARG;
|
||||||
|
}
|
||||||
|
else if (tok != Token::BRACKET_OUT) {
|
||||||
|
for (auto arg : args) {
|
||||||
|
delete arg.data();
|
||||||
|
}
|
||||||
|
REQUIRE(0, "Expected A Closing Bracket", {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tokSkip();
|
||||||
|
|
||||||
|
auto out = prnt->ExprCall({});
|
||||||
|
out->mArgs.reserve(args.length());
|
||||||
|
|
||||||
|
for (auto arg : args) {
|
||||||
|
out->mArgs[arg.idx()] = arg.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression* Parser::parseExprAriphm() {
|
||||||
|
|
||||||
|
tp::init_list<ExprType> expessions = {
|
||||||
|
ExprType::Compound,
|
||||||
|
ExprType::NEW,
|
||||||
|
ExprType::LOCAL,
|
||||||
|
ExprType::CONST,
|
||||||
|
};
|
||||||
|
|
||||||
|
Expression* left = parseExpr(expessions);
|
||||||
|
CHECK_ERROR(left, {});
|
||||||
|
|
||||||
|
Expression* ret = NULL;
|
||||||
|
|
||||||
|
PARSE:
|
||||||
|
|
||||||
|
Expression* right = NULL;
|
||||||
|
|
||||||
|
auto tok = tokLookup();
|
||||||
|
if (tok.isAriphm()) {
|
||||||
|
tokSkip();
|
||||||
|
|
||||||
|
|
||||||
|
right = parseExpr(expessions);
|
||||||
|
|
||||||
|
if (mRes.err) {
|
||||||
|
if (ret) {
|
||||||
|
goto PRECEDENCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete left;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
CHECK(ret, {
|
||||||
|
delete left;
|
||||||
|
});
|
||||||
|
goto PRECEDENCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (tok) {
|
||||||
|
case Token::ADD:
|
||||||
|
ret = ExprAriphm(left, right, OpCode::OBJ_ADD);
|
||||||
|
break;
|
||||||
|
case Token::SUB:
|
||||||
|
ret = ExprAriphm(left, right, OpCode::OBJ_SUB);
|
||||||
|
break;
|
||||||
|
case Token::DIV:
|
||||||
|
ret = ExprAriphm(left, right, OpCode::OBJ_DIV);
|
||||||
|
break;
|
||||||
|
case Token::MUL:
|
||||||
|
ret = ExprAriphm(left, right, OpCode::OBJ_MUL);
|
||||||
|
}
|
||||||
|
|
||||||
|
left = ret;
|
||||||
|
goto PARSE;
|
||||||
|
|
||||||
|
PRECEDENCE:
|
||||||
|
// FIXME: Not Implemented
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression* Parser::parseExprBOOLEAN() {
|
||||||
|
|
||||||
|
tp::init_list<ExprType> expessions = {
|
||||||
|
ExprType::Compound,
|
||||||
|
ExprType::NEW,
|
||||||
|
ExprType::LOCAL,
|
||||||
|
ExprType::CONST,
|
||||||
|
ExprType::BOOLEAN_NOT,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Expression* left = parseExpr(expessions);
|
||||||
|
CHECK_ERROR(left, {});
|
||||||
|
|
||||||
|
Expression* ret = NULL;
|
||||||
|
|
||||||
|
PARSE:
|
||||||
|
|
||||||
|
Expression* right = NULL;
|
||||||
|
|
||||||
|
auto tok = tokLookup();
|
||||||
|
if (tok.isBoolean()) {
|
||||||
|
tokSkip();
|
||||||
|
|
||||||
|
right = parseExpr(expessions);
|
||||||
|
|
||||||
|
if (mRes.err) {
|
||||||
|
if (ret) {
|
||||||
|
goto PRECEDENCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete left;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
CHECK(ret, {
|
||||||
|
delete left;
|
||||||
|
});
|
||||||
|
goto PRECEDENCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (tok) {
|
||||||
|
case Token::EQUAL:
|
||||||
|
ret = ExprBool(left, right, OpCode::EQUAL);
|
||||||
|
break;
|
||||||
|
case Token::NOT_EQUAL:
|
||||||
|
ret = ExprBool(left, right, OpCode::NOT_EQUAL);
|
||||||
|
break;
|
||||||
|
case Token::BOOL_AND:
|
||||||
|
ret = ExprBool(left, right, OpCode::AND);
|
||||||
|
break;
|
||||||
|
case Token::BOOL_OR:
|
||||||
|
ret = ExprBool(left, right, OpCode::OR);
|
||||||
|
break;
|
||||||
|
case Token::MORE:
|
||||||
|
ret = ExprBool(left, right, OpCode::MORE);
|
||||||
|
break;
|
||||||
|
case Token::LESS:
|
||||||
|
ret = ExprBool(left, right, OpCode::LESS);
|
||||||
|
break;
|
||||||
|
case Token::QE_OR_MORE:
|
||||||
|
ret = ExprBool(left, right, OpCode::EQUAL_OR_MORE);
|
||||||
|
break;
|
||||||
|
case Token::QE_OR_LESS:
|
||||||
|
ret = ExprBool(left, right, OpCode::EQUAL_OR_LESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
left = ret;
|
||||||
|
goto PARSE;
|
||||||
|
|
||||||
|
PRECEDENCE:
|
||||||
|
// FIXME: Not Implemented
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression* Parser::parseExprBOOLEAN_NOT() {
|
||||||
|
CHECK(tokRead() == Token::BOOL_NOT, {});
|
||||||
|
|
||||||
|
tp::init_list<ExprType> exprs = {
|
||||||
|
ExprType::Compound,
|
||||||
|
ExprType::BOOLEAN,
|
||||||
|
ExprType::Ariphm,
|
||||||
|
ExprType::NEW,
|
||||||
|
ExprType::LOCAL,
|
||||||
|
ExprType::CONST,
|
||||||
|
};
|
||||||
|
|
||||||
|
auto out = parseExpr(exprs);
|
||||||
|
CHECK_ERROR(out, {});
|
||||||
|
|
||||||
|
return ExprBoolNot(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression* Parser::parseExprFUNC() {
|
||||||
|
auto op_tok = tokRead();
|
||||||
|
CHECK(op_tok == Token::ID, {});
|
||||||
|
return ExprFunc(op_tok.token);
|
||||||
|
}
|
||||||
|
|
||||||
|
// passed prnt isno longer responsability of callee
|
||||||
|
// suc : returns top level parent
|
||||||
|
// err : returns NULL
|
||||||
|
Expression* Parser::parseExprChain(Expression* prnt) {
|
||||||
|
|
||||||
|
PARSE_CHAIN:
|
||||||
|
auto tok = tokLookup();
|
||||||
|
|
||||||
|
switch (tok) {
|
||||||
|
case Token::CHILD: {
|
||||||
|
tokRead();
|
||||||
|
|
||||||
|
auto child_id = tokRead();
|
||||||
|
REQUIRE(child_id == Token::ID, "expected an id", {
|
||||||
|
delete prnt;
|
||||||
|
});
|
||||||
|
|
||||||
|
prnt = prnt->ExprChild(child_id.token);
|
||||||
|
goto PARSE_CHAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Token::BRACKET_IN: {
|
||||||
|
|
||||||
|
auto new_prnt = parseExprCALL(prnt);
|
||||||
|
CHECK_ERROR(new_prnt, {
|
||||||
|
delete prnt;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (prnt->mType == Expression::Type::CHILD) {
|
||||||
|
((ExpressionChild*)prnt)->mMethod = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
prnt = new_prnt;
|
||||||
|
goto PARSE_CHAIN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return prnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression* Parser::parseExpr(tp::init_list<ExprType> expressions) {
|
||||||
|
|
||||||
|
Expression* out = NULL;
|
||||||
|
|
||||||
|
List<Error*> errors;
|
||||||
|
|
||||||
|
for (auto expr_type : expressions) {
|
||||||
|
auto crs = tokGetCursor();
|
||||||
|
switch (expr_type) {
|
||||||
|
case Parser::ExprType::BOOLEAN_NOT:
|
||||||
|
out = parseExprBOOLEAN_NOT();
|
||||||
|
break;
|
||||||
|
case Parser::ExprType::BOOLEAN:
|
||||||
|
out = parseExprBOOLEAN();
|
||||||
|
break;
|
||||||
|
case Parser::ExprType::Ariphm:
|
||||||
|
out = parseExprAriphm();
|
||||||
|
break;
|
||||||
|
case Parser::ExprType::NEW:
|
||||||
|
out = parseExprNEW();
|
||||||
|
break;
|
||||||
|
case Parser::ExprType::LOCAL:
|
||||||
|
out = parseExprLOCAL();
|
||||||
|
break;
|
||||||
|
case Parser::ExprType::CONST:
|
||||||
|
out = parseExprCONST();
|
||||||
|
break;
|
||||||
|
case Parser::ExprType::Compound:
|
||||||
|
out = parseExprCompound();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tokSetCursor(crs);
|
||||||
|
if (mRes.err) {
|
||||||
|
errors.pushBack(mRes.err);
|
||||||
|
mRes.err = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out) {
|
||||||
|
// check for child expression and calls
|
||||||
|
out = parseExprChain(out);
|
||||||
|
|
||||||
|
// check errors
|
||||||
|
if (mRes.err) {
|
||||||
|
errors.pushBack(mRes.err);
|
||||||
|
mRes.err = NULL;
|
||||||
|
goto ERRORS;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto err : errors) {
|
||||||
|
delete err.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ERRORS:
|
||||||
|
Error* error = NULL;
|
||||||
|
tp::alni max_advanced = 0;
|
||||||
|
for (auto err : errors) {
|
||||||
|
if (err.data()->mAdvanecedIdx && err.data()->mAdvanecedIdx > max_advanced) {
|
||||||
|
max_advanced = err.data()->mAdvanecedIdx;
|
||||||
|
error = err.data();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
mRes.err = new Error(*error);
|
||||||
|
|
||||||
|
for (auto err : errors) {
|
||||||
|
delete err.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
REQUIRE(0, "Expected and expression", {});
|
||||||
|
}
|
||||||
|
|
||||||
|
Statement* Parser::parseStmCall() {
|
||||||
|
|
||||||
|
Expression* expr = parseExpr();
|
||||||
|
CHECK_ERROR(expr, {});
|
||||||
|
|
||||||
|
REQUIRE(expr->mType == Expression::Type::CALL,
|
||||||
|
"expression statement can only be function call", {
|
||||||
|
delete expr;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (tokRead() != Token::STM_END) {
|
||||||
|
delete expr;
|
||||||
|
REQUIRE(0, "Expected End Of Statement", {});
|
||||||
|
}
|
||||||
|
|
||||||
|
return StmIgnore(expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Statement* Parser::parseStmDefFunc() {
|
||||||
|
CHECK(tokRead() == Token::DEF_FUNC, {});
|
||||||
|
List<tp::String> args;
|
||||||
|
auto name = tokRead();
|
||||||
|
REQUIRE(name == Token::ID, "Expected an Identifier", {});
|
||||||
|
|
||||||
|
REQUIRE(tokRead() == Token::BRACKET_IN, "Expected Opening Bracket", {});
|
||||||
|
|
||||||
|
READ_ARG:
|
||||||
|
auto tok = tokLookup();
|
||||||
|
|
||||||
|
REQUIRE(tok != Token::NO_TOKEN, "Missing Closing Bracket", {});
|
||||||
|
|
||||||
|
if (tok == Token::ID) {
|
||||||
|
args.pushBack(tok.token);
|
||||||
|
tokSkip();
|
||||||
|
tok = tokLookup();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tok == Token::COMMA) {
|
||||||
|
tokSkip();
|
||||||
|
goto READ_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(tok == Token::BRACKET_OUT, "Expected Closing Bracket", {});
|
||||||
|
tokSkip();
|
||||||
|
|
||||||
|
auto func_def = StmDefFunc(name.token, {}, {});
|
||||||
|
|
||||||
|
func_def->mArgs.reserve(args.length());
|
||||||
|
for (auto iter : args) {
|
||||||
|
func_def->mArgs[iter.idx()] = iter.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementScope* scope = parseScope(true);
|
||||||
|
CHECK_ERROR(scope, {
|
||||||
|
delete func_def;
|
||||||
|
});
|
||||||
|
|
||||||
|
func_def->mStatements.reserve(scope->mStatements.size());
|
||||||
|
for (auto stm : scope->mStatements) {
|
||||||
|
func_def->mStatements[stm.idx()] = stm.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
delete scope;
|
||||||
|
return func_def;
|
||||||
|
}
|
||||||
|
|
||||||
|
Statement* Parser::parseStmDefLocal() {
|
||||||
|
CHECK(tokRead() == Token::VAR, {});
|
||||||
|
|
||||||
|
auto tok = tokRead();
|
||||||
|
REQUIRE(tok == Token::ID, "Expected an Identifier", {});
|
||||||
|
REQUIRE(tokRead() == Token::ASSIGN, "Expected an assigment", {});
|
||||||
|
|
||||||
|
auto expr = parseExpr();
|
||||||
|
CHECK_ERROR(expr, {});
|
||||||
|
|
||||||
|
if (tokRead() != Token::STM_END) {
|
||||||
|
delete expr;
|
||||||
|
REQUIRE(0, "Expected End Of Statement", {});
|
||||||
|
}
|
||||||
|
|
||||||
|
return StmDefLocal(tok.token, expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Statement* Parser::parseStmReturn() {
|
||||||
|
CHECK(tokRead() == Token::RETURN, {});
|
||||||
|
auto crs = tokGetCursor();
|
||||||
|
|
||||||
|
auto expr = parseExpr();
|
||||||
|
if (mRes.err) {
|
||||||
|
tokSetCursor(crs);
|
||||||
|
delete mRes.err;
|
||||||
|
mRes.err = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tokRead() != Token::STM_END) {
|
||||||
|
if (expr) delete expr;
|
||||||
|
REQUIRE(0, "Expected End Of Statement", {});
|
||||||
|
}
|
||||||
|
|
||||||
|
return expr ? StmReturn(expr) : StmReturn();
|
||||||
|
}
|
||||||
|
|
||||||
|
Statement* Parser::parseStmPrint() {
|
||||||
|
CHECK(tokRead() == Token::PRINT, {});
|
||||||
|
auto expr = parseExpr();
|
||||||
|
CHECK_ERROR(expr, {});
|
||||||
|
|
||||||
|
if (tokRead() != Token::STM_END) {
|
||||||
|
delete expr;
|
||||||
|
REQUIRE(0, "Expected End Of Statement", {});
|
||||||
|
}
|
||||||
|
return StmPrint(expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Statement* Parser::parseStmIf() {
|
||||||
|
CHECK(tokRead() == Token::IF, {});
|
||||||
|
|
||||||
|
// single if
|
||||||
|
REQUIRE(tokRead() == Token::BRACKET_IN, "Expected Opening Bracket", {});
|
||||||
|
auto expr = parseExpr();
|
||||||
|
CHECK_ERROR(expr, {});
|
||||||
|
|
||||||
|
if (tokRead() != Token::BRACKET_OUT) {
|
||||||
|
delete expr;
|
||||||
|
REQUIRE(0, "Expected Closing Bracket", {});
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ontrue = parseScope(false);
|
||||||
|
CHECK_ERROR(ontrue, {});
|
||||||
|
|
||||||
|
// if-else
|
||||||
|
auto crs = tokGetCursor();
|
||||||
|
if (tokRead() == Token::ELSE) {
|
||||||
|
StatementScope* onfalse = parseScope(false);
|
||||||
|
CHECK_ERROR(onfalse, {
|
||||||
|
delete ontrue;
|
||||||
|
delete expr;
|
||||||
|
});
|
||||||
|
|
||||||
|
return StmIf(expr, ontrue, onfalse);
|
||||||
|
}
|
||||||
|
tokSetCursor(crs);
|
||||||
|
|
||||||
|
return StmIf(expr, ontrue, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
Statement* Parser::parseStmWhile() {
|
||||||
|
CHECK(tokRead() == Token::WHILE, {});
|
||||||
|
|
||||||
|
REQUIRE(tokRead() == Token::BRACKET_IN, "Expected Opening Bracket", {});
|
||||||
|
auto expr = parseExpr();
|
||||||
|
CHECK_ERROR(expr, {});
|
||||||
|
|
||||||
|
if (tokRead() != Token::BRACKET_OUT) {
|
||||||
|
delete expr;
|
||||||
|
REQUIRE(0, "Expected Closing Bracket", {});
|
||||||
|
}
|
||||||
|
|
||||||
|
auto scope = parseScope(false);
|
||||||
|
CHECK_ERROR(scope, {});
|
||||||
|
|
||||||
|
return StmWhile(expr, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
Statement* Parser::parseStmCopy() {
|
||||||
|
auto left = parseExpr();
|
||||||
|
CHECK_ERROR(left, {});
|
||||||
|
|
||||||
|
CHECK(tokRead() == Token::ASSIGN, {});
|
||||||
|
|
||||||
|
auto right = parseExpr();
|
||||||
|
CHECK_ERROR(right, {
|
||||||
|
delete left;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (tokRead() != Token::STM_END) {
|
||||||
|
delete left;
|
||||||
|
delete right;
|
||||||
|
REQUIRE(0, "Expected End Of Statement", {});
|
||||||
|
}
|
||||||
|
|
||||||
|
return StmCopy(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
Statement* Parser::parseStmClassDef() {
|
||||||
|
CHECK(tokRead() == Token::CLASS_DEF, {});
|
||||||
|
|
||||||
|
auto id = tokRead();
|
||||||
|
REQUIRE(id == Token::ID, "Expected an Identifier", {});
|
||||||
|
|
||||||
|
auto scope = parseScope(true);
|
||||||
|
CHECK_ERROR(scope, {});
|
||||||
|
|
||||||
|
return StmClassDef(id.token, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
Statement* Parser::parseStm(tp::init_list<StmType> stm_types) {
|
||||||
|
Statement* out = NULL;
|
||||||
|
|
||||||
|
List<Error*> errors;
|
||||||
|
|
||||||
|
for (auto stm_type : stm_types) {
|
||||||
|
auto crs = tokGetCursor();
|
||||||
|
switch (stm_type) {
|
||||||
|
case StmType::DefFunc:
|
||||||
|
out = parseStmDefFunc();
|
||||||
|
break;
|
||||||
|
case StmType::DefLocal:
|
||||||
|
out = parseStmDefLocal();
|
||||||
|
break;
|
||||||
|
case StmType::Return:
|
||||||
|
out = parseStmReturn();
|
||||||
|
break;
|
||||||
|
case StmType::Print:
|
||||||
|
out = parseStmPrint();
|
||||||
|
break;
|
||||||
|
case StmType::If:
|
||||||
|
out = parseStmIf();
|
||||||
|
break;
|
||||||
|
case StmType::While:
|
||||||
|
out = parseStmWhile();
|
||||||
|
break;
|
||||||
|
case StmType::Copy:
|
||||||
|
out = parseStmCopy();
|
||||||
|
break;
|
||||||
|
case StmType::Call:
|
||||||
|
out = parseStmCall();
|
||||||
|
break;
|
||||||
|
case StmType::CLASS_DEF:
|
||||||
|
out = parseStmClassDef();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tokSetCursor(crs);
|
||||||
|
if (mRes.err) {
|
||||||
|
errors.pushBack(mRes.err);
|
||||||
|
mRes.err = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out) {
|
||||||
|
for (auto err : errors) {
|
||||||
|
delete err.data();
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error* error = NULL;
|
||||||
|
tp::alni max_advanced = 0;
|
||||||
|
for (auto err : errors) {
|
||||||
|
if (err.data()->mAdvanecedIdx && max_advanced < err.data()->mAdvanecedIdx) {
|
||||||
|
max_advanced = err.data()->mAdvanecedIdx;
|
||||||
|
error = err.data();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
mRes.err = new Error(*error);
|
||||||
|
|
||||||
|
for (auto err : errors) {
|
||||||
|
delete err.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(0, "Exprected A Statement", {});
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementScope* Parser::parseScope(bool aPushToScopeStack) {
|
||||||
|
CHECK(tokRead() == Token::SCOPE_IN, {});
|
||||||
|
|
||||||
|
auto out = new StatementScope({}, aPushToScopeStack);
|
||||||
|
List<Statement*> stms;
|
||||||
|
|
||||||
|
READ_STM:
|
||||||
|
auto crs = tokGetCursor();
|
||||||
|
auto tok = tokRead();
|
||||||
|
|
||||||
|
if (tok == Token::NO_TOKEN) {
|
||||||
|
delete out;
|
||||||
|
for (auto stm : stms) {
|
||||||
|
delete stm.data();
|
||||||
|
}
|
||||||
|
REQUIRE(0, "Missing Scope Closing Bracket", {});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tok != Token::SCOPE_OUT) {
|
||||||
|
tokSetCursor(crs);
|
||||||
|
|
||||||
|
auto stm = parseStm();
|
||||||
|
CHECK_ERROR(stm, {
|
||||||
|
delete out;
|
||||||
|
for (auto stm : stms) {
|
||||||
|
delete stm.data();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
stms.pushBack(stm);
|
||||||
|
|
||||||
|
goto READ_STM;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->mStatements.reserve(stms.length());
|
||||||
|
for (auto stm : stms) {
|
||||||
|
out->mStatements[stm.idx()] = stm.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
Parser::Resault Parser::parse(const tp::String& oscript) {
|
||||||
|
mTok.bindSource(oscript.read());
|
||||||
|
|
||||||
|
mRes.scope = new StatementScope({}, true);
|
||||||
|
|
||||||
|
List<Statement*> stms;
|
||||||
|
do {
|
||||||
|
auto stm = parseStm();
|
||||||
|
|
||||||
|
if (mRes.err || !stm) { // catch
|
||||||
|
delete mRes.scope;
|
||||||
|
mRes.scope = NULL;
|
||||||
|
for (auto stm : stms) {
|
||||||
|
delete stm.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
return mRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
stms.pushBack(stm);
|
||||||
|
|
||||||
|
} while (tokInputLeft());
|
||||||
|
|
||||||
|
mRes.scope->mStatements.reserve(stms.length());
|
||||||
|
for (auto stm : stms) {
|
||||||
|
mRes.scope->mStatements[stm.idx()] = stm.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
return mRes;
|
||||||
|
}
|
||||||
78
Objects/private/primitives/boolobject.cpp
Normal file
78
Objects/private/primitives/boolobject.cpp
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
|
||||||
|
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
#include "primitives/boolobject.h"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
void BoolObject::constructor(BoolObject* self) {
|
||||||
|
self->val = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoolObject::copy(BoolObject* self, const BoolObject* in) {
|
||||||
|
self->val = in->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
BoolObject* BoolObject::create(bool in) {
|
||||||
|
NDO_CASTV(BoolObject, NDO->create("bool"), out)->val = alni(in);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoolObject::from_int(BoolObject* self, alni in) {
|
||||||
|
self->val = in;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoolObject::from_float(BoolObject* self, alnf in) {
|
||||||
|
self->val = alni(bool(in));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoolObject::from_string(BoolObject* self, String in) {
|
||||||
|
self->val = alni(bool(in));
|
||||||
|
}
|
||||||
|
|
||||||
|
String BoolObject::to_string(BoolObject* self) {
|
||||||
|
return String(bool(self->val));
|
||||||
|
}
|
||||||
|
|
||||||
|
alni BoolObject::to_int(BoolObject* self) {
|
||||||
|
return self->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
alnf BoolObject::to_float(BoolObject* self) {
|
||||||
|
return alnf(bool(self->val));
|
||||||
|
}
|
||||||
|
|
||||||
|
static alni save_size(BoolObject* self) {
|
||||||
|
return sizeof(alni);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void save(BoolObject* self, Archiver& file_self) {
|
||||||
|
file_self.write<alni>(&self->val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load(Archiver& file_self, BoolObject* self) {
|
||||||
|
file_self.read<alni>(&self->val);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ObjectTypeConversions BoolObjectTypeConversions = {
|
||||||
|
.from_int = (object_from_int) BoolObject::from_int,
|
||||||
|
.from_float = (object_from_float) BoolObject::from_float,
|
||||||
|
.from_string = (object_from_string) BoolObject::from_string,
|
||||||
|
.to_string = (object_to_string) BoolObject::to_string,
|
||||||
|
.to_int = (object_to_int) BoolObject::to_int,
|
||||||
|
.to_float = (object_to_float) BoolObject::to_float,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct obj::ObjectType obj::BoolObject::TypeData = {
|
||||||
|
.base = NULL,
|
||||||
|
.constructor = (object_constructor) BoolObject::constructor,
|
||||||
|
.destructor = NULL,
|
||||||
|
.copy = (object_copy) BoolObject::copy,
|
||||||
|
.size = sizeof(BoolObject),
|
||||||
|
.name = "bool",
|
||||||
|
.convesions = &BoolObjectTypeConversions,
|
||||||
|
.save_size = (object_save_size)save_size,
|
||||||
|
.save = (object_save)save,
|
||||||
|
.load = (object_load)load,
|
||||||
|
};
|
||||||
81
Objects/private/primitives/classobject.cpp
Normal file
81
Objects/private/primitives/classobject.cpp
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
|
||||||
|
#include "primitives/classobject.h"
|
||||||
|
#include "primitives/dictobject.h"
|
||||||
|
#include "primitives/nullobject.h"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
void ClassObject::constructor(ClassObject* self) {
|
||||||
|
self->members = NDO_CAST(DictObject, NDO->create("dict"));
|
||||||
|
|
||||||
|
self->addMember(NDO_NULL, "__init__");
|
||||||
|
self->addMember(NDO_NULL, "__del__");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassObject::copy(ClassObject* self, const ClassObject* blueprint) {
|
||||||
|
NDO->copy(self->members, blueprint->members);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassObject::destructor(ClassObject* self) {
|
||||||
|
NDO->destroy(self->members);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassObject::addMember(Object* obj, tp::String id) {
|
||||||
|
members->put(id, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassObject::createMember(tp::String type, tp::String id) {
|
||||||
|
auto newo = NDO->create(type);
|
||||||
|
members->put(id, newo);
|
||||||
|
}
|
||||||
|
|
||||||
|
alni ClassObject::save_size(ClassObject* self) {
|
||||||
|
return sizeof(alni); // dict object adress
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassObject::save(ClassObject* self, Archiver& file_self) {
|
||||||
|
// save dictobject
|
||||||
|
alni ndo_object_adress = NDO->save(file_self, self->members);
|
||||||
|
file_self.write<alni>(&ndo_object_adress);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassObject::load(Archiver& file_self, ClassObject* self) {
|
||||||
|
alni ndo_object_adress;
|
||||||
|
file_self.read<alni>(&ndo_object_adress);
|
||||||
|
self->members = NDO_CAST(DictObject, NDO->load(file_self, ndo_object_adress));
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::Buffer<Object*> childs_retrival(ClassObject* self) {
|
||||||
|
tp::Buffer<Object*> out;
|
||||||
|
out.append(self->members);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
alni allocated_size(ClassObject* self) {
|
||||||
|
return sizeof(DictObject*);
|
||||||
|
}
|
||||||
|
|
||||||
|
alni allocated_size_recursive(ClassObject* self) {
|
||||||
|
alni out = sizeof(DictObject*);
|
||||||
|
out += NDO->objsize_ram_recursive_util(self->members, self->members->type);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ObjectType ClassObject::TypeData = {
|
||||||
|
.base = NULL,
|
||||||
|
.constructor = (object_constructor) ClassObject::constructor,
|
||||||
|
.destructor = (object_destructor) ClassObject::destructor,
|
||||||
|
.copy = (object_copy) ClassObject::copy,
|
||||||
|
.size = sizeof(ClassObject),
|
||||||
|
.name = "class",
|
||||||
|
.save_size = (object_save_size)save_size,
|
||||||
|
.save = (object_save)save,
|
||||||
|
.load = (object_load)load,
|
||||||
|
.childs_retrival = (object_debug_all_childs_retrival) childs_retrival,
|
||||||
|
.allocated_size = (object_allocated_size) allocated_size,
|
||||||
|
.allocated_size_recursive = (object_allocated_size_recursive) allocated_size_recursive
|
||||||
|
};
|
||||||
84
Objects/private/primitives/colorobject.cpp
Normal file
84
Objects/private/primitives/colorobject.cpp
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
#include "primitives/colorobject.h"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
void ColorObject::constructor(Object* self) {
|
||||||
|
NDO_CAST(ColorObject, self)->mCol = tp::RGBA(1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ColorObject::copy(ColorObject* self, const ColorObject* in) {
|
||||||
|
self->mCol = in->mCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorObject* ColorObject::create(tp::RGBA in) {
|
||||||
|
NDO_CASTV(ColorObject, NDO->create("RGBA"), out)->mCol = in;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ColorObject::from_int(ColorObject* self, alni in) {
|
||||||
|
self->mCol = tp::RGBA((tp::halnf)tp::clamp(in, (tp::alni) 0, (tp::alni) 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ColorObject::from_float(ColorObject* self, alnf in) {
|
||||||
|
NDO_CAST(ColorObject, self)->mCol = tp::RGBA(tp::clamp((tp::halnf)in, 0.f, 1.f));
|
||||||
|
}
|
||||||
|
|
||||||
|
String ColorObject::to_string(ColorObject* self) {
|
||||||
|
// auto &col = NDO_CAST(ColorObject, self)->mCol;
|
||||||
|
// return tp::sfmt("%i:%i:%i:%i", (tp::alni) (col.r * 255), (tp::alni)(col.g * 255), (tp::alni)(col.b * 255), (tp::alni)(col.a * 255));
|
||||||
|
// TODO : implement
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static alni save_size(ColorObject* self) {
|
||||||
|
return sizeof(tp::RGBA);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void save(ColorObject* self, Archiver& file_self) {
|
||||||
|
file_self.write<tp::RGBA>(&self->mCol);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load(Archiver& file_self, ColorObject* self) {
|
||||||
|
file_self.read<tp::RGBA>(&self->mCol);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ObjectTypeConversions ColorObjectTypeConversions = {
|
||||||
|
.from_int = (object_from_int) ColorObject::from_int,
|
||||||
|
.from_float = (object_from_float) ColorObject::from_float,
|
||||||
|
.from_string = NULL,
|
||||||
|
.to_string = (object_to_string) ColorObject::to_string,
|
||||||
|
.to_int = NULL,
|
||||||
|
.to_float = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
void sub(ColorObject* self, ColorObject* in) {
|
||||||
|
self->mCol = in->mCol - self->mCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(ColorObject* self, ColorObject* in) {
|
||||||
|
self->mCol = in->mCol + self->mCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ObjectTypeAriphmetics ColorObject::TypeAriphm = {
|
||||||
|
.add = (object_add) add,
|
||||||
|
.sub = (object_sub) sub,
|
||||||
|
.mul = (object_mul) NULL,
|
||||||
|
.div = (object_div) NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct obj::ObjectType obj::ColorObject::TypeData = {
|
||||||
|
.base = NULL,
|
||||||
|
.constructor = ColorObject::constructor,
|
||||||
|
.destructor = NULL,
|
||||||
|
.copy = (object_copy) ColorObject::copy,
|
||||||
|
.size = sizeof(ColorObject),
|
||||||
|
.name = "RGBA",
|
||||||
|
.convesions = &ColorObjectTypeConversions,
|
||||||
|
.ariphmetics = &ColorObject::TypeAriphm,
|
||||||
|
.save_size = (object_save_size)save_size,
|
||||||
|
.save = (object_save)save,
|
||||||
|
.load = (object_load)load,
|
||||||
|
};
|
||||||
232
Objects/private/primitives/dictobject.cpp
Normal file
232
Objects/private/primitives/dictobject.cpp
Normal file
|
|
@ -0,0 +1,232 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
|
||||||
|
#include "primitives/dictobject.h"
|
||||||
|
#include "primitives/stringobject.h"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
void DictObject::constructor(Object* self) {
|
||||||
|
NDO_CASTV(DictObject, self, dict);
|
||||||
|
|
||||||
|
new (&dict->items) Map<String, Object*>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DictObject::copy(Object* in, const Object* target) {
|
||||||
|
NDO_CASTV(DictObject, in, self);
|
||||||
|
NDO_CASTV(DictObject, target, src);
|
||||||
|
|
||||||
|
destructor(self);
|
||||||
|
constructor(self);
|
||||||
|
|
||||||
|
for (auto item : src->items) {
|
||||||
|
auto instance = NDO->instatiate(item->val);
|
||||||
|
self->items.put(item->key, instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DictObject::destructor(Object* self) {
|
||||||
|
NDO_CASTV(DictObject, self, dict);
|
||||||
|
for (auto item : dict->items) {
|
||||||
|
NDO->destroy(item->val);
|
||||||
|
}
|
||||||
|
dict->items.~Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
alni DictObject::save_size(DictObject* self) {
|
||||||
|
// calculate size needed
|
||||||
|
alni save_size = 0;
|
||||||
|
|
||||||
|
// number on entries
|
||||||
|
save_size += sizeof(alni);
|
||||||
|
|
||||||
|
for (auto item : self->items) {
|
||||||
|
// string length
|
||||||
|
save_size += (item->key.size() + 1) * sizeof(*item->key.read());
|
||||||
|
// object file adress
|
||||||
|
save_size += sizeof(alni);
|
||||||
|
}
|
||||||
|
|
||||||
|
return save_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DictObject::save(DictObject* self, Archiver& file_self) {
|
||||||
|
|
||||||
|
// write size
|
||||||
|
alni len = self->items.size();
|
||||||
|
file_self.write<alni>(&len);
|
||||||
|
|
||||||
|
// save hashmap pairs
|
||||||
|
for (auto item : self->items) {
|
||||||
|
// item val
|
||||||
|
alni ndo_object_adress = NDO->save(file_self, item->val);
|
||||||
|
file_self.write<alni>(&ndo_object_adress);
|
||||||
|
|
||||||
|
// item key
|
||||||
|
item->key.save(&file_self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DictObject::load(Archiver& file_self, DictObject* self) {
|
||||||
|
new (&self->items) tp::Map<tp::String, Object*>();
|
||||||
|
|
||||||
|
alni len;
|
||||||
|
file_self.read<alni>(&len);
|
||||||
|
|
||||||
|
for (alni i = 0; i < len; i++) {
|
||||||
|
|
||||||
|
// read val
|
||||||
|
alni ndo_object_adress;
|
||||||
|
file_self.read<alni>(&ndo_object_adress);
|
||||||
|
Object* val = NDO->load(file_self, ndo_object_adress);
|
||||||
|
|
||||||
|
// read key value
|
||||||
|
String key;
|
||||||
|
key.load(&file_self);
|
||||||
|
|
||||||
|
// add to dictinary
|
||||||
|
self->items.put(key, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::Buffer<Object*> DictObject::childs_retrival(DictObject* self) {
|
||||||
|
tp::Buffer<Object*> out;
|
||||||
|
out.reserve(self->items.size());
|
||||||
|
ualni i = 0;
|
||||||
|
for (auto item : self->items) {
|
||||||
|
out[i] = item->val;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
alni DictObject::allocated_size(DictObject* self) {
|
||||||
|
alni out = self->items.sizeAllocatedMem();
|
||||||
|
for (auto item : self->items) {
|
||||||
|
out += item->key.sizeAllocatedMem();
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
alni DictObject::allocated_size_recursive(DictObject* self) {
|
||||||
|
alni out = allocated_size(self);
|
||||||
|
for (auto item : self->items) {
|
||||||
|
out += NDO->objsize_ram_recursive_util(item->val, item->val->type);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DictObject::put(tp::String str, Object* obj) {
|
||||||
|
DEBUG_ASSERT(obj);
|
||||||
|
NDO->refinc(obj);
|
||||||
|
items.put(str, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DictObject::remove(tp::String str) {
|
||||||
|
auto idx = items.presents(str);
|
||||||
|
if (idx) {
|
||||||
|
NDO->destroy(items.getSlotVal(idx));
|
||||||
|
items.remove(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object* DictObject::get(tp::String str) {
|
||||||
|
return items.get(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::Map<tp::String, Object*>::Idx DictObject::presents(tp::String str) {
|
||||||
|
return items.presents(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object* DictObject::getSlotVal(tp::alni idx) {
|
||||||
|
return items.getSlotVal(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
const tp::Map<tp::String, Object*>& DictObject::getItems() const {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto tm_get = TypeMethod{
|
||||||
|
.nameid = "get",
|
||||||
|
.descr = "gets the object",
|
||||||
|
.args = {
|
||||||
|
{ "str key", NULL }
|
||||||
|
},
|
||||||
|
.exec = [](const TypeMethod* tm) {
|
||||||
|
auto const self = (DictObject*)tm->self;
|
||||||
|
auto str_key = tm->args[0].obj;
|
||||||
|
|
||||||
|
NDO_CASTV(StringObject, str_key, key);
|
||||||
|
ASSERT(key);
|
||||||
|
|
||||||
|
auto idx = self->presents(key->val);
|
||||||
|
if (idx) {
|
||||||
|
tm->ret.obj = self->getSlotVal(idx);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.ret = { "object", NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static auto tm_put = TypeMethod{
|
||||||
|
.nameid = "put",
|
||||||
|
.descr = "puts the object into the dictinary",
|
||||||
|
.args = {
|
||||||
|
{ "key", NULL },
|
||||||
|
{ "object", NULL }
|
||||||
|
},
|
||||||
|
.exec = [](const TypeMethod* tm) {
|
||||||
|
auto const self = (DictObject*)tm->self;
|
||||||
|
|
||||||
|
auto str_key = tm->args[0].obj;
|
||||||
|
auto obj = tm->args[1].obj;
|
||||||
|
|
||||||
|
NDO_CASTV(StringObject, str_key, key);
|
||||||
|
ASSERT(key);
|
||||||
|
|
||||||
|
self->put(key->val, obj);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static auto tm_remove = TypeMethod{
|
||||||
|
.nameid = "remove",
|
||||||
|
.descr = "remove the object from the dictinary",
|
||||||
|
.args = {
|
||||||
|
{ "key", NULL },
|
||||||
|
},
|
||||||
|
.exec = [](const TypeMethod* tm) {
|
||||||
|
auto const self = (DictObject*)tm->self;
|
||||||
|
|
||||||
|
auto str_key = tm->args[0].obj;
|
||||||
|
|
||||||
|
NDO_CASTV(StringObject, str_key, key);
|
||||||
|
ASSERT(key);
|
||||||
|
|
||||||
|
self->remove(key->val);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
struct obj::ObjectType DictObject::TypeData = {
|
||||||
|
.base = NULL,
|
||||||
|
.constructor = DictObject::constructor,
|
||||||
|
.destructor = DictObject::destructor,
|
||||||
|
.copy = DictObject::copy,
|
||||||
|
.size = sizeof(DictObject),
|
||||||
|
.name = "dict",
|
||||||
|
.save_size = (object_save_size)DictObject::save_size,
|
||||||
|
.save = (object_save)DictObject::save,
|
||||||
|
.load = (object_load)DictObject::load,
|
||||||
|
.childs_retrival = (object_debug_all_childs_retrival)DictObject::childs_retrival,
|
||||||
|
.allocated_size = (object_allocated_size)DictObject::allocated_size,
|
||||||
|
.allocated_size_recursive = (object_allocated_size_recursive)DictObject::allocated_size_recursive,
|
||||||
|
|
||||||
|
.type_methods = {
|
||||||
|
.methods = {
|
||||||
|
&tm_put,
|
||||||
|
&tm_remove,
|
||||||
|
&tm_get,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
182
Objects/private/primitives/enumobject.cpp
Normal file
182
Objects/private/primitives/enumobject.cpp
Normal file
|
|
@ -0,0 +1,182 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
#include "primitives/enumobject.h"
|
||||||
|
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
void EnumObject::constructor(EnumObject* self) {
|
||||||
|
self->active = 0;
|
||||||
|
self->nentries = 0;
|
||||||
|
self->entries = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void obj::EnumObject::destructor(EnumObject* self) {
|
||||||
|
if (self->entries) free(self->entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnumObject::copy(EnumObject* self, const EnumObject* in) {
|
||||||
|
if (self->entries) free(self->entries);
|
||||||
|
self->active = in->active;
|
||||||
|
self->nentries = in->nentries;
|
||||||
|
|
||||||
|
self->entries = (alni*)malloc(self->nentries * ENV_ALNI_SIZE_B);
|
||||||
|
tp::memCopy(self->entries, in->entries, self->nentries * ENV_ALNI_SIZE_B);
|
||||||
|
}
|
||||||
|
|
||||||
|
void obj::EnumObject::init(tp::init_list<const char*> list) {
|
||||||
|
|
||||||
|
if (entries) free(entries);
|
||||||
|
|
||||||
|
active = 0;
|
||||||
|
nentries = (uhalni) list.size();
|
||||||
|
entries = (alni*) malloc(nentries * ENV_ALNI_SIZE_B);
|
||||||
|
tp::memSetVal(entries, nentries * ENV_ALNI_SIZE_B, 0);
|
||||||
|
|
||||||
|
alni* entry = entries;
|
||||||
|
for (auto elem : list) {
|
||||||
|
|
||||||
|
alni len = tp::String::Logic::calcLength(elem);
|
||||||
|
if (len > ENV_ALNI_SIZE_B - 1) len = ENV_ALNI_SIZE_B - 1;
|
||||||
|
|
||||||
|
tp::memCopy(entry, elem, len);
|
||||||
|
|
||||||
|
for (alni* chech_entry = entries; chech_entry != entry; chech_entry++) {
|
||||||
|
DEBUG_ASSERT(tp::memCompare(chech_entry, entry, ENV_ALNI_SIZE_B) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
entry++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* obj::EnumObject::getActiveName() {
|
||||||
|
return getItemName(active);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* obj::EnumObject::getItemName(tp::uhalni idx) {
|
||||||
|
DEBUG_ASSERT(entries && idx >= 0 && idx < nentries);
|
||||||
|
return (const char*) (entries + idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EnumObject::from_int(EnumObject* self, alni in) {
|
||||||
|
if (self->entries && in >= 0 && in < self->nentries) {
|
||||||
|
self->active = uhalni(in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnumObject::from_float(EnumObject* self, alnf in) {
|
||||||
|
if (self->entries && in >= 0 && in < self->nentries) {
|
||||||
|
self->active = uhalni(in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnumObject::from_string(EnumObject* self, String in) {
|
||||||
|
if (self->entries) {
|
||||||
|
alni* entry = self->entries;
|
||||||
|
for (uhalni i = 0; i < self->nentries; i++) {
|
||||||
|
if (tp::String::Logic::isEqualLogic((const char*)entry, in.read())) {
|
||||||
|
self->active = i;
|
||||||
|
}
|
||||||
|
entry += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String EnumObject::to_string(EnumObject* self) {
|
||||||
|
if (!self->entries) {
|
||||||
|
return tp::String();
|
||||||
|
}
|
||||||
|
auto val = (const char*)(&self->entries[self->active]);
|
||||||
|
return String(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
alni EnumObject::to_int(EnumObject* self) {
|
||||||
|
if (!self->entries) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return alni(self->active);
|
||||||
|
}
|
||||||
|
|
||||||
|
alnf EnumObject::to_float(EnumObject* self) {
|
||||||
|
if (!self->entries) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return alnf(self->active);
|
||||||
|
}
|
||||||
|
|
||||||
|
static alni save_size(EnumObject* self) {
|
||||||
|
if (!self->entries) {
|
||||||
|
return sizeof(uhalni);
|
||||||
|
}
|
||||||
|
return sizeof(uhalni) + sizeof(uhalni) + sizeof(alni) * self->nentries;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void save(EnumObject* self, Archiver& file_self) {
|
||||||
|
if (!self->entries) {
|
||||||
|
uhalni empty_code = -1;
|
||||||
|
file_self.write<uhalni>(&empty_code);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
file_self.write<uhalni>(&self->active);
|
||||||
|
file_self.write<uhalni>(&self->nentries);
|
||||||
|
file_self.write_bytes((tp::int1*) self->entries, self->nentries * ENV_ALNI_SIZE_B);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load(Archiver& file_self, EnumObject* self) {
|
||||||
|
file_self.read<uhalni>(&self->active);
|
||||||
|
if (self->active == -1) {
|
||||||
|
self->nentries = 0;
|
||||||
|
self->entries = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
file_self.read<uhalni>(&self->nentries);
|
||||||
|
self->entries = (alni*) malloc(self->nentries * ENV_ALNI_SIZE_B);
|
||||||
|
file_self.read_bytes((tp::int1*) self->entries, self->nentries * ENV_ALNI_SIZE_B);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool obj::EnumObject::compare(EnumObject* first, EnumObject* second) {
|
||||||
|
return first->entries != NULL && second->entries != NULL && first->active == second->active;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnumObject* obj::EnumObject::create(tp::init_list<const char*> list) {
|
||||||
|
auto enum_object = (EnumObject*)obj::NDO->create("enum");
|
||||||
|
enum_object->init(list);
|
||||||
|
return enum_object;
|
||||||
|
}
|
||||||
|
|
||||||
|
alni allocated_size(EnumObject* self) {
|
||||||
|
alni out = sizeof(uhalni) * 2 + sizeof(tp::alni*);
|
||||||
|
if (self->entries) {
|
||||||
|
out += self->nentries * sizeof(alni) * 2;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ObjectTypeConversions EnumObjectTypeConversions = {
|
||||||
|
.from_int = (object_from_int) EnumObject::from_int,
|
||||||
|
.from_float = (object_from_float) EnumObject::from_float,
|
||||||
|
.from_string = (object_from_string) EnumObject::from_string,
|
||||||
|
.to_string = (object_to_string) EnumObject::to_string,
|
||||||
|
.to_int = (object_to_int) EnumObject::to_int,
|
||||||
|
.to_float = (object_to_float) EnumObject::to_float,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct obj::ObjectType obj::EnumObject::TypeData = {
|
||||||
|
.base = NULL,
|
||||||
|
.constructor = (object_constructor) EnumObject::constructor,
|
||||||
|
.destructor = (object_destructor) EnumObject::destructor,
|
||||||
|
.copy = (object_copy) EnumObject::copy,
|
||||||
|
.size = sizeof(EnumObject),
|
||||||
|
.name = "enum",
|
||||||
|
.convesions = &EnumObjectTypeConversions,
|
||||||
|
.save_size = (object_save_size)save_size,
|
||||||
|
.save = (object_save)save,
|
||||||
|
.load = (object_load)load,
|
||||||
|
.comparison = (object_compare) EnumObject::compare,
|
||||||
|
.allocated_size = (object_allocated_size) allocated_size,
|
||||||
|
};
|
||||||
102
Objects/private/primitives/floatobject.cpp
Normal file
102
Objects/private/primitives/floatobject.cpp
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
#include "primitives/floatobject.h"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
void FloatObject::constructor(FloatObject* self) {
|
||||||
|
self->val = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloatObject::copy(FloatObject* self, const FloatObject* in) {
|
||||||
|
self->val = in->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatObject* FloatObject::create(alnf in) {
|
||||||
|
NDO_CASTV(FloatObject, NDO->create("float"), out)->val = alnf(in);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloatObject::from_int(FloatObject* self, alni in) {
|
||||||
|
self->val = alnf(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloatObject::from_float(FloatObject* self, alnf in) {
|
||||||
|
self->val = in;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloatObject::from_string(FloatObject* self, String in) {
|
||||||
|
self->val = alnf(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
String FloatObject::to_string(FloatObject* self) {
|
||||||
|
return String(self->val);
|
||||||
|
}
|
||||||
|
|
||||||
|
alni FloatObject::to_int(FloatObject* self) {
|
||||||
|
return alni(self->val);
|
||||||
|
}
|
||||||
|
|
||||||
|
alnf FloatObject::to_float(FloatObject* self) {
|
||||||
|
return self->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static alni save_size(FloatObject* self) {
|
||||||
|
return sizeof(alnf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void save(FloatObject* self, Archiver& file_self) {
|
||||||
|
file_self.write<alnf>(&self->val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load(Archiver& file_self, FloatObject* self) {
|
||||||
|
file_self.read<alnf>(&self->val);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ObjectTypeConversions FloatObjectTypeConversions = {
|
||||||
|
.from_int = (object_from_int) FloatObject::from_int,
|
||||||
|
.from_float = (object_from_float) FloatObject::from_float,
|
||||||
|
.from_string = (object_from_string) FloatObject::from_string,
|
||||||
|
.to_string = (object_to_string) FloatObject::to_string,
|
||||||
|
.to_int = (object_to_int) FloatObject::to_int,
|
||||||
|
.to_float = (object_to_float) FloatObject::to_float,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void mul(FloatObject* self, FloatObject* in) {
|
||||||
|
self->val *= in->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sub(FloatObject* self, FloatObject* in) {
|
||||||
|
self->val -= in->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add(FloatObject* self, FloatObject* in) {
|
||||||
|
self->val += in->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void divide(FloatObject* self, FloatObject* in) {
|
||||||
|
self->val /= in->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ObjectTypeAriphmetics FloatObject::TypeAriphm = {
|
||||||
|
.add = (object_add)add,
|
||||||
|
.sub = (object_sub)sub,
|
||||||
|
.mul = (object_mul)mul,
|
||||||
|
.div = (object_div)divide,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct obj::ObjectType obj::FloatObject::TypeData = {
|
||||||
|
.base = NULL,
|
||||||
|
.constructor = (object_constructor) FloatObject::constructor,
|
||||||
|
.destructor = NULL,
|
||||||
|
.copy = (object_copy) FloatObject::copy,
|
||||||
|
.size = sizeof(FloatObject),
|
||||||
|
.name = "float",
|
||||||
|
.convesions = &FloatObjectTypeConversions,
|
||||||
|
.ariphmetics = &FloatObject::TypeAriphm,
|
||||||
|
.save_size = (object_save_size) save_size,
|
||||||
|
.save = (object_save) save,
|
||||||
|
.load = (object_load) load,
|
||||||
|
};
|
||||||
82
Objects/private/primitives/interpreterobject.cpp
Normal file
82
Objects/private/primitives/interpreterobject.cpp
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
|
||||||
|
#include "primitives/interpreterobject.h"
|
||||||
|
#include "primitives/linkobject.h"
|
||||||
|
#include "primitives/methodobject.h"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
void InterpreterObject::constructor(InterpreterObject* self) {
|
||||||
|
new (&self->mInterpreter) Interpreter();
|
||||||
|
|
||||||
|
self->createMember("dict", "globals");
|
||||||
|
self->createMember("link", "target method");
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterpreterObject::destructor(InterpreterObject* self) {
|
||||||
|
self->mInterpreter.~Interpreter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterpreterObject::load(Archiver& file_self, InterpreterObject* self) {
|
||||||
|
new (&self->mInterpreter) Interpreter();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InterpreterObject::running() { return !mInterpreter.finished(); }
|
||||||
|
|
||||||
|
void InterpreterObject::exec(obj::ClassObject* self, tp::init_list<Interpreter::GlobalDef> globals) {
|
||||||
|
|
||||||
|
if (running()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto link_target = getMember<obj::LinkObject>("target method");
|
||||||
|
if (!link_target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto target = link_target->getLink();
|
||||||
|
if (!target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NDO_CASTV(obj::MethodObject, target, method);
|
||||||
|
if (!method || !method->mScript->mBytecode.mInstructions.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mInterpreter.execAll(method, self, getMember<obj::DictObject>("globals"), globals);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterpreterObject::debug() {
|
||||||
|
if (running()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto link_target = getMember<obj::LinkObject>("target method");
|
||||||
|
if (!link_target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto target = link_target->getLink();
|
||||||
|
if (!target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NDO_CASTV(obj::MethodObject, target, method);
|
||||||
|
if (!method || !method->mScript->mBytecode.mInstructions.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mInterpreter.exec(method, this, getMember<obj::DictObject>("globals"));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct obj::ObjectType InterpreterObject::TypeData = {
|
||||||
|
.base = &ClassObject::TypeData,
|
||||||
|
.constructor = (object_constructor)InterpreterObject::constructor,
|
||||||
|
.destructor = (object_destructor)InterpreterObject::destructor,
|
||||||
|
.size = sizeof(InterpreterObject),
|
||||||
|
.name = "interpreter",
|
||||||
|
.load = (object_load)InterpreterObject::load,
|
||||||
|
};
|
||||||
104
Objects/private/primitives/intobject.cpp
Normal file
104
Objects/private/primitives/intobject.cpp
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
|
||||||
|
#include "primitives/intobject.h"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
void IntObject::constructor(Object* self) {
|
||||||
|
NDO_CAST(IntObject, self)->val = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntObject::copy(IntObject* self, const IntObject* in) {
|
||||||
|
self->val = in->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
IntObject* IntObject::create(alni in) {
|
||||||
|
NDO_CASTV(IntObject, NDO->create("int"), out)->val = in;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntObject::from_int(Object* self, alni in) {
|
||||||
|
NDO_CAST(IntObject, self)->val = in;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntObject::from_float(Object* self, alnf in) {
|
||||||
|
NDO_CAST(IntObject, self)->val = (alni)in;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntObject::from_string(Object* self, String in) {
|
||||||
|
NDO_CAST(IntObject, self)->val = alni(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
String IntObject::to_string(Object* self) {
|
||||||
|
return String(NDO_CAST(IntObject, self)->val);
|
||||||
|
}
|
||||||
|
|
||||||
|
alni IntObject::to_int(Object* self) {
|
||||||
|
return alni(NDO_CAST(IntObject, self)->val);
|
||||||
|
}
|
||||||
|
|
||||||
|
alnf IntObject::to_float(Object* self) {
|
||||||
|
return alnf(NDO_CAST(IntObject, self)->val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static alni save_size(IntObject* self) {
|
||||||
|
return sizeof(alni);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void save(IntObject* self, Archiver& file_self) {
|
||||||
|
file_self.write<alni>(&self->val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load(Archiver& file_self, IntObject* self) {
|
||||||
|
file_self.read<alni>(&self->val);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ObjectTypeConversions IntObjectTypeConversions = {
|
||||||
|
.from_int = IntObject::from_int,
|
||||||
|
.from_float = IntObject::from_float,
|
||||||
|
.from_string = IntObject::from_string,
|
||||||
|
.to_string = IntObject::to_string,
|
||||||
|
.to_int = IntObject::to_int,
|
||||||
|
.to_float = IntObject::to_float,
|
||||||
|
};
|
||||||
|
|
||||||
|
void divide(IntObject* self, IntObject* in) {
|
||||||
|
self->val /= in->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mul(IntObject* self, IntObject* in) {
|
||||||
|
self->val *= in->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sub(IntObject* self, IntObject* in) {
|
||||||
|
self->val -= in->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(IntObject* self, IntObject* in) {
|
||||||
|
self->val += in->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ObjectTypeAriphmetics IntObject::TypeAriphm = {
|
||||||
|
.add = (object_add) add,
|
||||||
|
.sub = (object_sub) sub,
|
||||||
|
.mul = (object_mul) mul,
|
||||||
|
.div = (object_div) divide,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct obj::ObjectType obj::IntObject::TypeData = {
|
||||||
|
.base = NULL,
|
||||||
|
.constructor = IntObject::constructor,
|
||||||
|
.destructor = NULL,
|
||||||
|
.copy = (object_copy) IntObject::copy,
|
||||||
|
.size = sizeof(IntObject),
|
||||||
|
.name = "int",
|
||||||
|
.convesions = &IntObjectTypeConversions,
|
||||||
|
.ariphmetics = &IntObject::TypeAriphm,
|
||||||
|
.save_size = (object_save_size)save_size,
|
||||||
|
.save = (object_save)save,
|
||||||
|
.load = (object_load)load,
|
||||||
|
};
|
||||||
132
Objects/private/primitives/linkobject.cpp
Normal file
132
Objects/private/primitives/linkobject.cpp
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
#include "primitives/linkobject.h"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
void LinkObject::constructor(Object* self) {
|
||||||
|
NDO_CAST(LinkObject, self)->link = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinkObject::destructor(LinkObject* self) {
|
||||||
|
if (self->link) NDO->destroy(self->link);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinkObject::copy(Object* self, const Object* in) {
|
||||||
|
NDO_CAST(LinkObject, self)->setLink(NDO_CAST(LinkObject, in)->link);
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkObject* LinkObject::create(Object* in) {
|
||||||
|
NDO_CASTV(LinkObject, NDO->create("link"), out)->link = in;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
alni LinkObject::save_size(LinkObject* self) {
|
||||||
|
return sizeof(alni);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinkObject::save(LinkObject* self, Archiver& file_self) {
|
||||||
|
if (self->link != NULL) {
|
||||||
|
alni link_object_save_adress = NDO->save(file_self, self->link);
|
||||||
|
file_self.write<alni>(&link_object_save_adress);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
alni null = -1;
|
||||||
|
file_self.write<alni>(&null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinkObject::load(Archiver& file_self, LinkObject* self) {
|
||||||
|
|
||||||
|
alni saved_object_adress;
|
||||||
|
file_self.read<alni>(&saved_object_adress);
|
||||||
|
|
||||||
|
if (saved_object_adress == -1) {
|
||||||
|
self->link = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self->link = NDO->load(file_self, saved_object_adress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::Buffer<Object*> LinkObject::childs_retrival(LinkObject* self) {
|
||||||
|
tp::Buffer<Object*> out;
|
||||||
|
if (self->link) out.append(self->link);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
alni LinkObject::allocated_size(LinkObject* self) {
|
||||||
|
return sizeof(Object*);
|
||||||
|
}
|
||||||
|
|
||||||
|
alni LinkObject::allocated_size_recursive(LinkObject* self) {
|
||||||
|
alni out = sizeof(Object*);
|
||||||
|
if (self->link) {
|
||||||
|
out += NDO->objsize_ram_recursive_util(self->link, self->link->type);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object* LinkObject::getLink() {
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinkObject::setLink(Object* obj) {
|
||||||
|
#ifdef OBJECT_REF_COUNT
|
||||||
|
if (link) NDO->destroy(link);
|
||||||
|
if (obj) NDO->refinc(obj);
|
||||||
|
#endif // OBJECT_REF_COUNT
|
||||||
|
link = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto tm_set = TypeMethod{
|
||||||
|
.nameid = "set",
|
||||||
|
.descr = "sets the link",
|
||||||
|
.args = {
|
||||||
|
{ "target", NULL }
|
||||||
|
},
|
||||||
|
.exec = [](const TypeMethod* tm) {
|
||||||
|
auto const self = (LinkObject*)tm->self;
|
||||||
|
auto const target = tm->args[0].obj;
|
||||||
|
self->setLink(target);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static auto tm_get = TypeMethod{
|
||||||
|
.nameid = "get",
|
||||||
|
.descr = "gets the link",
|
||||||
|
.exec = [](const TypeMethod* tm) {
|
||||||
|
auto const self = (LinkObject*)tm->self;
|
||||||
|
auto link = self->getLink();
|
||||||
|
if (link) {
|
||||||
|
tm->ret.obj = link;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.ret = { "the link", NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct obj::ObjectType LinkObject::TypeData = {
|
||||||
|
.base = NULL,
|
||||||
|
.constructor = LinkObject::constructor,
|
||||||
|
.destructor = (object_destructor)LinkObject::destructor,
|
||||||
|
.copy = LinkObject::copy,
|
||||||
|
.size = sizeof(LinkObject),
|
||||||
|
.name = "link",
|
||||||
|
.convesions = NULL,
|
||||||
|
.save_size = (object_save_size)LinkObject::save_size,
|
||||||
|
.save = (object_save)LinkObject::save,
|
||||||
|
.load = (object_load)LinkObject::load,
|
||||||
|
.childs_retrival = (object_debug_all_childs_retrival)LinkObject::childs_retrival,
|
||||||
|
.allocated_size = (object_allocated_size)LinkObject::allocated_size,
|
||||||
|
.allocated_size_recursive = (object_allocated_size_recursive)LinkObject::allocated_size_recursive,
|
||||||
|
|
||||||
|
.type_methods = {
|
||||||
|
.methods = {
|
||||||
|
&tm_set,
|
||||||
|
&tm_get,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
135
Objects/private/primitives/listobject.cpp
Normal file
135
Objects/private/primitives/listobject.cpp
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
|
||||||
|
#include "primitives/listobject.h"
|
||||||
|
#include "primitives/intobject.h"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
void ListObject::constructor(Object* in) {
|
||||||
|
NDO_CASTV(ListObject, in, self);
|
||||||
|
new (&self->items) List<Object*>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListObject::copy(Object* in, const Object* target) {
|
||||||
|
NDO_CASTV(ListObject, in, self);
|
||||||
|
NDO_CASTV(ListObject, target, src);
|
||||||
|
|
||||||
|
destructor(in);
|
||||||
|
|
||||||
|
for (auto item : src->items) {
|
||||||
|
self->pushBack(NDO->instatiate(item.data()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListObject::destructor(Object* in) {
|
||||||
|
NDO_CASTV(ListObject, in, self);
|
||||||
|
for (auto item : self->items) {
|
||||||
|
NDO->destroy(item.data());
|
||||||
|
}
|
||||||
|
self->items.removeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
alni ListObject::save_size(ListObject* self) {
|
||||||
|
alni len = self->items.length();
|
||||||
|
return (len + 1) * sizeof(alni);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListObject::save(ListObject* self, Archiver& file_self) {
|
||||||
|
alni len = self->items.length();
|
||||||
|
file_self.write<alni>(&len);
|
||||||
|
|
||||||
|
for (auto item : self->items) {
|
||||||
|
alni ndo_object_adress = NDO->save(file_self, item.data());
|
||||||
|
file_self.write<alni>(&ndo_object_adress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListObject::load(Archiver& file_self, ListObject* self) {
|
||||||
|
new (&self->items) tp::List<Object*>();
|
||||||
|
|
||||||
|
alni len;
|
||||||
|
file_self.read<alni>(&len);
|
||||||
|
|
||||||
|
for (alni i = 0; i < len; i++) {
|
||||||
|
alni ndo_object_adress;
|
||||||
|
file_self.read<alni>(&ndo_object_adress);
|
||||||
|
self->items.pushBack(NDO->load(file_self, ndo_object_adress));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::Buffer<Object*> ListObject::childs_retrival(ListObject* self) {
|
||||||
|
tp::Buffer<Object*> out;
|
||||||
|
out.reserve(self->items.length());
|
||||||
|
ualni i = 0;
|
||||||
|
for (auto item : self->items) {
|
||||||
|
out[i] = item.data();
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
alni ListObject::allocated_size(ListObject* self) {
|
||||||
|
// return self->items.sizeAllocatedMem();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
alni ListObject::allocated_size_recursive(ListObject* self) {
|
||||||
|
alni out = self->items.sizeAllocatedMem();
|
||||||
|
for (auto item : self->items) {
|
||||||
|
out += NDO->objsize_ram_recursive_util(item.data(), item->type);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListObject::pushBack(Object* obj) {
|
||||||
|
#ifdef OBJECT_REF_COUNT
|
||||||
|
obj::NDO->refinc(obj);
|
||||||
|
#endif // OBJECT_REF_COUNT
|
||||||
|
items.pushBack(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListObject::pushFront(Object* obj) {
|
||||||
|
#ifdef OBJECT_REF_COUNT
|
||||||
|
obj::NDO->refinc(obj);
|
||||||
|
#endif // OBJECT_REF_COUNT
|
||||||
|
items.pushFront(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListObject::delNode(tp::List<Object*>::Node* node) {
|
||||||
|
#ifdef OBJECT_REF_COUNT
|
||||||
|
obj::NDO->destroy(node->data);
|
||||||
|
#endif // OBJECT_REF_COUNT
|
||||||
|
items.deleteNode(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListObject::popBack() {
|
||||||
|
#ifdef OBJECT_REF_COUNT
|
||||||
|
auto obj = items.last();
|
||||||
|
if (obj) obj::NDO->destroy(obj->data);
|
||||||
|
#endif // OBJECT_REF_COUNT
|
||||||
|
items.popBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
const tp::List<Object*>& ListObject::getItems() const {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct obj::ObjectType obj::ListObject::TypeData = {
|
||||||
|
.base = NULL,
|
||||||
|
.constructor = ListObject::constructor,
|
||||||
|
.destructor = ListObject::destructor,
|
||||||
|
.copy = ListObject::copy,
|
||||||
|
.size = sizeof(ListObject),
|
||||||
|
.name = "list",
|
||||||
|
.convesions = NULL,
|
||||||
|
.save_size = (object_save_size)save_size,
|
||||||
|
.save = (object_save)save,
|
||||||
|
.load = (object_load)load,
|
||||||
|
.childs_retrival = (object_debug_all_childs_retrival) childs_retrival,
|
||||||
|
.allocated_size = (object_allocated_size) allocated_size,
|
||||||
|
.allocated_size_recursive = (object_allocated_size_recursive) allocated_size_recursive
|
||||||
|
};
|
||||||
78
Objects/private/primitives/methodobject.cpp
Normal file
78
Objects/private/primitives/methodobject.cpp
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
|
||||||
|
#include "primitives/methodobject.h"
|
||||||
|
#include "core/scriptsection.h"
|
||||||
|
#include "compiler/function.h"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
|
||||||
|
struct ObjectType MethodObject::TypeData = {
|
||||||
|
.base = NULL,
|
||||||
|
.constructor = (object_constructor)MethodObject::constructor,
|
||||||
|
.destructor = (object_destructor)MethodObject::destructor,
|
||||||
|
.copy = (object_copy)MethodObject::copy,
|
||||||
|
.size = sizeof(MethodObject),
|
||||||
|
.name = "method",
|
||||||
|
.convesions = NULL,
|
||||||
|
.save_size = (object_save_size)MethodObject::save_size,
|
||||||
|
.save = (object_save)MethodObject::save,
|
||||||
|
.load = (object_load)MethodObject::load,
|
||||||
|
};
|
||||||
|
|
||||||
|
void MethodObject::constructor(MethodObject* self) {
|
||||||
|
self->mScript = obj::ScriptSection::globalHandle()->createScript();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MethodObject::copy(MethodObject* self, MethodObject* in) {
|
||||||
|
obj::ScriptSection::globalHandle()->changeScript(&self->mScript, &in->mScript);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MethodObject::destructor(MethodObject* self) {
|
||||||
|
obj::ScriptSection::globalHandle()->abandonScript(self->mScript);
|
||||||
|
}
|
||||||
|
|
||||||
|
tp::alni MethodObject::save_size(MethodObject* self) {
|
||||||
|
// script_table_file_address & script string object address
|
||||||
|
return sizeof(tp::alni);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MethodObject::save(MethodObject* self, Archiver& file_self) {
|
||||||
|
auto script_section = obj::ScriptSection::globalHandle();
|
||||||
|
|
||||||
|
// script_table_file_address
|
||||||
|
tp::alni script_table_file_address = script_section->get_script_file_adress(self->mScript);
|
||||||
|
file_self.write<tp::alni>(&script_table_file_address);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MethodObject::load(Archiver& file_self, obj::MethodObject* self) {
|
||||||
|
auto script_section = obj::ScriptSection::globalHandle();
|
||||||
|
|
||||||
|
// script_table_file_address
|
||||||
|
tp::alni script_table_file_address;
|
||||||
|
file_self.read<tp::alni>(&script_table_file_address);
|
||||||
|
self->mScript = script_section->get_scritp_from_file_adress(script_table_file_address);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MethodObject::Initialize() {
|
||||||
|
obj::ScriptSection::initialize();
|
||||||
|
NDO->define(&MethodObject::TypeData);
|
||||||
|
obj::NDO->type_groups.addType(&MethodObject::TypeData, { "Primitives" });
|
||||||
|
}
|
||||||
|
|
||||||
|
void MethodObject::UnInitialize() {
|
||||||
|
obj::ScriptSection::uninitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MethodObject::compile() {
|
||||||
|
BCgen::Compile(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
MethodObject* MethodObject::create(tp::String script) {
|
||||||
|
auto out = (MethodObject*)NDO->create(MethodObject::TypeData.name);
|
||||||
|
out->mScript->mReadable->val = script;
|
||||||
|
out->compile();
|
||||||
|
return out;
|
||||||
|
}
|
||||||
60
Objects/private/primitives/nullobject.cpp
Normal file
60
Objects/private/primitives/nullobject.cpp
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
|
||||||
|
#include "primitives/nullobject.h"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
obj::NullObject* obj::NdoNull_globalInstance = NULL;
|
||||||
|
bool uninit_flag = false;
|
||||||
|
|
||||||
|
void NullObject::uninit() {
|
||||||
|
uninit_flag = true;
|
||||||
|
NDO->destroy(NdoNull_globalInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NullObject::destructor(Object* self) {
|
||||||
|
DEBUG_ASSERT(uninit_flag && "Only one the instance of NullObject exists and thus it can't be destroyed");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String to_string(NullObject* self) {
|
||||||
|
return "NULL";
|
||||||
|
}
|
||||||
|
|
||||||
|
alni to_int(NullObject* self) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
alnf to_float(NullObject* self) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj::TypeMethods* tm_construct() {
|
||||||
|
auto out = new obj::TypeMethods();
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ObjectTypeConversions NullObjectTypeConversions = {
|
||||||
|
.from_int = NULL,
|
||||||
|
.from_float = NULL,
|
||||||
|
.from_string = NULL,
|
||||||
|
.to_string = (object_to_string) to_string,
|
||||||
|
.to_int = (object_to_int) to_int,
|
||||||
|
.to_float = (object_to_float) to_float,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct ObjectType NullObject::TypeData = {
|
||||||
|
.base = NULL,
|
||||||
|
.constructor = NULL,
|
||||||
|
.destructor = NullObject::destructor,
|
||||||
|
.copy = NULL,
|
||||||
|
.size = sizeof(NullObject),
|
||||||
|
.name = "null",
|
||||||
|
.convesions = &NullObjectTypeConversions,
|
||||||
|
};
|
||||||
83
Objects/private/primitives/primitives.cpp
Normal file
83
Objects/private/primitives/primitives.cpp
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
|
||||||
|
#include "primitives/primitives.h"
|
||||||
|
|
||||||
|
#include "Tokenizer.hpp"
|
||||||
|
|
||||||
|
void obj::primitives_uninitialize() {
|
||||||
|
obj::NullObject::uninit();
|
||||||
|
obj::MethodObject::UnInitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void obj::primitives_define_types() {
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
static bool initialized = false;
|
||||||
|
if (initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_ASSERT(NDO && "Objects library is not initialized");
|
||||||
|
|
||||||
|
NDO->define(&DictObject::TypeData);
|
||||||
|
NDO->define(&IntObject::TypeData);
|
||||||
|
NDO->define(&LinkObject::TypeData);
|
||||||
|
NDO->define(&ListObject::TypeData);
|
||||||
|
NDO->define(&NullObject::TypeData);
|
||||||
|
NDO->define(&StringObject::TypeData);
|
||||||
|
NDO->define(&BoolObject::TypeData);
|
||||||
|
NDO->define(&FloatObject::TypeData);
|
||||||
|
NDO->define(&EnumObject::TypeData);
|
||||||
|
NDO->define(&ClassObject::TypeData);
|
||||||
|
NDO->define(&ColorObject::TypeData);
|
||||||
|
NDO->define(&InterpreterObject::TypeData);
|
||||||
|
NDO->define(&TypeObject::TypeData);
|
||||||
|
|
||||||
|
NDO->type_groups.addType(&DictObject::TypeData, {"Primitives"});
|
||||||
|
NDO->type_groups.addType(&IntObject::TypeData, {"Primitives"});
|
||||||
|
NDO->type_groups.addType(&LinkObject::TypeData, {"Primitives"});
|
||||||
|
NDO->type_groups.addType(&ListObject::TypeData, {"Primitives"});
|
||||||
|
NDO->type_groups.addType(&NullObject::TypeData, {"Primitives"});
|
||||||
|
NDO->type_groups.addType(&StringObject::TypeData, {"Primitives"});
|
||||||
|
NDO->type_groups.addType(&BoolObject::TypeData, {"Primitives"});
|
||||||
|
NDO->type_groups.addType(&FloatObject::TypeData, {"Primitives"});
|
||||||
|
NDO->type_groups.addType(&EnumObject::TypeData, {"Primitives"});
|
||||||
|
NDO->type_groups.addType(&ClassObject::TypeData, {"Primitives"});
|
||||||
|
NDO->type_groups.addType(&ColorObject::TypeData, {"Primitives"});
|
||||||
|
NDO->type_groups.addType(&InterpreterObject::TypeData, { "scripting" });
|
||||||
|
|
||||||
|
obj::MethodObject::Initialize();
|
||||||
|
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace obj {
|
||||||
|
objects_api* objects_init();
|
||||||
|
void objects_finalize();
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool objInit() {
|
||||||
|
obj::objects_init();
|
||||||
|
obj::primitives_define_types();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void objDeinit() {
|
||||||
|
obj::primitives_uninitialize();
|
||||||
|
obj::objects_finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
static tp::ModuleManifest* sModuleDependencies[] = {
|
||||||
|
// &tp::gModuleCompressor,
|
||||||
|
&tp::gModuleMath,
|
||||||
|
&tp::gModuleStrings,
|
||||||
|
&tp::gModuleTokenizer,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
tp::ModuleManifest obj::gModuleObjects = tp::ModuleManifest("Objects", objInit, objDeinit, sModuleDependencies);
|
||||||
97
Objects/private/primitives/stringobject.cpp
Normal file
97
Objects/private/primitives/stringobject.cpp
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
|
||||||
|
#include "primitives/stringobject.h"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
void StringObject::constructor(Object* self) {
|
||||||
|
new (&NDO_CAST(StringObject, self)->val) String();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StringObject::destructor(StringObject* self) {
|
||||||
|
self->val.~String();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StringObject::copy(Object* self, const Object* in) {
|
||||||
|
NDO_CAST(StringObject, self)->val = NDO_CAST(StringObject, in)->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringObject* StringObject::create(String in) {
|
||||||
|
NDO_CASTV(StringObject, NDO->create("str"), out)->val = in;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StringObject::from_int(StringObject* self, alni in) {
|
||||||
|
// self->val = in;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StringObject::from_float(StringObject* self, alnf in) {
|
||||||
|
// self->val = in;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StringObject::from_string(StringObject* self, String in) {
|
||||||
|
// self->val = in;
|
||||||
|
}
|
||||||
|
|
||||||
|
String StringObject::to_string(StringObject* self) {
|
||||||
|
return self->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
alni StringObject::to_int(StringObject* self) {
|
||||||
|
return alni(self->val);
|
||||||
|
}
|
||||||
|
|
||||||
|
alnf StringObject::to_float(StringObject* self) {
|
||||||
|
return alnf(self->val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static alni save_size(StringObject* self) {
|
||||||
|
// return self->val.save_size();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static void save(StringObject* self, Archiver& file_self) {
|
||||||
|
self->val.save(&file_self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load(Archiver& file_self, StringObject* self) {
|
||||||
|
new (&self->val) tp::String();
|
||||||
|
self->val.load(&file_self);
|
||||||
|
}
|
||||||
|
|
||||||
|
alni allocated_size(StringObject* self) {
|
||||||
|
// return self->val.sizeAllocatedMem();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool compare_strings(StringObject* left, StringObject* right) {
|
||||||
|
return left->val == right->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ObjectTypeConversions StringObjectTypeConversions = {
|
||||||
|
.from_int = (object_from_int)StringObject::from_int,
|
||||||
|
.from_float = (object_from_float)StringObject::from_float,
|
||||||
|
.from_string = (object_from_string)StringObject::from_string,
|
||||||
|
.to_string = (object_to_string)StringObject::to_string,
|
||||||
|
.to_int = (object_to_int)StringObject::to_int,
|
||||||
|
.to_float = (object_to_float)StringObject::to_float,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct obj::ObjectType StringObject::TypeData = {
|
||||||
|
.base = NULL,
|
||||||
|
.constructor = StringObject::constructor,
|
||||||
|
.destructor = (object_destructor)StringObject::destructor,
|
||||||
|
.copy = StringObject::copy,
|
||||||
|
.size = sizeof(StringObject),
|
||||||
|
.name = "str",
|
||||||
|
.convesions = &StringObjectTypeConversions,
|
||||||
|
.save_size = (object_save_size)save_size,
|
||||||
|
.save = (object_save)save,
|
||||||
|
.load = (object_load)load,
|
||||||
|
.comparison = (object_compare) compare_strings,
|
||||||
|
.allocated_size = (object_allocated_size) allocated_size,
|
||||||
|
};
|
||||||
80
Objects/private/primitives/typeobject.cpp
Normal file
80
Objects/private/primitives/typeobject.cpp
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "NewPlacement.hpp"
|
||||||
|
#include "primitives/typeobject.h"
|
||||||
|
#include "primitives/nullobject.h"
|
||||||
|
|
||||||
|
using namespace obj;
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
TypeObject* TypeObject::create(const ObjectType* type) {
|
||||||
|
NDO_CASTV(TypeObject, NDO->create("typeobject"), out);
|
||||||
|
out->mTypeRef = type;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static alni save_size(TypeObject* self) {
|
||||||
|
tp::String const nameid(self->mTypeRef->name);
|
||||||
|
return nameid.save_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void save(TypeObject* self, Archiver& file_self) {
|
||||||
|
tp::String const nameid(self->mTypeRef->name);
|
||||||
|
nameid.save(&file_self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load(Archiver& file_self, TypeObject* self) {
|
||||||
|
tp::String nameid;
|
||||||
|
nameid.load(&file_self);
|
||||||
|
|
||||||
|
auto idx = NDO->types.presents(nameid);
|
||||||
|
|
||||||
|
if (idx) {
|
||||||
|
self->mTypeRef = NDO->types.getSlotVal(idx);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self->mTypeRef = &NullObject::TypeData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static alni allocated_size(TypeObject* self) {
|
||||||
|
return sizeof(alni);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void from_string(TypeObject* self, tp::String in) {
|
||||||
|
auto idx = NDO->types.presents(in);
|
||||||
|
|
||||||
|
if (idx) {
|
||||||
|
self->mTypeRef = NDO->types.getSlotVal(idx);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self->mTypeRef = &NullObject::TypeData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static String to_string(TypeObject* self) {
|
||||||
|
return self->mTypeRef->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool comparator(TypeObject* left, TypeObject* right) {
|
||||||
|
return left->mTypeRef == right->mTypeRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ObjectTypeConversions conversions = {
|
||||||
|
.from_string = (object_from_string) from_string,
|
||||||
|
.to_string = (object_to_string) to_string,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct obj::ObjectType TypeObject::TypeData = {
|
||||||
|
.base = NULL,
|
||||||
|
//.constructor = (object_constructor) TypeObject::constructor,
|
||||||
|
.size = sizeof(TypeObject),
|
||||||
|
.name = "typeobject",
|
||||||
|
.convesions = &conversions,
|
||||||
|
.save_size = (object_save_size) save_size,
|
||||||
|
.save = (object_save) save,
|
||||||
|
.load = (object_load) load,
|
||||||
|
.comparison = (object_compare) comparator,
|
||||||
|
.allocated_size = (object_allocated_size) allocated_size,
|
||||||
|
};
|
||||||
42
Objects/public/compiler/constants.h
Normal file
42
Objects/public/compiler/constants.h
Normal file
|
|
@ -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<tp::String, ConstObject*> mMethods;
|
||||||
|
tp::Map<tp::String, ConstObject*> mStrings;
|
||||||
|
tp::Map<tp::alni, ConstObject*> mIntegers;
|
||||||
|
tp::Map<tp::alnf, ConstObject*> 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<ConstData>& out);
|
||||||
|
|
||||||
|
~ConstObjectsPool();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
126
Objects/public/compiler/expression.h
Normal file
126
Objects/public/compiler/expression.h
Normal file
|
|
@ -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<Expression*> 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<Expression*> mArgs;
|
||||||
|
ExpressionCall(Expression* mParent, tp::init_list<Expression*> 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 <typename ConstType>
|
||||||
|
ExpressionConst* ExprConst(ConstType val) {
|
||||||
|
return new ExpressionConst(val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
47
Objects/public/compiler/function.h
Normal file
47
Objects/public/compiler/function.h
Normal file
|
|
@ -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<ConstObject*> mArgsOrder;
|
||||||
|
|
||||||
|
ConstObjectsPool mConstants;
|
||||||
|
tp::Map<tp::String, ConstObject*> mLocals;
|
||||||
|
tp::List<Instruction> mInstructions;
|
||||||
|
|
||||||
|
FunctionDefinition(tp::String function_id, tp::Buffer<tp::String> args, FunctionDefinition* prnt);
|
||||||
|
FunctionDefinition() {}
|
||||||
|
|
||||||
|
void generateByteCode(ByteCode& out);
|
||||||
|
|
||||||
|
tp::List<Instruction>::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);
|
||||||
|
};
|
||||||
|
};
|
||||||
52
Objects/public/compiler/instruction.h
Normal file
52
Objects/public/compiler/instruction.h
Normal file
|
|
@ -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<Instruction>::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<Instruction>::Node* inst, InstType jump_type);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
116
Objects/public/compiler/statement.h
Normal file
116
Objects/public/compiler/statement.h
Normal file
|
|
@ -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<Statement*> mStatements;
|
||||||
|
bool mPushToScopeStack = false;
|
||||||
|
|
||||||
|
StatementScope(tp::init_list<Statement*> statements, bool aPushToScopeStack);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StatementFuncDef : public Statement {
|
||||||
|
tp::Buffer<tp::String> mArgs;
|
||||||
|
tp::String mFunctionId;
|
||||||
|
tp::Buffer<Statement*> mStatements;
|
||||||
|
|
||||||
|
StatementFuncDef(tp::String function_id, tp::init_list<tp::String> args, tp::init_list<Statement*> 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<tp::String> args, tp::init_list<Statement*> 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<Statement*> statements, bool aPushToScopeStack);
|
||||||
|
StatementWhile* StmWhile(Expression* condition, StatementScope* scope);
|
||||||
|
StatementIgnore* StmIgnore(Expression* expr);
|
||||||
|
StatementClassDef* StmClassDef(tp::String id, StatementScope* scope);
|
||||||
|
};
|
||||||
|
};
|
||||||
226
Objects/public/core/object.h
Normal file
226
Objects/public/core/object.h
Normal file
|
|
@ -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 <typename Type>
|
||||||
|
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 <typename Type>
|
||||||
|
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*> (*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<tp::String, const ObjectType*> 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 <typename Type>
|
||||||
|
Type* create() {
|
||||||
|
return (Type*)obj::NDO->create(Type::TypeData.name);
|
||||||
|
}
|
||||||
|
};
|
||||||
36
Objects/public/core/scriptsection.h
Normal file
36
Objects/public/core/scriptsection.h
Normal file
|
|
@ -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<Script*> 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);
|
||||||
|
};
|
||||||
|
};
|
||||||
40
Objects/public/core/typegroups.h
Normal file
40
Objects/public/core/typegroups.h
Normal file
|
|
@ -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<tp::String, obj::TypeGroups*> Dict;
|
||||||
|
|
||||||
|
TypeGroups();
|
||||||
|
|
||||||
|
friend struct obj::objects_api;
|
||||||
|
|
||||||
|
TypeGroups(bool is_group);
|
||||||
|
|
||||||
|
void addType(ObjectType* type, tp::init_list<const char*> 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;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
63
Objects/public/core/typemethods.h
Normal file
63
Objects/public/core/typemethods.h
Normal file
|
|
@ -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;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
28
Objects/public/interpreter/bytecode.h
Normal file
28
Objects/public/interpreter/bytecode.h
Normal file
|
|
@ -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<ConstData> mConstants;
|
||||||
|
tp::Buffer<OpCode> mInstructions;
|
||||||
|
tp::ualni mInstructionIdx = 0;
|
||||||
|
tp::ualni mArgumentsLoaded = 0;
|
||||||
|
|
||||||
|
~ByteCode() {
|
||||||
|
for (auto const_obj : mConstants) {
|
||||||
|
NDO->destroy(const_obj.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
32
Objects/public/interpreter/callstack.h
Normal file
32
Objects/public/interpreter/callstack.h
Normal file
|
|
@ -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<CallFrame, CallFrame::CALL_DEPTH> mStack;
|
||||||
|
};
|
||||||
|
};
|
||||||
29
Objects/public/interpreter/interpreter.h
Normal file
29
Objects/public/interpreter/interpreter.h
Normal file
|
|
@ -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<GlobalDef> 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<GlobalDef> globals2 = {});
|
||||||
|
};
|
||||||
|
};
|
||||||
158
Objects/public/interpreter/opcodes.h
Normal file
158
Objects/public/interpreter/opcodes.h
Normal file
|
|
@ -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<Operand> 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<Param> 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);
|
||||||
|
};
|
||||||
|
}
|
||||||
39
Objects/public/interpreter/operandsstack.h
Normal file
39
Objects/public/interpreter/operandsstack.h
Normal file
|
|
@ -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 <typename ObjectType>
|
||||||
|
ObjectType* getOperand() {
|
||||||
|
auto operand = getOperand();
|
||||||
|
auto ret = NDO_CAST(ObjectType, operand);
|
||||||
|
ASSERT(ret && "Operand Has Invalid Object Type");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
~OperandStack();
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
46
Objects/public/interpreter/scopestack.h
Normal file
46
Objects/public/interpreter/scopestack.h
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/object.h"
|
||||||
|
#include "Map.hpp"
|
||||||
|
|
||||||
|
namespace obj {
|
||||||
|
|
||||||
|
struct Scope {
|
||||||
|
typedef tp::Map<tp::String, obj::Object*> ObjDict;
|
||||||
|
typedef tp::List<obj::Object*> 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);
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
12
Objects/public/interpreter/script.h
Normal file
12
Objects/public/interpreter/script.h
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "interpreter/bytecode.h"
|
||||||
|
|
||||||
|
namespace obj {
|
||||||
|
struct Script {
|
||||||
|
obj::StringObject* mReadable;
|
||||||
|
ByteCode mBytecode;
|
||||||
|
|
||||||
|
void compile();
|
||||||
|
};
|
||||||
|
};
|
||||||
195
Objects/public/parser/parser.h
Normal file
195
Objects/public/parser/parser.h
Normal file
|
|
@ -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<char, Token::TokType, Token::NO_TOKEN, Token::FAILED, Token::SOURCE_END_TOKEN> 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<tp::alni, tp::alni> 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<ExprType> 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<StmType> 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);
|
||||||
|
};
|
||||||
|
};
|
||||||
24
Objects/public/primitives/boolobject.h
Normal file
24
Objects/public/primitives/boolobject.h
Normal file
|
|
@ -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);
|
||||||
|
};
|
||||||
|
};
|
||||||
49
Objects/public/primitives/classobject.h
Normal file
49
Objects/public/primitives/classobject.h
Normal file
|
|
@ -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<typename Type>
|
||||||
|
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<typename Type>
|
||||||
|
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<typename Type>
|
||||||
|
Type* getMemberAssert(const tp::String& id) {
|
||||||
|
auto out = getMember<Type>(id);
|
||||||
|
assert(out && "invalid member access");
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
24
Objects/public/primitives/colorobject.h
Normal file
24
Objects/public/primitives/colorobject.h
Normal file
|
|
@ -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);
|
||||||
|
};
|
||||||
|
};
|
||||||
31
Objects/public/primitives/dictobject.h
Normal file
31
Objects/public/primitives/dictobject.h
Normal file
|
|
@ -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<Object*> 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<tp::String, Object*>::Idx presents(tp::String);
|
||||||
|
Object* getSlotVal(tp::alni);
|
||||||
|
|
||||||
|
const tp::Map<tp::String, Object*>& getItems() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
tp::Map<tp::String, Object*> items;
|
||||||
|
};
|
||||||
|
};
|
||||||
34
Objects/public/primitives/enumobject.h
Normal file
34
Objects/public/primitives/enumobject.h
Normal file
|
|
@ -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<const char*> 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<const char*> list);
|
||||||
|
};
|
||||||
|
};
|
||||||
26
Objects/public/primitives/floatobject.h
Normal file
26
Objects/public/primitives/floatobject.h
Normal file
|
|
@ -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);
|
||||||
|
};
|
||||||
|
};
|
||||||
19
Objects/public/primitives/interpreterobject.h
Normal file
19
Objects/public/primitives/interpreterobject.h
Normal file
|
|
@ -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<Interpreter::GlobalDef> globals = {});
|
||||||
|
void debug();
|
||||||
|
bool running();
|
||||||
|
};
|
||||||
|
};
|
||||||
25
Objects/public/primitives/intobject.h
Normal file
25
Objects/public/primitives/intobject.h
Normal file
|
|
@ -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);
|
||||||
|
};
|
||||||
|
};
|
||||||
29
Objects/public/primitives/linkobject.h
Normal file
29
Objects/public/primitives/linkobject.h
Normal file
|
|
@ -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<Object*> childs_retrival(LinkObject* self);
|
||||||
|
|
||||||
|
Object* getLink();
|
||||||
|
void setLink(Object* obj);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Object* link;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
36
Objects/public/primitives/listobject.h
Normal file
36
Objects/public/primitives/listobject.h
Normal file
|
|
@ -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<Object*> 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<Object*>& getItems() const;
|
||||||
|
|
||||||
|
void pushBack(Object* obj);
|
||||||
|
void pushFront(Object* obj);
|
||||||
|
void popBack();
|
||||||
|
void delNode(tp::List<Object*>::Node*);
|
||||||
|
|
||||||
|
private:
|
||||||
|
tp::List<Object*> items;
|
||||||
|
};
|
||||||
|
};
|
||||||
28
Objects/public/primitives/methodobject.h
Normal file
28
Objects/public/primitives/methodobject.h
Normal file
|
|
@ -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);
|
||||||
|
};
|
||||||
|
};
|
||||||
32
Objects/public/primitives/nullobject.h
Normal file
32
Objects/public/primitives/nullobject.h
Normal file
|
|
@ -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()
|
||||||
|
|
||||||
|
};
|
||||||
22
Objects/public/primitives/primitives.h
Normal file
22
Objects/public/primitives/primitives.h
Normal file
|
|
@ -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();
|
||||||
|
};
|
||||||
24
Objects/public/primitives/stringobject.h
Normal file
24
Objects/public/primitives/stringobject.h
Normal file
|
|
@ -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);
|
||||||
|
};
|
||||||
|
};
|
||||||
13
Objects/public/primitives/typeobject.h
Normal file
13
Objects/public/primitives/typeobject.h
Normal file
|
|
@ -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);
|
||||||
|
};
|
||||||
|
};
|
||||||
15
Objects/rsc/script.osc
Normal file
15
Objects/rsc/script.osc
Normal file
|
|
@ -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();
|
||||||
90
Objects/tests/TestEntry.cpp
Normal file
90
Objects/tests/TestEntry.cpp
Normal file
|
|
@ -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();
|
||||||
|
}
|
||||||
75
Objects/tests/test.cpp
Normal file
75
Objects/tests/test.cpp
Normal file
|
|
@ -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();
|
||||||
|
}
|
||||||
14
TODO
14
TODO
|
|
@ -2,7 +2,19 @@ Testing !
|
||||||
Serialization !
|
Serialization !
|
||||||
|
|
||||||
Objects:
|
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:
|
Storage:
|
||||||
Finish networking
|
Finish networking
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ namespace tp {
|
||||||
if (!mSource) {
|
if (!mSource) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (mSource[mAdvancedOffset] == nullptr) {
|
if (mSource[mAdvancedOffset] == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,9 @@ namespace tp {
|
||||||
return 0;
|
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) {
|
int1 memCompareVal(const void* left, uhalni len, uint1 val) {
|
||||||
MODULE_SANITY_CHECK(gModuleBase)
|
MODULE_SANITY_CHECK(gModuleBase)
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ namespace tp {
|
||||||
void memSetVal(void* p, uhalni byteSize, uint1 val);
|
void memSetVal(void* p, uhalni byteSize, uint1 val);
|
||||||
void memCopy(void* left, const void* right, uhalni len);
|
void memCopy(void* left, const void* right, uhalni len);
|
||||||
int1 memCompare(const 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);
|
int1 memCompareVal(const void* left, uhalni len, uint1 val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue