Objects Initial
This commit is contained in:
parent
0f639ba3b1
commit
94057d2a66
76 changed files with 7895 additions and 17 deletions
148
Objects/private/compiler/constants.cpp
Normal file
148
Objects/private/compiler/constants.cpp
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
#include "NewPlacement.hpp"
|
||||
#include "compiler/constants.h"
|
||||
#include "primitives/primitives.h"
|
||||
#include "primitives/methodobject.h"
|
||||
|
||||
using namespace obj;
|
||||
using namespace tp;
|
||||
using namespace BCgen;
|
||||
|
||||
ConstObject::ConstObject() {}
|
||||
ConstObject::ConstObject(obj::Object* mObj) : mObj(mObj) {}
|
||||
|
||||
ConstObjectsPool::~ConstObjectsPool() {
|
||||
if (mDelete) {
|
||||
for (auto obj : mStrings) {
|
||||
obj::NDO->destroy(obj->val->mObj);
|
||||
}
|
||||
for (auto obj : mIntegers) {
|
||||
obj::NDO->destroy(obj->val->mObj);
|
||||
}
|
||||
for (auto obj : mFloats) {
|
||||
obj::NDO->destroy(obj->val->mObj);
|
||||
}
|
||||
for (auto obj : mMethods) {
|
||||
obj::NDO->destroy(obj->val->mObj);
|
||||
}
|
||||
if (mBoolFalse.mObj) {
|
||||
obj::NDO->destroy(mBoolFalse.mObj);
|
||||
}
|
||||
if (mBoolTrue.mObj) {
|
||||
obj::NDO->destroy(mBoolTrue.mObj);
|
||||
}
|
||||
}
|
||||
for (auto obj : mStrings) {
|
||||
delete obj->val;
|
||||
}
|
||||
for (auto obj : mIntegers) {
|
||||
delete obj->val;
|
||||
}
|
||||
for (auto obj : mFloats) {
|
||||
delete obj->val;
|
||||
}
|
||||
}
|
||||
|
||||
ConstObject* ConstObjectsPool::registerObject(obj::Object* obj) {
|
||||
ConstObject* out = new ConstObject(obj);
|
||||
mTotalObjects++;
|
||||
return out;
|
||||
}
|
||||
|
||||
ConstObject* ConstObjectsPool::get(tp::alni val) {
|
||||
auto idx = mIntegers.presents(val);
|
||||
ConstObject* const_obj = NULL;
|
||||
if (idx) {
|
||||
const_obj = mIntegers.getSlotVal(idx);
|
||||
}
|
||||
else {
|
||||
const_obj = registerObject(IntObject::create(val));
|
||||
mIntegers.put(val, const_obj);
|
||||
}
|
||||
return const_obj;
|
||||
}
|
||||
|
||||
ConstObject* ConstObjectsPool::get(tp::String val) {
|
||||
auto idx = mStrings.presents(val);
|
||||
ConstObject* const_obj = NULL;
|
||||
if (idx) {
|
||||
const_obj = mStrings.getSlotVal(idx);
|
||||
}
|
||||
else {
|
||||
const_obj = registerObject(StringObject::create(val));
|
||||
mStrings.put(val, const_obj);
|
||||
}
|
||||
return const_obj;
|
||||
}
|
||||
|
||||
ConstObject* ConstObjectsPool::get(tp::alnf val) {
|
||||
auto idx = mFloats.presents(val);
|
||||
ConstObject* const_obj = NULL;
|
||||
if (idx) {
|
||||
const_obj = mFloats.getSlotVal(idx);
|
||||
}
|
||||
else {
|
||||
const_obj = registerObject(FloatObject::create(val));
|
||||
mFloats.put(val, const_obj);
|
||||
}
|
||||
return const_obj;
|
||||
}
|
||||
|
||||
ConstObject* ConstObjectsPool::get(bool val) {
|
||||
if (val) {
|
||||
if (!mBoolTrue.mObj) {
|
||||
mBoolTrue.mObj = BoolObject::create(val);
|
||||
mTotalObjects++;
|
||||
}
|
||||
return &mBoolTrue;
|
||||
}
|
||||
else {
|
||||
if (!mBoolFalse.mObj) {
|
||||
mBoolFalse.mObj = BoolObject::create(val);
|
||||
mTotalObjects++;
|
||||
}
|
||||
return &mBoolFalse;
|
||||
}
|
||||
}
|
||||
|
||||
ConstObject* ConstObjectsPool::addMethod(tp::String method_id, obj::Object* method) {
|
||||
ASSERT(NDO_CAST(MethodObject, method) && "Object is not a method object");
|
||||
ASSERT(!mMethods.presents(method_id) && "Method Redefinition");
|
||||
auto out = registerObject(method);
|
||||
mMethods.put(method_id, out);
|
||||
return out;
|
||||
}
|
||||
|
||||
void ConstObjectsPool::save(tp::Buffer<ConstData>& out) {
|
||||
out.reserve(mTotalObjects);
|
||||
tp::alni data_idx = 0;
|
||||
for (auto obj : mMethods) {
|
||||
out[data_idx] = obj->val->mObj;
|
||||
obj->val->mConstIdx = data_idx;
|
||||
data_idx++;
|
||||
}
|
||||
for (auto obj : mStrings) {
|
||||
out[data_idx] = obj->val->mObj;
|
||||
obj->val->mConstIdx = data_idx;
|
||||
data_idx++;
|
||||
}
|
||||
for (auto obj : mIntegers) {
|
||||
out[data_idx] = obj->val->mObj;
|
||||
obj->val->mConstIdx = data_idx;
|
||||
data_idx++;
|
||||
}
|
||||
for (auto obj : mFloats) {
|
||||
out[data_idx] = obj->val->mObj;
|
||||
obj->val->mConstIdx = data_idx;
|
||||
data_idx++;
|
||||
}
|
||||
if (mBoolFalse.mObj) {
|
||||
out[data_idx] = mBoolFalse.mObj;
|
||||
mBoolFalse.mConstIdx = data_idx;
|
||||
data_idx++;
|
||||
}
|
||||
if (mBoolTrue.mObj) {
|
||||
out[data_idx] = mBoolTrue.mObj;
|
||||
mBoolTrue.mConstIdx = data_idx;
|
||||
}
|
||||
mDelete = false;
|
||||
}
|
||||
70
Objects/private/compiler/expression.cpp
Normal file
70
Objects/private/compiler/expression.cpp
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
#include "NewPlacement.hpp"
|
||||
#include "compiler/expression.h"
|
||||
|
||||
using namespace obj;
|
||||
using namespace BCgen;
|
||||
|
||||
Expression::Expression() {}
|
||||
Expression::Expression(Type type) : mType(type) {}
|
||||
|
||||
ExpressionChild* Expression::ExprChild(tp::String id) {
|
||||
return new ExpressionChild(this, id);
|
||||
}
|
||||
|
||||
ExpressionCall* Expression::ExprCall(tp::init_list<Expression*> args) {
|
||||
return new ExpressionCall(this, args);
|
||||
}
|
||||
|
||||
ExpressionLocal* obj::BCgen::ExprLocal(tp::String id) {
|
||||
return new ExpressionLocal(id);
|
||||
}
|
||||
|
||||
ExpressionSelf* obj::BCgen::ExprSelf() {
|
||||
return new ExpressionSelf();
|
||||
}
|
||||
|
||||
ExpressionNew* obj::BCgen::ExprNew(tp::String type) {
|
||||
return new ExpressionNew(type);
|
||||
}
|
||||
|
||||
ExpressionAriphm* obj::BCgen::ExprAriphm(Expression* left, Expression* right, OpCode type) {
|
||||
return new ExpressionAriphm(left, right, type);
|
||||
}
|
||||
|
||||
ExpressionFunc* obj::BCgen::ExprFunc(tp::String id) {
|
||||
return new ExpressionFunc(id);
|
||||
}
|
||||
|
||||
ExpressionBoolean* obj::BCgen::ExprBool(Expression* left, Expression* right, obj::OpCode type) {
|
||||
return new ExpressionBoolean(left, right, ExpressionBoolean::BoolType(type));
|
||||
}
|
||||
|
||||
ExpressionBoolean* obj::BCgen::ExprBoolNot(Expression* invert) {
|
||||
return new ExpressionBoolean(invert);
|
||||
}
|
||||
|
||||
ExpressionBoolean::ExpressionBoolean(Expression* left, Expression* right, BoolType type)
|
||||
: Expression(Type::BOOLEAN), mLeft(left), mRight(right), mBoolType(type) {
|
||||
}
|
||||
|
||||
ExpressionBoolean::ExpressionBoolean(Expression* invert)
|
||||
: Expression(Type::BOOLEAN), mLeft(invert), mBoolType(BoolType::NOT){
|
||||
}
|
||||
|
||||
ExpressionCall::ExpressionCall(Expression * mParent, tp::init_list<Expression*> args) : Expression(Type::CALL), mParent(mParent) {
|
||||
mArgs = args;
|
||||
}
|
||||
|
||||
ExpressionNew::ExpressionNew(tp::String type) : Expression(Type::NEW), mNewType(type) {}
|
||||
ExpressionLocal::ExpressionLocal(tp::String id) : Expression(Type::LOCAL), mLocalId(id) {}
|
||||
ExpressionSelf::ExpressionSelf() : Expression(Type::SELF) {}
|
||||
ExpressionChild::ExpressionChild(Expression* mParent, tp::String id) : Expression(Type::CHILD), mParent(mParent), mLocalId(id) {}
|
||||
ExpressionAriphm::ExpressionAriphm(Expression* left, Expression* right, OpCode type) : Expression(Type::ARIPHM), mLeft(left), mRight(right), mOpType(type) {}
|
||||
ExpressionFunc::ExpressionFunc(tp::String id) : Expression(Type::FUNC), mFuncId(id) {}
|
||||
ExpressionConst::ExpressionConst(tp::String val) : Expression(Type::CONST), mConstType(STR), str(val) {}
|
||||
ExpressionConst::ExpressionConst(const char* val) : Expression(Type::CONST), mConstType(STR), str(val) {}
|
||||
ExpressionConst::ExpressionConst(tp::int4 val) : Expression(Type::CONST), mConstType(INT), integer(val) {}
|
||||
ExpressionConst::ExpressionConst(tp::flt4 val) : Expression(Type::CONST), mConstType(FLT), floating(val) {}
|
||||
ExpressionConst::ExpressionConst(tp::alni val) : Expression(Type::CONST), mConstType(INT), integer(val) {}
|
||||
ExpressionConst::ExpressionConst(tp::alnf val) : Expression(Type::CONST), mConstType(FLT), floating(val) {}
|
||||
ExpressionConst::ExpressionConst(bool val) : Expression(Type::CONST), mConstType(BOOL), boolean(val) {}
|
||||
556
Objects/private/compiler/function.cpp
Normal file
556
Objects/private/compiler/function.cpp
Normal file
|
|
@ -0,0 +1,556 @@
|
|||
|
||||
#include "NewPlacement.hpp"
|
||||
|
||||
#include "compiler/function.h"
|
||||
|
||||
#include "primitives/primitives.h"
|
||||
#include "primitives/methodobject.h"
|
||||
|
||||
#include "Logging.hpp"
|
||||
|
||||
#include "parser/parser.h"
|
||||
|
||||
using namespace obj;
|
||||
using namespace tp;
|
||||
using namespace obj;
|
||||
using namespace BCgen;
|
||||
|
||||
void obj::BCgen::Genereate(ByteCode& out, StatementScope* body) {
|
||||
auto root = FunctionDefinition();
|
||||
|
||||
root.inst(Instruction(OpCode::SCOPE_IN));
|
||||
|
||||
for (auto child_stm : body->mStatements) {
|
||||
root.EvalStatement(child_stm.data());
|
||||
}
|
||||
|
||||
root.inst(Instruction(OpCode::SCOPE_OUT));
|
||||
|
||||
root.generateByteCode(out);
|
||||
}
|
||||
|
||||
ConstObject* FunctionDefinition::defineLocal(tp::String id) {
|
||||
auto idx = mLocals.presents(id);
|
||||
//RelAssert(!idx && "Local Redefinition");
|
||||
auto const_str_id = mConstants.get(id);
|
||||
mLocals.put(id, const_str_id);
|
||||
return const_str_id;
|
||||
}
|
||||
|
||||
FunctionDefinition::FunctionDefinition(tp::String function_id, tp::Buffer<tp::String> args, FunctionDefinition* prnt) {
|
||||
mFunctionId = function_id;
|
||||
inst(Instruction(OpCode::SAVE_ARGS, args.size(), 1));
|
||||
for (auto id : args) {
|
||||
ASSERT(!mLocals.presents(id.data()) && "Argument Redefinition");
|
||||
auto const_data = mConstants.get(id.data());
|
||||
mArgsOrder.pushBack(const_data);
|
||||
mLocals.put(id.data(), const_data);
|
||||
inst(Instruction(const_data));
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionDefinition::EvalStatement(Statement* stm) {
|
||||
switch (stm->mType) {
|
||||
case Statement::Type::IGNORE: {
|
||||
auto stm_ignore = (StatementIgnore*)stm;
|
||||
EvalExpr(stm_ignore->mExpr);
|
||||
inst(OpCode::IGNORE);
|
||||
break;
|
||||
}
|
||||
case Statement::Type::WHILE: {
|
||||
auto stm_while = (StatementWhile*)stm;
|
||||
|
||||
auto check_mark = inst(Instruction());
|
||||
|
||||
EvalExpr(stm_while->mCondition);
|
||||
|
||||
auto jump_if_inst = inst(Instruction(NULL, Instruction::InstType::JUMP_IF_NOT));
|
||||
|
||||
if (stm_while->mScope) {
|
||||
EvalStatement(stm_while->mScope);
|
||||
}
|
||||
|
||||
auto jump_inst = inst(Instruction(NULL, Instruction::InstType::JUMP));
|
||||
auto end_mark = inst(Instruction());
|
||||
|
||||
jump_if_inst->data.mInstTarget = end_mark;
|
||||
jump_inst->data.mInstTarget = check_mark;
|
||||
|
||||
break;
|
||||
}
|
||||
case Statement::Type::IF: {
|
||||
auto stm_if = (StatementIf*)stm;
|
||||
|
||||
EvalExpr(stm_if->mCondition);
|
||||
|
||||
auto jump_if_inst = inst(Instruction(NULL, Instruction::InstType::JUMP_IF_NOT));
|
||||
|
||||
if (stm_if->mOnTrue) {
|
||||
EvalStatement(stm_if->mOnTrue);
|
||||
}
|
||||
|
||||
auto jump_inst = inst(Instruction(NULL, Instruction::InstType::JUMP));
|
||||
auto else_mark = inst(Instruction());
|
||||
|
||||
if (stm_if->mOnFalse) {
|
||||
EvalStatement(stm_if->mOnFalse);
|
||||
}
|
||||
|
||||
auto end_mark = inst(Instruction());
|
||||
|
||||
jump_if_inst->data.mInstTarget = else_mark;
|
||||
jump_inst->data.mInstTarget = end_mark;
|
||||
|
||||
break;
|
||||
}
|
||||
case Statement::Type::SCOPE: {
|
||||
auto stm_scope = (StatementScope*)stm;
|
||||
if (stm_scope->mPushToScopeStack) {
|
||||
inst(Instruction(OpCode::SCOPE_IN));
|
||||
}
|
||||
for (auto child_stm : stm_scope->mStatements) {
|
||||
EvalStatement(child_stm.data());
|
||||
}
|
||||
if (stm_scope->mPushToScopeStack) {
|
||||
inst(Instruction(OpCode::SCOPE_OUT));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Statement::Type::DEF_FUNC: {
|
||||
auto stm_func_def = (StatementFuncDef*) stm;
|
||||
|
||||
FunctionDefinition func(stm_func_def->mFunctionId, stm_func_def->mArgs, this);
|
||||
|
||||
// define method as local
|
||||
auto idx = mLocals.presents(func.mFunctionId);
|
||||
ASSERT(!idx && "Local Redefinition with function name");
|
||||
mLocals.put(func.mFunctionId, mConstants.get(func.mFunctionId));
|
||||
|
||||
// create and register const func object
|
||||
auto function_obj = NDO_CAST(MethodObject, NDO->create("method"));
|
||||
auto method_const_obj = mConstants.addMethod(func.mFunctionId, function_obj);
|
||||
|
||||
for (auto child_stm : stm_func_def->mStatements) {
|
||||
func.EvalStatement(child_stm.data());
|
||||
}
|
||||
|
||||
func.generateByteCode(function_obj->mScript->mBytecode);
|
||||
|
||||
inst(Instruction(OpCode::LOAD_CONST, method_const_obj));
|
||||
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(func.mFunctionId)));
|
||||
inst(Instruction(OpCode::DEF_LOCAL));
|
||||
break;
|
||||
}
|
||||
case Statement::Type::CLASS_DEF: {
|
||||
|
||||
// do the function definition
|
||||
auto stm_class_def = (StatementClassDef*)stm;
|
||||
|
||||
FunctionDefinition func(stm_class_def->mClassId, {}, this);
|
||||
|
||||
// define method as local
|
||||
auto idx = mLocals.presents(func.mFunctionId);
|
||||
ASSERT(!idx && "Local Redefinition with function name");
|
||||
mLocals.put(func.mFunctionId, mConstants.get(func.mFunctionId));
|
||||
|
||||
// create and register const func object
|
||||
auto function_obj = NDO_CAST(MethodObject, NDO->create("method"));
|
||||
auto method_const_obj = mConstants.addMethod(func.mFunctionId, function_obj);
|
||||
|
||||
// compile function
|
||||
for (auto child_stm : stm_class_def->mScope->mStatements) {
|
||||
// check for return statements
|
||||
ASSERT(child_stm.data()->mType != Statement::Type::RET && "return statements are not allowed in class definition");
|
||||
func.EvalStatement(child_stm.data());
|
||||
}
|
||||
// create one last instruction - constructing class from function execution state
|
||||
func.inst(Instruction(OpCode::CLASS_CONSTRUCT));
|
||||
func.generateByteCode(function_obj->mScript->mBytecode);
|
||||
|
||||
inst(Instruction(OpCode::LOAD_CONST, method_const_obj));
|
||||
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(func.mFunctionId)));
|
||||
inst(Instruction(OpCode::DEF_LOCAL));
|
||||
break;
|
||||
}
|
||||
case Statement::Type::DEF_LOCAL: {
|
||||
auto stm_local_def = (StatementLocalDef*)stm;
|
||||
|
||||
if (!stm_local_def->mIsConstExpr) {
|
||||
auto const_id = defineLocal(stm_local_def->mLocalId);
|
||||
EvalExpr(stm_local_def->mNewExpr);
|
||||
inst(Instruction(OpCode::LOAD_CONST, const_id));
|
||||
inst(Instruction(OpCode::DEF_LOCAL));
|
||||
|
||||
} else {
|
||||
|
||||
tp::String type;
|
||||
switch (stm_local_def->mConstExpr->mConstType) {
|
||||
case ExpressionConst::BOOL: {
|
||||
type = "bool";
|
||||
break;
|
||||
}
|
||||
case ExpressionConst::INT: {
|
||||
type = "int";
|
||||
break;
|
||||
}
|
||||
case ExpressionConst::FLT: {
|
||||
type = "float";
|
||||
break;
|
||||
}
|
||||
case ExpressionConst::STR: {
|
||||
type = "str";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ASSERT(0 && "Cantbe");
|
||||
}
|
||||
}
|
||||
|
||||
auto new_expr = new ExpressionNew(type);
|
||||
|
||||
EvalStatement(StmDefLocal(stm_local_def->mLocalId, new_expr));
|
||||
EvalExpr(stm_local_def->mConstExpr);
|
||||
inst(Instruction(OpCode::LOAD_LOCAL, mConstants.get(stm_local_def->mLocalId)));
|
||||
inst(Instruction(OpCode::OBJ_COPY));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Statement::Type::COPY: {
|
||||
auto stm_cp = (StatementCopy*)stm;
|
||||
EvalExpr(stm_cp->mRight);
|
||||
EvalExpr(stm_cp->mLeft);
|
||||
inst(Instruction(OpCode::OBJ_COPY));
|
||||
break;
|
||||
}
|
||||
case Statement::Type::PRINT: {
|
||||
auto stm_prnt = (StatementPrint*)stm;
|
||||
EvalExpr(stm_prnt->mTarget);
|
||||
inst(Instruction(OpCode::PRINT));
|
||||
break;
|
||||
}
|
||||
case Statement::Type::RET: {
|
||||
auto stm_ret = (StatementReturn*)stm;
|
||||
if (stm_ret->mRet) {
|
||||
EvalExpr(stm_ret->mRet);
|
||||
inst(Instruction(OpCode::RETURN_OBJ));
|
||||
} else {
|
||||
inst(Instruction(OpCode::RETURN));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ASSERT(0)
|
||||
}
|
||||
|
||||
delete stm;
|
||||
}
|
||||
|
||||
|
||||
void FunctionDefinition::EvalExpr(Expression* expr) {
|
||||
switch (expr->mType) {
|
||||
case Expression::Type::BOOLEAN: {
|
||||
auto boolean = (ExpressionBoolean*)expr;
|
||||
if (boolean->mBoolType == ExpressionBoolean::BoolType::NOT) {
|
||||
EvalExpr(boolean->mLeft);
|
||||
inst(OpCode::NOT);
|
||||
} else {
|
||||
EvalExpr(boolean->mRight);
|
||||
EvalExpr(boolean->mLeft);
|
||||
inst(OpCode(boolean->mBoolType));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Expression::Type::FUNC: {
|
||||
auto func = (ExpressionFunc*)expr;
|
||||
|
||||
//RelAssert(mConstants.mMethods.presents(func->mFuncId) && "No such function");
|
||||
inst(Instruction(OpCode::LOAD_LOCAL, mConstants.get(func->mFuncId)));
|
||||
break;
|
||||
}
|
||||
case Expression::Type::ARIPHM: {
|
||||
auto ariphm = (ExpressionAriphm*)expr;
|
||||
EvalExpr(ariphm->mRight);
|
||||
EvalExpr(ariphm->mLeft);
|
||||
inst(Instruction(ariphm->mOpType));
|
||||
break;
|
||||
}
|
||||
case Expression::Type::NEW: {
|
||||
auto create_new = (ExpressionNew*)expr;
|
||||
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(create_new->mNewType)));
|
||||
inst(Instruction(OpCode::OBJ_CREATE));
|
||||
break;
|
||||
}
|
||||
case Expression::Type::LOCAL: {
|
||||
auto local = (ExpressionLocal*)expr;
|
||||
// RelAssert(mLocals.presents(local->mLocalId) && "undefined local");
|
||||
inst(Instruction(OpCode::LOAD_LOCAL, mConstants.get(local->mLocalId)));
|
||||
break;
|
||||
}
|
||||
case Expression::Type::CONST: {
|
||||
auto constobj = (ExpressionConst*)expr;
|
||||
switch (constobj->mConstType) {
|
||||
case ExpressionConst::STR: {
|
||||
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(constobj->str)));
|
||||
break;
|
||||
}
|
||||
case ExpressionConst::INT: {
|
||||
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(constobj->integer)));
|
||||
break;
|
||||
}
|
||||
case ExpressionConst::FLT: {
|
||||
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(constobj->floating)));
|
||||
break;
|
||||
}
|
||||
case ExpressionConst::BOOL: {
|
||||
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(constobj->boolean)));
|
||||
break;
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
case Expression::Type::CHILD: {
|
||||
auto child = (ExpressionChild*)expr;
|
||||
EvalExpr(child->mParent);
|
||||
inst(Instruction(OpCode::LOAD_CONST, mConstants.get(child->mLocalId)));
|
||||
inst(Instruction(OpCode::CHILD, child->mMethod, 1));
|
||||
break;
|
||||
}
|
||||
case Expression::Type::SELF: {
|
||||
inst(Instruction(OpCode::SELF));
|
||||
break;
|
||||
}
|
||||
case Expression::Type::CALL: {
|
||||
auto call = (ExpressionCall*)expr;
|
||||
inst(Instruction(OpCode::PUSH_ARGS, call->mArgs.size(), 1));
|
||||
for (auto arg : call->mArgs) {
|
||||
EvalExpr(arg.data());
|
||||
}
|
||||
EvalExpr(call->mParent);
|
||||
inst(Instruction(OpCode::CALL));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ASSERT(0)
|
||||
}
|
||||
delete expr;
|
||||
}
|
||||
|
||||
tp::alni instSize(const Instruction& inst) {
|
||||
switch (inst.mInstType) {
|
||||
case Instruction::InstType::JUMP:
|
||||
case Instruction::InstType::JUMP_IF_NOT:
|
||||
case Instruction::InstType::JUMP_IF: {
|
||||
// 2 bytes for offset 1 byte for instrtuction
|
||||
return 3;
|
||||
}
|
||||
case Instruction::InstType::PURE_CONST: {
|
||||
return 2;
|
||||
}
|
||||
case Instruction::InstType::EXEC: {
|
||||
tp::alni out = 1;
|
||||
switch (inst.mArgType) {
|
||||
case Instruction::ArgType::PARAM: {
|
||||
out += inst.mParamBytes;
|
||||
return out;
|
||||
}
|
||||
case Instruction::ArgType::CONST: {
|
||||
out += 2;
|
||||
if (inst.mConstData2) {
|
||||
out += 2;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
case Instruction::ArgType::NO_ARG: {
|
||||
return out;
|
||||
}
|
||||
default: {
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
case Instruction::InstType::NONE: {
|
||||
return 0;
|
||||
}
|
||||
default: {
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void writeConst(ByteCode& out, tp::alni& idx, tp::uint2 data) {
|
||||
for (auto byte : tp::Range(sizeof(tp::uint2))) {
|
||||
out.mInstructions[idx] = OpCode((tp::int1)(data >> byte * 8));
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
void writeParam(ByteCode& out, tp::alni& idx, tp::int1* data, tp::alni size) {
|
||||
for (auto byte : tp::Range(size)) {
|
||||
out.mInstructions[idx] = OpCode(data[byte]);
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
tp::alni calcOffset(tp::List<Instruction>::Node* jump_inst, tp::List<Instruction>::Node* to) {
|
||||
tp::alni offset = 0;
|
||||
bool reversed = jump_inst->data.mInstIdx > to->data.mInstIdx;
|
||||
auto iter_node = reversed ? jump_inst : jump_inst->next;
|
||||
while (iter_node != to) {
|
||||
offset += instSize(iter_node->data);
|
||||
iter_node = reversed ? iter_node->prev : iter_node->next;
|
||||
}
|
||||
if (reversed) {
|
||||
offset += instSize(iter_node->data);
|
||||
}
|
||||
return reversed ? -offset : offset;
|
||||
}
|
||||
|
||||
void FunctionDefinition::generateByteCode(ByteCode& out) {
|
||||
|
||||
out.~ByteCode();
|
||||
new (&out) ByteCode();
|
||||
|
||||
mConstants.save(out.mConstants);
|
||||
|
||||
tp::alni inst_len = 0;
|
||||
for (auto inst_iter : mInstructions) {
|
||||
inst_len += instSize(inst_iter.data());
|
||||
}
|
||||
out.mInstructions.reserve(inst_len);
|
||||
|
||||
tp::alni idx = 0;
|
||||
for (auto inst_iter : mInstructions) {
|
||||
auto inst = inst_iter.data();
|
||||
|
||||
switch (inst.mInstType) {
|
||||
case Instruction::InstType::JUMP_IF:
|
||||
case Instruction::InstType::JUMP_IF_NOT:
|
||||
case Instruction::InstType::JUMP: {
|
||||
tp::alni offset = calcOffset(inst_iter.node(), inst.mInstTarget);
|
||||
|
||||
if (offset == 0) {
|
||||
out.mInstructions[idx] = OpCode::NONE;
|
||||
idx += 3;
|
||||
break;
|
||||
}
|
||||
|
||||
if (inst.mInstType == Instruction::InstType::JUMP_IF) {
|
||||
if (offset > 0) {
|
||||
out.mInstructions[idx] = OpCode::JUMP_IF;
|
||||
}
|
||||
else {
|
||||
out.mInstructions[idx] = OpCode::JUMP_IF_R;
|
||||
}
|
||||
}
|
||||
else if (inst.mInstType == Instruction::InstType::JUMP_IF_NOT) {
|
||||
if (offset > 0) {
|
||||
out.mInstructions[idx] = OpCode::JUMP_IF_NOT;
|
||||
}
|
||||
else {
|
||||
out.mInstructions[idx] = OpCode::JUMP_IF_NOT_R;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (offset > 0) {
|
||||
out.mInstructions[idx] = OpCode::JUMP;
|
||||
}
|
||||
else {
|
||||
out.mInstructions[idx] = OpCode::JUMP_R;
|
||||
}
|
||||
}
|
||||
|
||||
idx++;
|
||||
|
||||
tp::alni offset_mod = abs(offset);
|
||||
tp::uint2 offset_param = (tp::uint2)offset_mod;
|
||||
writeParam(out, idx, (tp::int1*)&offset_param, 2);
|
||||
break;
|
||||
}
|
||||
case Instruction::InstType::PURE_CONST: {
|
||||
writeConst(out, idx, (tp::uint2)inst.mConstData->mConstIdx);
|
||||
break;
|
||||
}
|
||||
case Instruction::InstType::EXEC: {
|
||||
out.mInstructions[idx] = inst.mOp;
|
||||
idx++;
|
||||
switch (inst.mArgType) {
|
||||
case Instruction::ArgType::PARAM: {
|
||||
writeParam(out, idx, (tp::int1*) &inst.mParam, inst.mParamBytes);
|
||||
break;
|
||||
}
|
||||
case Instruction::ArgType::CONST: {
|
||||
writeConst(out, idx, (tp::uint2)inst.mConstData->mConstIdx);
|
||||
if (inst.mConstData2) {
|
||||
writeConst(out, idx, (tp::uint2)inst.mConstData2->mConstIdx);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Instruction::ArgType::NO_ARG: {
|
||||
break;
|
||||
}
|
||||
default:{
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ASSERT(0);
|
||||
}
|
||||
case Instruction::InstType::NONE: {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tp::List<Instruction>::Node* FunctionDefinition::inst(Instruction inst) {
|
||||
mInstructions.pushBack(inst);
|
||||
auto out = &mInstructions.last()->data;
|
||||
out->mInstIdx = mInstructions.length() - 1;
|
||||
return mInstructions.last();
|
||||
}
|
||||
|
||||
static Parser* sParger = NULL;
|
||||
|
||||
void obj::BCgen::init() {
|
||||
ASSERT(!sParger);
|
||||
if (!sParger) {
|
||||
sParger = new Parser();
|
||||
}
|
||||
}
|
||||
|
||||
void obj::BCgen::deinit() {
|
||||
ASSERT(sParger);
|
||||
if (sParger) {
|
||||
delete sParger;
|
||||
}
|
||||
}
|
||||
|
||||
bool obj::BCgen::Compile(obj::MethodObject* method) {
|
||||
|
||||
ASSERT(method);
|
||||
ASSERT(sParger);
|
||||
|
||||
if (!sParger) return false;
|
||||
|
||||
auto script = method->mScript->mReadable->val;
|
||||
auto res = sParger->parse(script);
|
||||
|
||||
if (res.err) {
|
||||
auto loc = res.err->get_err_location(script.read());
|
||||
// TODO : print parse error
|
||||
// tp::gLogeer->write(tp::sfmt("Parser Error (%i,%i): \n", loc.head, loc.tail), true, tp::Logger::LogEntry::ERR);
|
||||
// tp::GLog->write(res.err->mDescr, true, tp::Logger::LogEntry::ERR);
|
||||
return false;
|
||||
}
|
||||
|
||||
BCgen::Genereate(method->mScript->mBytecode, res.scope);
|
||||
|
||||
delete res.scope;
|
||||
|
||||
return true;
|
||||
}
|
||||
29
Objects/private/compiler/instruction.cpp
Normal file
29
Objects/private/compiler/instruction.cpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
#include "compiler/instruction.h"
|
||||
|
||||
using namespace obj;
|
||||
using namespace tp;
|
||||
using namespace BCgen;
|
||||
|
||||
Instruction::Instruction(OpCode op) : mOp(op), mArgType(ArgType::NO_ARG), mInstType(InstType::EXEC) {}
|
||||
|
||||
Instruction::Instruction() : mInstType(InstType::NONE) {}
|
||||
|
||||
Instruction::Instruction(ConstObject* constData)
|
||||
: mConstData(constData), mInstType(InstType::PURE_CONST) {}
|
||||
|
||||
Instruction::Instruction(OpCode op, ConstObject* constData)
|
||||
: mOp(op), mConstData(constData), mArgType(ArgType::CONST), mInstType(InstType::EXEC) {
|
||||
}
|
||||
|
||||
Instruction::Instruction(OpCode op, ConstObject* constData, ConstObject* constData2)
|
||||
: mOp(op), mConstData(constData), mConstData2(constData2), mArgType(ArgType::CONST), mInstType(InstType::EXEC) {
|
||||
}
|
||||
|
||||
Instruction::Instruction(OpCode op, tp::alni param, tp::alni nBytes)
|
||||
: mOp(op), mParam(param), mArgType(ArgType::PARAM), mParamBytes(nBytes), mInstType(InstType::EXEC) {
|
||||
}
|
||||
|
||||
Instruction::Instruction(tp::List<Instruction>::Node* inst, InstType jump_type): mInstTarget(inst) {
|
||||
mInstType = jump_type;
|
||||
}
|
||||
116
Objects/private/compiler/statement.cpp
Normal file
116
Objects/private/compiler/statement.cpp
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
#include "NewPlacement.hpp"
|
||||
#include "compiler/statement.h"
|
||||
|
||||
using namespace obj;
|
||||
using namespace BCgen;
|
||||
|
||||
|
||||
StatementFuncDef::StatementFuncDef(tp::String function_id, tp::init_list<tp::String> args, tp::init_list<Statement*> statements) {
|
||||
mType = Type::DEF_FUNC;
|
||||
mArgs = args;
|
||||
mStatements = statements;
|
||||
mFunctionId = function_id;
|
||||
}
|
||||
|
||||
StatementLocalDef::StatementLocalDef(tp::String id, Expression* value) : mLocalId(id), mNewExpr(value) {
|
||||
mType = Type::DEF_LOCAL;
|
||||
}
|
||||
|
||||
StatementLocalDef::StatementLocalDef(tp::String id, ExpressionConst* value) : mLocalId(id), mConstExpr(value), mIsConstExpr(true) {
|
||||
mType = Type::DEF_LOCAL;
|
||||
}
|
||||
|
||||
StatementCopy::StatementCopy(Expression* left, Expression* right) : mLeft(left), mRight(right) {
|
||||
mType = Type::COPY;
|
||||
}
|
||||
|
||||
StatementReturn::StatementReturn() {
|
||||
mType = Type::RET;
|
||||
}
|
||||
|
||||
StatementReturn::StatementReturn(Expression* ret) : mRet(ret) {
|
||||
mType = Type::RET;
|
||||
}
|
||||
|
||||
StatementPrint::StatementPrint(Expression* target) : mTarget(target) {
|
||||
mType = Type::PRINT;
|
||||
}
|
||||
|
||||
StatementScope::StatementScope(tp::init_list<Statement*> statements, bool aPushToScopeStack) {
|
||||
mType = Type::SCOPE;
|
||||
mStatements = statements;
|
||||
mPushToScopeStack = aPushToScopeStack;
|
||||
}
|
||||
|
||||
StatementIf::StatementIf(Expression* condition, StatementScope* on_true, StatementScope* on_false) {
|
||||
mType = Type::IF;
|
||||
mOnFalse = on_false;
|
||||
mOnTrue = on_true;
|
||||
mCondition = condition;
|
||||
}
|
||||
|
||||
StatementWhile::StatementWhile(Expression* condition, StatementScope* scope) {
|
||||
mType = Type::WHILE;
|
||||
mScope = scope;
|
||||
mCondition = condition;
|
||||
}
|
||||
|
||||
StatementIgnore::StatementIgnore(Expression* expr) {
|
||||
mType = Type::IGNORE;
|
||||
mExpr = expr;
|
||||
}
|
||||
|
||||
StatementClassDef::StatementClassDef(tp::String class_id, StatementScope* scope) {
|
||||
mClassId = class_id;
|
||||
mScope = scope;
|
||||
mType = Type::CLASS_DEF;
|
||||
}
|
||||
// helpers
|
||||
|
||||
StatementFuncDef* obj::BCgen::StmDefFunc(tp::String id, tp::init_list<tp::String> args, tp::init_list<Statement*> stms) {
|
||||
return new StatementFuncDef(id, args, stms);
|
||||
}
|
||||
|
||||
StatementLocalDef* obj::BCgen::StmDefLocal(tp::String id, Expression* value) {
|
||||
if (value->mType == Expression::Type::CONST) {
|
||||
return new StatementLocalDef(id, (ExpressionConst*)value);
|
||||
}
|
||||
|
||||
return new StatementLocalDef(id, value);
|
||||
}
|
||||
|
||||
StatementCopy* obj::BCgen::StmCopy(Expression* left, Expression* right) {
|
||||
return new StatementCopy(left, right);
|
||||
}
|
||||
|
||||
StatementPrint* obj::BCgen::StmPrint(Expression* target) {
|
||||
return new StatementPrint(target);
|
||||
}
|
||||
|
||||
StatementReturn* obj::BCgen::StmReturn() {
|
||||
return new StatementReturn();
|
||||
}
|
||||
|
||||
StatementReturn* obj::BCgen::StmReturn(Expression* obj) {
|
||||
return new StatementReturn(obj);
|
||||
}
|
||||
|
||||
StatementIf* obj::BCgen::StmIf(Expression* condition, StatementScope* on_true, StatementScope* on_false) {
|
||||
return new StatementIf(condition, on_true, on_false);
|
||||
}
|
||||
|
||||
StatementScope* obj::BCgen::StmScope(tp::init_list<Statement*> statements, bool aPushToScopeStack = false) {
|
||||
return new StatementScope(statements, aPushToScopeStack);
|
||||
}
|
||||
|
||||
StatementWhile* obj::BCgen::StmWhile(Expression* condition, StatementScope* scope) {
|
||||
return new StatementWhile(condition, scope);
|
||||
}
|
||||
|
||||
StatementIgnore* obj::BCgen::StmIgnore(Expression* expr) {
|
||||
return new StatementIgnore(expr);
|
||||
}
|
||||
|
||||
StatementClassDef* obj::BCgen::StmClassDef(tp::String id, StatementScope* scope) {
|
||||
return new StatementClassDef(id, scope);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue