[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/rburkholder/daScript/master/src/ast/ast_generate.cpp [Back]  [Original]

#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 

Web Proxy Viewer  |  New URL  |  Original Page