#include "daScript/misc/platform.h"
#include "daScript/ast/ast_generate.h"
#include "daScript/ast/ast_expressions.h"
#include "daScript/ast/ast_visitor.h"
namespace das {
bool isExpressionVariable(const ExpressionPtr & expr, const string & name) {
if (expr->rtti_isVar()) {
auto var = static_pointer_cast(expr);
return var->name == name;
}
return false;
}
bool isExpressionVariableDeref(const ExpressionPtr & expr, const string & name) {
if (expr->rtti_isVar()) {
auto var = static_pointer_cast(expr);
return var->name == name;
} else if (expr->rtti_isR2V()) {
auto r2v = static_pointer_cast(expr);
if (r2v->subexpr->rtti_isVar()) {
auto var = static_pointer_cast(r2v->subexpr);
return var->name == name;
}
}
return false;
}
bool isExpressionNull(const ExpressionPtr & expr) {
if (expr->rtti_isConstant() && expr->type->isPointer()) {
auto cptr = static_pointer_cast(expr);
return cptr->getValue() == nullptr;
}
return false;
}
#define VERIFY_GENERATED 0
#define LOG_GENERATED 0
struct CheckLineInfoVisitor : Visitor {
virtual void preVisitExpression ( Expression * expr ) override {
Visitor::preVisitExpression(expr);
if ( expr->rtti_isFakeContext() || expr->rtti_isFakeLineInfo() ) return;
DAS_ASSERT(expr->at.column && expr->at.line);
}
virtual void preVisit ( Structure * var ) override {
Visitor::preVisit(var);
DAS_ASSERT(var->at.column && var->at.line);
}
virtual void preVisitStructureField ( Structure * var, Structure::FieldDeclaration & decl, bool last ) override {
Visitor::preVisitStructureField(var,decl,last);
DAS_ASSERT(decl.at.column && decl.at.line);
}
virtual void preVisitLet ( ExprLet * expr, const VariablePtr & var, bool last ) override {
Visitor::preVisitLet(expr,var,last);
DAS_ASSERT(var->at.column && var->at.line);
DAS_ASSERT(expr->atInit.line);
}
virtual void preVisitGlobalLet ( const VariablePtr & var ) override {
Visitor::preVisitGlobalLet(var);
DAS_ASSERT(var->at.column && var->at.line);
}
virtual void preVisit ( Function * fn ) override {
Visitor::preVisit(fn);
DAS_ASSERT(fn->at.column && fn->at.line);
DAS_ASSERT(fn->atDecl.column && fn->atDecl.line);
}
virtual void preVisitArgument ( Function * fn, const VariablePtr & var, bool lastArg ) override {
Visitor::preVisitArgument(fn, var, lastArg);
DAS_ASSERT(var->at.column && var->at.line);
}
virtual void preVisitBlockArgument ( ExprBlock * block, const VariablePtr & var, bool lastArg ) override {
Visitor::preVisitBlockArgument(block, var, lastArg);
DAS_ASSERT(var->at.column && var->at.line);
}
};
void verifyGenerated ( const ExpressionPtr & expr ) {
(void)expr;
#if LOG_GENERATED
LOG(LogLevel::trace) isAutoOrAlias() ) {
fullyInferred = false;
}
}
};
bool isFullyInferredBlock ( ExprBlock * block ) {
CheckFullyInferred vis;
block->visit(vis);
return vis.fullyInferred;
}
// array comprehension
// invoke( $()
// let temp : Arraysubexpr->type>
// for .....
// if where ....
// push(temp, subexpr)
// return temp
ExpressionPtr generateComprehension ( ExprArrayComprehension * expr ) {
auto compName = "__acomp_" + to_string(expr->at.line);
auto pClosure = make_smart();
pClosure->at = expr->subexpr->at;
pClosure->returnType = make_smart(Type::autoinfer);
pClosure->generated = true;
// temp : Arraysubexpr->type>
auto pVar = make_smart();
pVar->generated = true;
pVar->at = expr->at;
pVar->name = compName;
pVar->type = make_smart(Type::tArray);
pVar->type->constant = false;
pVar->type->removeConstant = true;
pVar->type->firstType = make_smart(*expr->subexpr->type);
pVar->type->firstType->ref = false;
pVar->type->firstType->constant = false;
// let temp
auto pLet = make_smart();
pLet->at = expr->at;
pLet->atInit = expr->at;
pLet->visibility = static_pointer_cast(expr->exprFor)->visibility;
pLet->variables.push_back(pVar);
pClosure->list.push_back(pLet);
// disable lock check
auto pSetLockCheck = make_smart(expr->at, "set_verify_array_locks");
pSetLockCheck->alwaysSafe = true;
pSetLockCheck->arguments.push_back(make_smart(expr->at,compName));
pSetLockCheck->arguments.push_back(make_smart(false));
pClosure->list.push_back(pSetLockCheck);
// push(temp, subexpr)
auto pPushVal = make_smart();
pPushVal->at = expr->at;
pPushVal->name = compName;
auto pPush = make_smart();
pPush->generated = true;
pPush->at = expr->at;
pPush->name = expr->subexpr->type->canCopy() ? "push" : "emplace";
pPush->arguments.push_back(pPushVal);
pPush->arguments.push_back(expr->subexpr->clone());
// for ...
auto pForBlock = make_smart();
pForBlock->at = expr->at;
pForBlock->inTheLoop = true;
if ( expr->exprWhere ) {
// push block
auto pPushBlock = make_smart();
pPushBlock->at = expr->at;
pPushBlock->list.push_back(pPush);
// for .... if where ... push
auto pIf = make_smart();
pIf->at = expr->at;
pIf->cond = expr->exprWhere->clone();
pIf->if_true = pPushBlock;
pForBlock->list.push_back(pIf);
} else {
// for .... push
pForBlock->list.push_back(pPush);
}
auto pFor = static_pointer_cast(expr->exprFor->clone());
pFor->body = pForBlock;
pClosure->list.push_back(pFor);
// enable lock check
auto pResetLockCheck = make_smart(expr->at, "set_verify_array_locks");
pResetLockCheck->alwaysSafe = true;
pResetLockCheck->arguments.push_back(make_smart(expr->at,compName));
pResetLockCheck->arguments.push_back(make_smart(true));
pClosure->list.push_back(pResetLockCheck);
// return temp
auto pVal = make_smart();
pVal->at = expr->at;
pVal->name = compName;
auto pRet = make_smart();
pRet->at = expr->at;
pRet->subexpr = pVal;
pRet->moveSemantics = true;
pRet->fromComprehension = true;
pRet->skipLockCheck = true;
pClosure->list.push_back(pRet);
// make block
auto pMakeBlock = make_smart(expr->at,pClosure);
// invoke
auto pInvoke = make_smart(expr->at, "invoke");
pInvoke->arguments.push_back(pMakeBlock);
return pInvoke;
}
// array comprehension
// generator( $()
// for .....
// if where ....
// yield subexpr
// return false
ExpressionPtr generateComprehensionIterator ( ExprArrayComprehension * expr ) {
auto pClosure = make_smart();
pClosure->at = expr->subexpr->at;
pClosure->returnType = make_smart(Type::autoinfer);
// yield subexpr
auto pYield = make_smart(expr->at, expr->subexpr->clone());
if ( !expr->subexpr->type->canCopy() ) {
pYield->moveSemantics = true;
pYield->skipLockCheck = true;
}
// for ...
auto pForBlock = make_smart();
pForBlock->at = expr->at;
pForBlock->inTheLoop = true;
if ( expr->exprWhere ) {
// yield block
auto pPushBlock = make_smart();
pPushBlock->at = expr->at;
pPushBlock->list.push_back(pYield);
// for .... if where ... yield
auto pIf = make_smart();
pIf->at = expr->at;
pIf->cond = expr->exprWhere->clone();
pIf->if_true = pPushBlock;
pForBlock->list.push_back(pIf);
} else {
// for .... yield
pForBlock->list.push_back(pYield);
}
auto pFor = static_pointer_cast(expr->exprFor->clone());
pFor->body = pForBlock;
pClosure->list.push_back(pFor);
// return false
auto pRet = make_smart();
pRet->at = expr->at;
pRet->subexpr = make_smart(expr->at, false);
pClosure->list.push_back(pRet);
// make block
auto pMakeBlock = make_smart(expr->at,pClosure);
// generator
auto pMkGen = make_smart(expr->at, pMakeBlock);
pMkGen->iterType = make_smart(*expr->subexpr->type);
return pMkGen;
}
/* a->b(args) is short for invoke(a.b, cast deref(a), args) */
ExprInvoke * makeInvokeMethod ( const LineInfo & at, Expression * a, const string & b ) {
auto pInvoke = new ExprInvoke(at, "invoke");
auto pAt = make_smart(at, a->clone(), b);
pInvoke->arguments.push_back(pAt);
pInvoke->isInvokeMethod = true;
auto pCast = make_smart();
pCast->at = at;
pCast->castType = make_smart(Type::autoinfer);
pCast->subexpr = make_smart(at,a);
pCast->subexpr->alwaysSafe = true;
pInvoke->arguments.push_back(pCast);
return pInvoke;
}
ExpressionPtr makeDelete ( const VariablePtr & var ) {
auto eUns = make_smart(var->at);
auto bod = make_smart();
bod->at = var->at;
eUns->body = bod;
auto eVar = make_smart(var->at, var->name);
auto del = make_smart(var->at, eVar);
bod->list.push_back(del);
return eUns;
}
// return [[t()]]
FunctionPtr makeConstructor ( Structure * str ) {
auto fn = make_smart();
fn->generated = true;
fn->name = str->name;
fn->at = fn->atDecl = str->at;
fn->result = make_smart(str);
if ( str->isClass ) {
fn->isClassMethod = true;
fn->classParent = str;
DAS_ASSERT(fn->classParent);
}
if ( str->macroInterface ) fn->macroFunction = true;
auto block = make_smart();
block->at = str->at;
auto makeT = make_smart(str->at);
makeT->useInitializer = false;
for ( auto & f : str->fields ) {
if ( f.init ) {
makeT->useInitializer = true;
break;
}
}
makeT->makeType = make_smart(str);
makeT->structs.push_back(make_smart());
auto returnDecl = make_smart(str->at,makeT);
returnDecl->moveSemantics = true;
block->list.push_back(returnDecl);
fn->body = block;
verifyGenerated(fn->body);
return fn;
}
// def clone(a,b:structure)
// a.f1 := b.f1
// a.f2 := b.f2
// ...
FunctionPtr makeClone ( Structure * str ) {
auto varA = make_smart();
varA->name = "a";
varA->type = make_smart(str);
varA->type->isExplicit = true;
varA->at = str->at;
auto varB = make_smart();
varB->name = "b";
varB->type = make_smart(str);
varB->type->constant = true;
varB->type->implicit = true;
varB->at = str->at;
auto fn = make_smart();
fn->name = "clone";
fn->generated = true;
fn->safeImplicit = true;
fn->privateFunction = true;
fn->at = fn->atDecl = str->at;
fn->result = make_smart();
fn->arguments.push_back(varA);
fn->arguments.push_back(varB);
auto block = make_smart();
block->at = str->at;
for ( auto & fi : str->fields ) {
auto lA = make_smart(fi.at, "a");
auto lAdotF = make_smart(fi.at, lA, fi.name);
auto lB = make_smart(fi.at, "b");
auto lBdotF = make_smart(fi.at, lB, fi.name);
auto cl = make_smart(fi.at, lAdotF, lBdotF);
block->list.push_back(cl);
}
fn->body = block;
verifyGenerated(fn->body);
return fn;
}
void wrapInUnsafe ( const FunctionPtr & func ) {
auto blk = make_smart();
blk->at = func->body->at;
auto usa = make_smart(func->body->at);
usa->body = func->body;
blk->list.push_back(usa);
func->body = blk;
}
FunctionPtr generatePointerFinalizer ( const TypeDeclPtr & ptrType, const LineInfo & at ) {
auto pFunc = make_smart();
pFunc->privateFunction = true;
pFunc->generated = true;
pFunc->at = pFunc->atDecl = at;
pFunc->name = "finalize";
auto THIS0 = make_smart(at, "__this");
auto NULLP0 = make_smart(at);
auto NEQ = make_smart(at, "!=", THIS0, NULLP0);
auto ifb = make_smart();
ifb->at = at;
if ( ptrType->firstType && ptrType->firstType->isClass() ) {
if ( ptrType->firstType->structType->macroInterface ) pFunc->macroFunction = true;
auto sizvar = make_smart(); // let __size = class_rtti_size(__this)
auto vsiz = make_smart();
vsiz->at = at;
vsiz->name = "__size";
vsiz->type = make_smart(Type::autoinfer);
vsiz->type->constant = true;
auto crs = make_smart(at,"class_rtti_size");
crs->arguments.push_back(make_smart(at,"__this"));
vsiz->init = crs;
//vsiz->init = make_sm
sizvar->variables.push_back(vsiz);
ifb->list.push_back(sizvar);
auto invk = new ExprInvoke(at, "invoke"); // invoke(__this,__this.__finalize)
auto THISA = make_smart(at, "__this");
auto pAt = make_smart(at, THISA, "__finalize");
invk->arguments.push_back(pAt);
auto pCast = make_smart();
pCast->at = at;
pCast->castType = make_smart(Type::autoinfer);
auto THISAA = make_smart(at, "__this");
pCast->subexpr = make_smart(at,THISAA);
pCast->subexpr->alwaysSafe = true;
invk->arguments.push_back(pCast);
ifb->list.push_back(invk);
auto THISA1 = make_smart(at, "__this"); // delete /*native*/ this, __size
auto delit1 = make_smart(at, THISA1);
delit1->native = true;
delit1->sizeexpr = make_smart(at,"__size");
ifb->list.push_back(delit1);
} else {
auto THISA = make_smart(at, "__this"); // delete * this
auto THISR = make_smart(at, THISA);
auto delit = make_smart(at, THISR);
ifb->list.push_back(delit);
auto THISA1 = make_smart(at, "__this"); // delete /*native*/ this
auto delit1 = make_smart(at, THISA1);
delit1->native = true;
ifb->list.push_back(delit1);
}
auto THISB = make_smart(at, "__this"); // *THIS = null
auto NULLP = make_smart(at);
auto SETB = make_smart(at, THISB, NULLP);
ifb->list.push_back(SETB);
auto ife = make_smart(at, NEQ, ifb, nullptr);
auto fb = make_smart();
fb->at = at;
fb->list.push_back(ife);
pFunc->body = fb;
pFunc->result = make_smart(Type::tVoid);
auto cTHIS = make_smart();
cTHIS->name = "__this";
cTHIS->at = at;
cTHIS->type = make_smart(*ptrType);
cTHIS->type->constant = false;
cTHIS->type->removeConstant = true;
cTHIS->type->ref = true;
cTHIS->type->removeRef = false;
cTHIS->type->isExplicit = true;
pFunc->arguments.push_back(cTHIS);
wrapInUnsafe(pFunc);
verifyGenerated(pFunc->body);
return pFunc;
}
FunctionPtr generateStructureFinalizer ( const StructurePtr & ls ) {
auto pFunc = make_smart();
pFunc->privateFunction = true;
pFunc->generated = true;
pFunc->at = pFunc->atDecl = ls->at;
pFunc->name = "finalize";
if ( ls->isClass ) {
pFunc->isClassMethod = true;
pFunc->classParent = ls.get();
DAS_ASSERT(pFunc->classParent);
}
if ( ls->macroInterface ) pFunc->macroFunction = true;
auto fb = make_smart();
fb->at = ls->at;
// now finalize
bool needUnsafe = false;
for ( const auto & fl : ls->fields ) {
if ( !fl.type->constant && !fl.capturedConstant && fl.type->needDelete() ) {
if ( !fl.doNotDelete && !fl.capturedRef ) {
if ( fl.type->isPointer() && fl.type->firstType && fl.type->firstType->constant ) continue;
auto fva = make_smart(fl.at, "__this");
auto fld = make_smart(fl.at, fva, fl.name);
fld->ignoreCaptureConst = true;
auto delf = make_smart(fl.at, fld);
fb->list.emplace_back(delf);
if ( fl.type->isPointer() ) {
needUnsafe = true;
}
}
}
}
auto mz = make_smart(ls->at, "memzero");
auto lvar = make_smart(ls->at, "__this");
mz->arguments.push_back(lvar);
fb->list.push_back(mz);
pFunc->body = fb;
pFunc->result = make_smart(Type::tVoid);
auto cTHIS = make_smart();
cTHIS->at = ls->at;
cTHIS->name = "__this";
cTHIS->type = make_smart(ls);
cTHIS->type->isExplicit = true;
pFunc->arguments.push_back(cTHIS);
if ( needUnsafe ) {
wrapInUnsafe(pFunc);
}
verifyGenerated(pFunc->body);
return pFunc;
}
FunctionPtr generateLambdaFinalizer ( const string & lambdaName, ExprBlock * block,
const StructurePtr & ls ) {
auto lfn = lambdaName + "`finalizer";
auto pFunc = make_smart();
pFunc->privateFunction = true;
pFunc->generated = true;
pFunc->at = pFunc->atDecl = block->at;
pFunc->name = lfn;
auto fb = make_smart();
fb->at = block->at;
// fb->list.push_back(genComment("delete this lambda\n"));
if ( block->finalList.size() ) {
auto with = make_smart(block->at);
auto THISVAR = make_smart(block->at, "__this");
with->with = make_smart(block->at, THISVAR);
with->with->generated = true;
auto bbl = make_smart();
with->body = bbl;
with->body->at = block->at;
bbl->list.reserve(block->finalList.size()); // copy finally section of the block body
for ( auto & subexpr : block->finalList ) {
bbl->list.push_back(subexpr->clone());
}
fb->list.push_back(with);
}
// delete * this
auto THISA = make_smart(block->at, "__this");
auto THISAP = make_smart(block->at, THISA);
auto delit = make_smart(block->at, THISAP);
fb->list.push_back(delit);
// delete this
auto THISA1 = make_smart(block->at, "__this");
auto delit1 = make_smart(block->at, THISA1);
delit1->native = true;
delit1->alwaysSafe = true;
fb->list.push_back(delit1);
pFunc->body = fb;
pFunc->result = make_smart(Type::tVoid);
auto cTHIS = make_smart();
cTHIS->at = ls->at;
cTHIS->name = "__this";
cTHIS->type = make_smart(Type::tPointer);
cTHIS->type->firstType = make_smart(ls);
cTHIS->type->isExplicit = true;
pFunc->arguments.push_back(cTHIS);
// wrapInUnsafe(pFunc);
verifyGenerated(pFunc->body);
return pFunc;
}
FunctionPtr generateLocalFunction ( const string & lambdaName, ExprBlock * block ) {
auto lfn = lambdaName + "`function";
auto pFunc = make_smart();
pFunc->generated = true;
pFunc->at = pFunc->atDecl = block->at;
pFunc->name = lfn;
pFunc->body = block->clone();
pFunc->privateFunction = true;
auto wb = static_pointer_cast(pFunc->body);
wb->blockFlags = 0;
wb->arguments.clear();
wb->returnType.reset();
pFunc->result = make_smart(*block->type);
for ( auto & arg : block->arguments ) {
auto cA = arg->clone();
cA->marked_used = true;
pFunc->arguments.push_back(cA);
}
verifyGenerated(pFunc->body);
return pFunc;
}
bool isCaptureAsRef ( const VariablePtr & var ) {
return var->capture_as_ref;
}
FunctionPtr generateLambdaFunction ( const string & lambdaName, ExprBlock * block,
const StructurePtr & ls, const safe_var_set & capt,
const vector & capture, uint32_t genFlags, Program * thisProgram ) {
auto lfn = lambdaName + "`function";
auto pFunc = make_smart();
pFunc->lambda = true;
pFunc->generated = true;
pFunc->at = pFunc->atDecl = block->at;
pFunc->name = lfn;
pFunc->privateFunction = true;
pFunc->requestJit = (genFlags & generator_jit)!=0;
auto fb = make_smart();
fb->at = block->at;
auto with = make_smart(block->at);
with->with = make_smart(block->at, "__this");
with->with->generated = true;
with->body = block->clone();
static_pointer_cast(with->body)->finalList.clear();
if ( genFlags & generator_needYield ) {
pFunc->generator = true;
auto bbl = static_pointer_cast(with->body);
// goto __yeild
auto gvar = make_smart(block->at, "__yield");
auto gexpr = make_smart(block->at, static_pointer_cast(gvar));
bbl->list.insert(bbl->list.begin(), gexpr);
// label "0"
auto lzero = make_smart(block->at, pFunc->totalGenLabel);
bbl->list.insert(bbl->list.begin() + 1, lzero);
pFunc->totalGenLabel ++;
}
auto wb = static_pointer_cast(with->body);
wb->blockFlags = 0;
wb->arguments.clear();
wb->returnType.reset();
fb->list.push_back(with);
pFunc->body = fb;
pFunc->result = make_smart(*block->type);
auto cTHIS = make_smart();
cTHIS->generated = true;
cTHIS->at = block->at;
cTHIS->name = "__this";
cTHIS->type = make_smart(ls);
cTHIS->type->isExplicit = true;
pFunc->arguments.push_back(cTHIS);
for ( auto & arg : block->arguments ) {
auto cA = arg->clone();
cA->marked_used = true; // to avoid 'unused argument' error
pFunc->arguments.push_back(cA);
}
for ( auto & var : capt ) {
CaptureMode mode = CaptureMode::capture_any;
auto it = find_if ( capture.begin(), capture.end(), [&] ( const auto & entry ){
return entry.name == var->name;
});
if ( it != capture.end() ) {
mode = it->mode;
}
if ( isCaptureAsRef(var) || mode==CaptureMode::capture_by_reference ) {
replaceRef2Ptr(pFunc->body, var->name);
}
}
thisProgram->library.foreach([&](Module * mod){
for ( auto & cm : mod->captureMacros ) {
cm->captureFunction(thisProgram, thisProgram->thisModule.get(), ls.get(), pFunc.get());
}
return true;
},"*");
verifyGenerated(pFunc->body);
return pFunc;
}
StructurePtr generateLambdaStruct ( const string & lambdaName, ExprBlock * block,
const safe_var_set & capt,
const vector & capture, bool needYield ) {
auto lsn = lambdaName;
auto pStruct = make_smart(lsn);
pStruct->generated = true;
pStruct->isLambda = true;
pStruct->at = block->at;
auto btd = block->makeBlockType();
btd->baseType = Type::tFunction;
btd->constant = false;
auto thisArg = make_smart(pStruct);
btd->argTypes.insert(btd->argTypes.begin(), thisArg);
btd->argNames.insert(btd->argNames.begin(), "__this");
pStruct->fields.emplace_back("__lambda", btd, nullptr, AnnotationArgumentList(), false, block->at);
pStruct->fields.back().generated = true;
pStruct->fields.back().type->sanitize();
auto finFunc = make_smart(Type::tFunction);
auto finArg = make_smart(Type::tPointer);
finArg->firstType = make_smart(pStruct);
finArg->constant = false;
finArg->removeConstant = true;
finFunc->argTypes.push_back(finArg);
finFunc->argNames.push_back("__this");
finFunc->firstType = make_smart(Type::tVoid);
pStruct->fields.emplace_back("__finalize", finFunc, nullptr, AnnotationArgumentList(), false, block->at);
pStruct->fields.back().generated = true;
pStruct->fields.back().type->sanitize();
if ( needYield ) {
auto yt = make_smart(Type::tInt);
pStruct->fields.emplace_back("__yield", yt, nullptr, AnnotationArgumentList(), false, block->at);
auto & fldb = pStruct->fields.back();
fldb.generated = true;
fldb.type->sanitize();
}
for ( auto var : capt ) {
auto td = make_smart(*var->type);
td->constant = false;
CaptureMode mode = CaptureMode::capture_any;
auto it = find_if ( capture.begin(), capture.end(), [&] ( const auto & entry ){
return entry.name == var->name;
});
if ( it != capture.end() ) {
mode = it->mode;
}
if ( isCaptureAsRef(var) || mode==CaptureMode::capture_by_reference ) {
td->ref = false;
auto ptd = make_smart(Type::tPointer);
ptd->firstType = td;
td = ptd;
pStruct->fields.emplace_back(var->name, td, nullptr, AnnotationArgumentList(), false, var->at);
auto & bfld = pStruct->fields.back();
bfld.capturedConstant = var->type->constant;
bfld.capturedRef = true;
bfld.type->sanitize();
} else {
td->ref = false;
pStruct->fields.emplace_back(var->name, td, nullptr, AnnotationArgumentList(), false, var->at);
auto & bfld = pStruct->fields.back();
bfld.capturedConstant = var->type->constant;
if ( mode==CaptureMode::capture_by_move || mode==CaptureMode::capture_by_clone ) {
bfld.doNotDelete = true;
}
bfld.type->sanitize();
}
}
return pStruct;
}
ExpressionPtr generateLambdaMakeStruct ( const StructurePtr & ls, const FunctionPtr & lf, const FunctionPtr & lff,
const safe_var_set & capt, const vector & capture, const LineInfo & at,
Program * thisProgram ) {
auto asc = new ExprAscend();
asc->at = at;
asc->needTypeInfo = true;
auto makeS = make_smart();
// makeS->useInitializer = true;
makeS->at = at;
makeS->makeType = make_smart(ls);
auto ms = make_smart();
auto atTHIS = make_smart(lf->at, "_::" + lf->name);
// TODO: expand atTHIS->funcType, so that it points to correct function by type as well
auto mTHIS = make_smart(lf->at, "__lambda", atTHIS, false, false);
ms->push_back(mTHIS);
auto atTHISF = make_smart(lff->at, "_::" + lff->name);
auto mTHISF = make_smart(lf->at, "__finalize", atTHISF, false, false);
ms->push_back(mTHISF);
for ( auto cV : capt ) {
CaptureMode mode = CaptureMode::capture_any;
auto it = find_if ( capture.begin(), capture.end(), [&] ( const auto & entry ){
return entry.name == cV->name;
});
if ( it != capture.end() ) {
mode = it->mode;
}
if ( isCaptureAsRef(cV) || mode==CaptureMode::capture_by_reference ) {
auto varV = make_smart(cV->at, cV->name);
auto addrV = make_smart(cV->at, varV);
addrV->alwaysSafe = true;
auto mV = make_smart(cV->at, cV->name, addrV, false, false);
ms->push_back(mV);
} else {
bool moveS = false;
bool cloneS = false;
switch ( mode ) {
case CaptureMode::capture_by_clone: cloneS = true; break;
case CaptureMode::capture_by_move: moveS = true; break;
case CaptureMode::capture_any: moveS = !cV->type->canCopy(); break;
default: ;
}
auto varV = make_smart(cV->at, cV->name);
auto mV = make_smart(cV->at, cV->name, varV, moveS, cloneS);
ms->push_back(mV);
}
auto & lexpr = ms->back();
thisProgram->library.foreach([&](Module * mod){
for ( auto & cm : mod->captureMacros ) {
auto cexpr = cm->captureExpression(thisProgram, thisProgram->thisModule.get(), lexpr->value.get(), cV->type.get());
if ( cexpr != nullptr ) {
lexpr->value = cexpr;
}
}
return true;
},"*");
}
makeS->structs.push_back(ms);
asc->subexpr = makeS;
asc->ascType = make_smart(*ls->fields[0].type);
asc->ascType->argTypes.erase(asc->ascType->argTypes.begin());
asc->ascType->argNames.erase(asc->ascType->argNames.begin());
asc->ascType->baseType = Type::tLambda;
auto res = ExpressionPtr(asc);
verifyGenerated(res);
return res;
}
// rename variable to unique name variable
string aotSuffixNameEx ( const string & funcName, const char * suffix );
class RenameVar : public Visitor {
public:
virtual void preVisit ( ExprBlock * block ) override {
Visitor::preVisit(block);
scopes.push_back(block);
}
virtual ExpressionPtr visit ( ExprBlock * block ) override {
scopes.pop_back();
return Visitor::visit(block);
}
virtual void preVisit ( ExprLet * expr ) override {
Visitor::preVisit(expr);
if ( scopes.size()==1 ) { // only top level block
for ( auto & var : expr->variables ) {
if ( var->name[0]!='_' || var->name[1]!='_' ) {
string newName = "__" + aotSuffixNameEx(var->name,"_Var") + "_rename_at_" + to_string(var->at.line);
rename[var->name] = newName;
var->name = newName;
}
}
}
}
virtual void preVisit ( ExprVar * expr ) override {
if ( !scopes.size() ) return;
auto it = rename.find(expr->name);
if ( it != rename.end() ) {
expr->name = it->second;
}
}
protected:
vector scopes;
das_hash_map rename;
};
void giveBlockVariablesUniqueNames ( const ExpressionPtr & expr ) {
RenameVar rename;
expr->visit(rename);
}
// rename variable
class RenameBlockArgument : public Visitor {
public:
RenameBlockArgument ( const string & name, const string & newName, ExprBlock * block )
: argName(name), argNewName(newName), renameBlock(block) {
}
virtual void preVisit ( ExprBlock * block ) override {
Visitor::preVisit(block);
scopes.push_back(block);
}
virtual ExpressionPtr visit ( ExprBlock * block ) override {
scopes.pop_back();
return Visitor::visit(block);
}
virtual void preVisit ( ExprVar * expr ) override {
if ( !scopes.empty() ) {
auto thisBlock = scopes.back();
if ( expr->name==argName && expr->block && renameBlock==thisBlock ) {
expr->name = argNewName;
}
}
}
protected:
string argName;
string argNewName;
ExprBlock * renameBlock;
vector scopes;
};
void renameBlockArgument ( ExprBlock * block, const string & name, const string & newName ) {
RenameBlockArgument vis(name,newName,block);
block->visit(vis);
}
// replace ref to ptr
class Ref2PtrVisitor : public Visitor {
public:
Ref2PtrVisitor ( const string & n ) : varName(n) {}
virtual ExpressionPtr visit ( ExprVar * expr ) override {
if ( expr->name==varName ) {
return make_smart(expr->at, expr);
}
return Visitor::visit(expr);
}
protected:
string varName;
};
void replaceRef2Ptr ( const ExpressionPtr & expr, const string & name ) {
Ref2PtrVisitor r2ptr(name);
expr->visit(r2ptr);
}
// replace break and continue with 'goto label' for the specific loop
class BreakAndContinueVisitor : public Visitor {
public:
BreakAndContinueVisitor ( int32_t bg, int32_t cg )
: breakGoto(bg), continueGoto(cg) {
}
virtual void preVisit ( ExprWhile * expr ) override {
Visitor::preVisit(expr);
depth ++;
}
virtual ExpressionPtr visit(ExprWhile *expr) override {
depth --;
return Visitor::visit(expr);
}
virtual void preVisit ( ExprFor * expr ) override {
Visitor::preVisit(expr);
depth ++;
}
virtual ExpressionPtr visit(ExprFor *expr) override {
depth --;
return Visitor::visit(expr);
}
virtual ExpressionPtr visit(ExprBreak *expr) override {
if ( depth ) return Visitor::visit(expr);
return make_smart(expr->at, breakGoto);
}
virtual ExpressionPtr visit(ExprContinue *expr) override {
if ( depth ) return Visitor::visit(expr);
return make_smart(expr->at, continueGoto);
}
protected:
int32_t breakGoto;
int32_t continueGoto;
int depth = 0;
};
void replaceBreakAndContinue ( Expression * expr, int32_t bg, int32_t cg ) {
BreakAndContinueVisitor rbnc(bg, cg);
expr->visit(rbnc);
}
ExpressionPtr generateYield( ExprYield * expr, const FunctionPtr & func ) {
const auto & yarg = func->arguments[1];
// TODO: verify yield type so that error is 'yield' error, not copy or move error
auto LabelX = func->totalGenLabel ++;
auto blk = make_smart();
blk->isCollapseable = true;
blk->at = expr->at;
bool makeRef = false;
if ( func->arguments.size()==2 ) { // starts with _ryield
const auto & argn = func->arguments[1]->name;
if ( argn.length()>=7 ) {
makeRef = memcmp ( argn.c_str(), "_ryield", 7 ) == 0;
}
}
if ( expr->moveSemantics ) {
// TODO: error on makeRef + moveSemantics
// result at, yarg->name);
auto mfr = expr->subexpr->clone();
auto mve = make_smart(expr->at, mto, mfr);
mve->skipLockCheck = expr->skipLockCheck;
blk->list.push_back(mve);
} else {
// result = a
auto cto = make_smart(expr->at, yarg->name);
auto cfr = expr->subexpr->clone();
if ( makeRef ) {
cfr = make_smart(expr->at, cfr);
cfr->alwaysSafe = true;
}
auto cpy = make_smart(expr->at, cto, cfr);
cpy->allowCopyTemp = true; // this is for generators which return temp# values
blk->list.push_back(cpy);
}
// yield = X
auto yyx = make_smart(expr->at, "__yield");
auto clx = make_smart(expr->at, LabelX);
auto cpy = make_smart(expr->at, yyx, clx);
blk->list.push_back(cpy);
// return true
auto btr = make_smart(expr->at, true);
auto rex = make_smart(expr->at, btr);
rex->fromYield = true;
blk->list.push_back(rex);
auto lbx = make_smart(expr->at, LabelX,
"yield at line " + to_string(expr->at.line));
blk->list.push_back(lbx);
verifyGenerated(blk);
return blk;
}
ExpressionPtr replaceGeneratorLet ( ExprLet * expr, const FunctionPtr & func, ExprBlock * scope ) {
auto blk = make_smart();
blk->at = expr->at;
blk->isCollapseable = true;
auto capture = func->arguments[0]->type->structType;
DAS_ASSERT(capture && "generator first argument is lambda capture");
for ( auto & var : expr->variables ) {
auto vtd = make_smart(*var->type);
bool isRef = vtd->ref;
if ( isRef ) {
auto pvtd = make_smart(Type::tPointer);
pvtd->firstType = vtd;
vtd->ref = false;
vtd = pvtd;
replaceRef2Ptr(scope, var->name);
} else {
vtd->constant = false;
}
capture->fields.emplace_back(var->name,
vtd,
nullptr,
AnnotationArgumentList(),
false,
expr->at);
auto & fldb = capture->fields.back();
if ( isRef || var->do_not_delete ) {
fldb.doNotDelete = true;
}
fldb.capturedConstant = var->type->constant;
auto cvar = make_smart(var->at, func->arguments[0]->name);
auto lvar = make_smart(var->at, cvar, var->name);
lvar->ignoreCaptureConst = true;
if ( var->init ) {
auto rini = var->init->clone();
if ( isRef ) {
auto arini = make_smart(expr->at, rini);
arini->alwaysSafe = true;
rini = arini;
}
if ( var->init_via_clone ) {
auto cln = make_smart(var->at, lvar, rini);
blk->list.push_back(cln);
} else if ( var->init_via_move ) {
auto mve = make_smart(var->at, lvar, rini);
blk->list.push_back(mve);
} else {
auto cpy = make_smart(var->at, lvar, rini);
blk->list.push_back(cpy);
}
} else {
auto mz = make_smart(var->at, "memzero");
mz->arguments.push_back(lvar);
blk->list.push_back(mz);
}
}
verifyGenerated(blk);
return blk;
}
ExpressionPtr replaceGeneratorIfThenElse ( ExprIfThenElse * expr, const FunctionPtr & func ) {
auto blk = make_smart();
blk->at = expr->at;
blk->isCollapseable = true;
if ( expr->if_false ) {
auto else_label = func->totalGenLabel ++;
auto end_label = func->totalGenLabel ++;
auto gtel = make_smart(expr->at, else_label);
auto btel = make_smart();
btel->at = expr->at;
btel->list.push_back(gtel);
auto ncnd = make_smart(expr->cond->at, "!", expr->cond->clone());
auto ifnc = make_smart(expr->at, ncnd, btel, nullptr);
blk->list.push_back(ifnc);
auto ift = expr->if_true->clone();
if ( ift->rtti_isBlock() ){
auto iftb = static_pointer_cast(ift);
iftb->isCollapseable = true;
giveBlockVariablesUniqueNames(ift);
}
blk->list.push_back(ift);
auto gten = make_smart(expr->at, end_label);
blk->list.push_back(gten);
auto elsel = make_smart(expr->at, else_label,
"else if at line " + to_string(expr->at.line));
blk->list.push_back(elsel);
auto iff = expr->if_false->clone();
if ( iff->rtti_isBlock() ){
auto iffb = static_pointer_cast(iff);
iffb->isCollapseable = true;
giveBlockVariablesUniqueNames(iff);
}
blk->list.push_back(iff);
auto enddl = make_smart(expr->at, end_label,
"end if at line " + to_string(expr->at.line));
blk->list.push_back(enddl);
} else {
auto end_label = func->totalGenLabel ++;
auto gtel = make_smart(expr->at, end_label);
auto btel = make_smart();
btel->at = expr->at;
btel->list.push_back(gtel);
auto ncnd = make_smart(expr->cond->at, "!", expr->cond->clone());
auto ifnc = make_smart(expr->at, ncnd, btel, nullptr);
blk->list.push_back(ifnc);
auto ift = expr->if_true->clone();
if ( ift->rtti_isBlock() ){
auto iftb = static_pointer_cast(ift);
iftb->isCollapseable = true;
giveBlockVariablesUniqueNames(ift);
}
blk->list.push_back(ift);
auto enddl = make_smart(expr->at, end_label,
"end if at line " + to_string(expr->at.line));
blk->list.push_back(enddl);
}
verifyGenerated(blk);
return blk;
}
ExpressionPtr replaceGeneratorWhile ( ExprWhile * expr, const FunctionPtr & func ) {
auto begin_loop_label = func->totalGenLabel ++;
auto end_loop_label = func->totalGenLabel ++;
smart_ptr bodyBlock;
if ( expr->body->rtti_isBlock() ) {
bodyBlock = static_pointer_cast(expr->body->clone());
giveBlockVariablesUniqueNames(bodyBlock);
replaceBreakAndContinue(bodyBlock.get(), end_loop_label, begin_loop_label);
}
auto blk = make_smart();
blk->at = expr->at;
blk->isCollapseable = true;
auto bll = make_smart(expr->at, begin_loop_label,
"begin while at line " + to_string(expr->at.line));
blk->list.push_back(bll);
auto gtel = make_smart(expr->at, end_loop_label);
auto btel = make_smart();
btel->at = expr->at;
btel->list.push_back(gtel);
auto ncnd = make_smart(expr->cond->at, "!", expr->cond->clone());
auto ifnc = make_smart(expr->at, ncnd, btel, nullptr);
blk->list.push_back(ifnc);
if ( bodyBlock ) {
for ( auto & bse : bodyBlock->list ) {
blk->list.push_back(bse->clone());
}
} else {
blk->list.push_back(expr->body->clone());
}
auto gbeg = make_smart(expr->at, begin_loop_label);
blk->list.push_back(gbeg);
auto ell = make_smart(expr->at, end_loop_label,
"end while at line " + to_string(expr->at.line));
blk->list.push_back(ell);
if ( bodyBlock && !bodyBlock->finalList.empty() ) { // finally, if we have it
for ( auto & fse : bodyBlock->finalList ) {
blk->list.push_back(fse->clone());
}
}
verifyGenerated(blk);
return blk;
}
ExpressionPtr replaceGeneratorFor ( ExprFor * expr, const FunctionPtr & func ) {
auto begin_loop_label = func->totalGenLabel ++;
auto mid_loop_label = func->totalGenLabel ++;
auto end_loop_label = func->totalGenLabel ++;
smart_ptr bodyBlock;
if ( expr->body->rtti_isBlock() ) {
bodyBlock = static_pointer_cast(expr->body->clone());
giveBlockVariablesUniqueNames(bodyBlock);
replaceBreakAndContinue(bodyBlock.get(), end_loop_label, mid_loop_label);
}
auto blk = make_smart();
blk->at = expr->at;
blk->isCollapseable = true;
auto gtel = make_smart(expr->at, end_loop_label);
auto btel = make_smart();
btel->at = expr->at;
btel->list.push_back(gtel);
// names
string loopVar = "_loop_at_" + to_string(expr->at.line);
vector srcNames, pVarNames;
for ( size_t si=0, sis=expr->sources.size(); si!=sis; ++si ) {
srcNames.push_back("_source_" + to_string(si) + "_at_" + to_string(expr->at.line));
pVarNames.push_back("_pvar_" + to_string(si) + "_at_" + to_string(expr->at.line));
}
auto leqt = make_smart();
leqt->at = expr->at;
leqt->atInit = expr->at;
leqt->visibility = expr->visibility;
auto lvar = make_smart();
lvar->generated = true;
lvar->at = expr->at;
lvar->name = loopVar;
lvar->type = make_smart(Type::tBool);
lvar->init = make_smart(expr->at, true);
leqt->variables.push_back(lvar);
blk->list.push_back(leqt);
// sources
for ( size_t si=0, sis=expr->sources.size(); si!=sis; ++si ) {
const string & srcName = srcNames[si];
const string & pVarName = pVarNames[si];
const string & srcVarName = expr->iterators[si];
const auto & src = expr->sources[si];
const auto & iterv = expr->iteratorVariables[si];
// let src0 = each(blah) or let src0 = blah if its iterator
auto seqt = make_smart();
seqt->at = expr->at;
seqt->atInit = expr->at;
seqt->visibility = expr->visibility;
auto svar = make_smart();
svar->generated = true;
svar->at = expr->at;
svar->name = srcName;
svar->type = make_smart(Type::autoinfer);
svar->init_via_move = true;
if ( src->type->isGoodIteratorType() ) {
svar->init = src->clone();
} else {
auto ceach = make_smart(expr->at, "each");
ceach->generated = true;
ceach->alwaysSafe = true;
ceach->arguments.push_back(src->clone());
svar->init = ceach;
}
seqt->variables.push_back(svar);
blk->list.push_back(seqt);
// let it0 : type_of_iterable
auto srci = make_smart();
srci->at = expr->at;
srci->atInit = expr->at;
srci->visibility = expr->visibility;
auto srcv = make_smart();
srcv->at = iterv->at;
srcv->name = srcVarName;
if ( iterv->type->ref ) {
srcv->do_not_delete = true;
srcv->type = make_smart(Type::tPointer);
srcv->type->firstType = make_smart(*iterv->type);
srcv->type->firstType->constant |= src->type->constant;
srcv->type->firstType->ref = false;
if ( bodyBlock ) {
replaceRef2Ptr(bodyBlock, iterv->name);
} else {
replaceRef2Ptr(expr, iterv->name);
}
} else {
srcv->type = make_smart(*iterv->type);
srcv->type->constant |= src->type->constant;
}
srci->variables.push_back(srcv);
blk->list.push_back(srci);
// let pvar0 = reinterpret_cast(addr(it0))
auto vit0 = make_smart(expr->at, srcVarName);
auto adri = make_smart(expr->at, vit0);
adri->alwaysSafe = true;
auto pvoid = make_smart(Type::tPointer);
pvoid->firstType = make_smart(Type::tVoid);
auto rein = make_smart(expr->at, adri, pvoid);
rein->reinterpret = true;
rein->alwaysSafe = true;
auto veqt = make_smart();
veqt->at = expr->at;
veqt->atInit = expr->at;
veqt->visibility = expr->visibility;
auto vvar = make_smart();
vvar->generated = true;
vvar->at = expr->at;
vvar->name = pVarName;
vvar->type = make_smart(*pvoid);
vvar->init = rein;
veqt->variables.push_back(vvar);
blk->list.push_back(veqt);
// loop &= _builtin_iterator_first(it0,pvar0)
auto cbif = make_smart(expr->at, "_builtin_iterator_first");
cbif->generated = true;
cbif->arguments.push_back(make_smart(expr->at, srcName));
cbif->arguments.push_back(make_smart(expr->at, pVarName));
auto lande = make_smart(expr->at,"&&=",
make_smart(expr->at,loopVar),cbif);
blk->list.push_back(lande);
}
auto bll = make_smart(expr->at, begin_loop_label,
"begin for at line " + to_string(expr->at.line));
blk->list.push_back(bll);
auto ncnd = make_smart(expr->at, "!", make_smart(expr->at,loopVar));
auto ifnc = make_smart(expr->at, ncnd, btel, nullptr);
blk->list.push_back(ifnc);
if ( bodyBlock ) {
for ( auto & bse : bodyBlock->list ) {
blk->list.push_back(bse->clone());
}
} else {
blk->list.push_back(expr->body->clone());
}
auto mll = make_smart(expr->at, mid_loop_label,
"continue for at line " + to_string(expr->at.line));
blk->list.push_back(mll);
// loop &= _builtin_iterator_next(it0,pvar0)
for ( size_t si=0, sis=expr->sources.size(); si!=sis; ++si ) {
const string & srcName = srcNames[si];
const string & pVarName = pVarNames[si];
auto cbif = make_smart(expr->at, "_builtin_iterator_next");
cbif->generated = true;
cbif->arguments.push_back(make_smart(expr->at, srcName));
cbif->arguments.push_back(make_smart(expr->at, pVarName));
auto lande = make_smart(expr->at,"&&=",
make_smart(expr->at,loopVar),cbif);
blk->list.push_back(lande);
}
auto gbeg = make_smart(expr->at, begin_loop_label);
blk->list.push_back(gbeg);
auto ell = make_smart(expr->at, end_loop_label,
"end for at line " + to_string(expr->at.line));
blk->list.push_back(ell);
if ( bodyBlock && !bodyBlock->finalList.empty() ) { // finally, if we have it
for ( auto & fse : bodyBlock->finalList ) {
blk->list.push_back(fse->clone());
}
}
// loop &= _builtin_iterator_close(it0,pvar0)
for ( size_t si=0, sis=expr->sources.size(); si!=sis; ++si ) {
const string & srcName = srcNames[si];
const string & pVarName = pVarNames[si];
auto cbif = make_smart(expr->at, "_builtin_iterator_close");
cbif->generated = true;
cbif->arguments.push_back(make_smart(expr->at, srcName));
cbif->arguments.push_back(make_smart(expr->at, pVarName));
blk->list.push_back(cbif);
}
verifyGenerated(blk);
return blk;
}
FunctionPtr makeCloneTuple ( const LineInfo & at, const TypeDeclPtr & tupleType ) {
DAS_ASSERT(tupleType->isTuple() && "can only clone tuple");
auto fn = make_smart();
fn->generated = true;
fn->safeImplicit = true;
fn->privateFunction = true;
fn->name = "clone";
fn->at = fn->atDecl = at;
fn->result = make_smart(Type::tVoid);
auto arg0 = make_smart();
arg0->at = at;
arg0->name = "dest";
arg0->type = make_smart(*tupleType);
arg0->type->constant = false;
arg0->type->ref = false;
fn->arguments.push_back(arg0);
auto arg1 = make_smart();
arg1->at = at;
arg1->name = "src";
arg1->type = make_smart(*tupleType);
arg1->type->constant = true;
arg1->type->ref = false;
arg1->type->implicit = true;
fn->arguments.push_back(arg1);
auto block = make_smart();
block->at = at;
for ( size_t argi=0, argis=tupleType->argTypes.size(); argi!=argis; ++argi ) {
string argn = "_" + to_string(argi);
auto lv = make_smart(at, "dest");
auto lf = make_smart(at, lv, argn);
auto rv = make_smart(at, "src");
auto rf = make_smart(at, rv, argn);
auto cl = make_smart(at, lf, rf);
block->list.push_back(cl);
}
fn->body = block;
verifyGenerated(fn->body);
return fn;
}
FunctionPtr generateTupleFinalizer ( const LineInfo & at, const TypeDeclPtr & tupleType ) {
DAS_ASSERT(tupleType->isTuple() && "can only finalize tuple");
auto fn = make_smart();
fn->privateFunction = true;
fn->generated = true;
fn->name = "finalize";
fn->at = fn->atDecl = at;
fn->result = make_smart(Type::tVoid);
auto arg0 = make_smart();
arg0->at = at;
arg0->name = "__this";
arg0->type = make_smart(*tupleType);
arg0->type->constant = false;
arg0->type->ref = false;
arg0->type->isExplicit = true;
fn->arguments.push_back(arg0);
auto block = make_smart();
block->at = at;
bool needUnsafe = false;
for ( size_t argi=0, argis=tupleType->argTypes.size(); argi!=argis; ++argi ) {
if ( !tupleType->argTypes[argi]->constant && tupleType->argTypes[argi]->needDelete() ) {
if ( tupleType->isPointer() && tupleType->firstType && tupleType->firstType->constant ) continue;
string argn = "_" + to_string(argi);
auto lv = make_smart(at, "__this");
auto lf = make_smart(at, lv, argn);
auto cl = make_smart(at, lf);
block->list.push_back(cl);
if ( tupleType->argTypes[argi]->isPointer() ) {
needUnsafe = true;
}
}
}
auto mz = make_smart(at, "memzero");
auto lvar = make_smart(at, "__this");
mz->arguments.push_back(lvar);
block->list.push_back(mz);
fn->body = block;
if ( needUnsafe ) {
wrapInUnsafe(fn);
}
verifyGenerated(fn->body);
return fn;
}
FunctionPtr makeCloneVariant ( const LineInfo & at, const TypeDeclPtr & variantType ) {
DAS_ASSERT(variantType->isVariant() && "can only clone variant");
auto fn = make_smart();
fn->generated = true;
fn->safeImplicit = true;
fn->privateFunction = true;
fn->name = "clone";
fn->at = fn->atDecl = at;
fn->result = make_smart(Type::tVoid);
auto arg0 = make_smart();
arg0->at = at;
arg0->name = "dest";
arg0->type = make_smart(*variantType);
arg0->type->constant = false;
arg0->type->ref = false;
fn->arguments.push_back(arg0);
auto arg1 = make_smart();
arg1->at = at;
arg1->name = "src";
arg1->type = make_smart(*variantType);
arg1->type->constant = true;
arg1->type->ref = false;
arg1->type->implicit = true;
fn->arguments.push_back(arg1);
auto block = make_smart();
block->at = at;
smart_ptr topIf, lastIf;
for ( size_t argi=0, argis=variantType->argTypes.size(); argi!=argis; ++argi ) {
const string & argn = variantType->argNames[argi];
auto cb = make_smart();
cb->at = at;
auto vd = make_smart(at, "dest");
auto vi = make_smart(at, int32_t(argi));
auto svi = make_smart(at, "set_variant_index");
svi->alwaysSafe = true;
svi->arguments.push_back(vd);
svi->arguments.push_back(vi);
cb->list.push_back(svi);
auto lv = make_smart(at, "dest");
auto lf = make_smart(at, lv, argn);
lf->alwaysSafe = true;
auto rv = make_smart(at, "src");
auto rf = make_smart(at, rv, argn);
rf->alwaysSafe = true;
auto cl = make_smart(at, lf, rf);
cb->list.push_back(cl);
auto av = make_smart(at, "src");
auto isv = make_smart(at, av, argn);
auto thisIf = make_smart(at, isv, cb, nullptr);
if ( lastIf ) {
lastIf->if_false = thisIf;
lastIf = thisIf;
thisIf.reset();
} else {
topIf = lastIf = thisIf;
}
}
if (topIf) block->list.push_back(topIf);
fn->body = block;
verifyGenerated(fn->body);
return fn;
}
FunctionPtr generateVariantFinalizer ( const LineInfo & at, const TypeDeclPtr & variantType ) {
DAS_ASSERT(variantType->isVariant() && "can only finalize variant");
auto fn = make_smart();
fn->privateFunction = true;
fn->generated = true;
fn->name = "finalize";
fn->at = fn->atDecl = at;
fn->result = make_smart(Type::tVoid);
auto arg0 = make_smart();
arg0->at = at;
arg0->name = "__this";
arg0->type = make_smart(*variantType);
arg0->type->constant = false;
arg0->type->ref = false;
arg0->type->isExplicit = true;
fn->arguments.push_back(arg0);
auto block = make_smart();
block->at = at;
smart_ptr topIf, lastIf;
bool needUnsafe = false;
for ( size_t argi=0, argis=variantType->argTypes.size(); argi!=argis; ++argi ) {
if ( !variantType->argTypes[argi]->constant && variantType->argTypes[argi]->needDelete() ) {
if ( variantType->argTypes[argi]->isPointer() && variantType->argTypes[argi]->firstType
&& variantType->argTypes[argi]->firstType->constant ) continue;
const string & argn = variantType->argNames[argi];
auto lv = make_smart(at, "__this");
auto lf = make_smart(at, lv, argn);
lf->alwaysSafe = true;
auto cl = make_smart(at, lf);
auto cb = make_smart();
cb->at = at;
cb->list.push_back(cl);
auto av = make_smart(at, "__this");
auto isv = make_smart(at, av, argn);
auto thisIf = make_smart(at, isv, cb, nullptr);
if ( lastIf ) {
lastIf->if_false = thisIf;
lastIf = thisIf;
thisIf.reset();
} else {
topIf = lastIf = thisIf;
}
if ( variantType->argTypes[argi]->isPointer() ) {
needUnsafe = true;
}
}
}
if (topIf) block->list.push_back(topIf);
auto mz = make_smart(at, "memzero");
auto lvar = make_smart(at, "__this");
mz->arguments.push_back(lvar);
block->list.push_back(mz);
fn->body = block;
if ( needUnsafe ) {
wrapInUnsafe(fn);
}
verifyGenerated(fn->body);
return fn;
}
FunctionPtr makeCloneSmartPtr ( const LineInfo & at, const TypeDeclPtr & left, const TypeDeclPtr & right ) {
DAS_ASSERT(left->isPointer() && left->smartPtr && right->isPointer() && "can only clone smart-ptr