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

#include "daScript/misc/platform.h"

#include "daScript/ast/ast.h"
#include "daScript/ast/ast_visitor.h"

namespace das {

    class ClearUnusedSymbols : public Visitor {
    public:
        virtual bool canVisitStructureFieldInit ( Structure * ) override { return true; }
        virtual bool canVisitArgumentInit ( Function *, const VariablePtr &, Expression * ) override { return false; }
        virtual void preVisit(ExprAddr * expr) override {
            Visitor::preVisit(expr);
            if ( expr->func && !expr->func->used && !expr->func->builtIn ) {
                expr->func = nullptr;
            }
        }
        virtual void preVisitExpression(Expression * expr) override {
            Visitor::preVisitExpression(expr);
            if ( expr->rtti_isCallFunc() ) {
                auto cfe = static_cast(expr);
                if ( cfe->func && !cfe->func->used && !cfe->func->builtIn ) {
                    cfe->func = nullptr;
                }
            }
        }
    };

    class MarkSymbolUse : public Visitor {
    public:
        MarkSymbolUse ( bool bid ) : builtInDependencies(bid) {
        }
        __forceinline void push ( const VariablePtr & pvar ) {
            if ( !tw ) return;
            *tw useFunctions) {
                propagateFunctionUse(it);
            }
            pop();
        }
        void propagateFunctionUse(const FunctionPtr & fn) {
            assert(fn);
            if (fn->used) return;
            if (fn->builtIn) return;
            push(fn);
            fn->used = true;
            for (const auto & gv : fn->useGlobalVariables) {
                propageteVarUse(gv);
            }
            for (const auto & it : fn->useFunctions) {
                propagateFunctionUse(it);
            }
            pop();
        }
        void markVarsUsed( ModuleLibrary & lib, bool forceAll ){
            lib.foreach([&](Module * pm) {
                for ( auto & var : pm->globals.each() ) {
                    if ( forceAll || var->used ) {
                        var->used = false;
                        propageteVarUse(var);
                    }
                }
                return true;
            }, "*");
        }
        void markUsedFunctions( ModuleLibrary & lib, bool forceAll, bool initThis, Module * macroModule ) {
            lib.foreach([&](Module * pm) {
                if ( initThis && macroModule && pm!=macroModule ) return true;
                for ( auto & fn : pm->functions.each() ) {
                    if ( (forceAll && !fn->macroInit) || fn->exports || fn->init || fn->shutdown || (fn->macroInit && initThis) ) {
                        propagateFunctionUse(fn);
                    }
                }
                return true;
            }, "*");
        }
        void markModuleVarsUsed( ModuleLibrary &, Module * inWhichModule ) {
            for ( auto & var : inWhichModule->globals.each() ) {
                var->used = false;
                propageteVarUse(var);
            }
        }
        void markModuleUsedFunctions( ModuleLibrary &, Module * inWhichModule ) {
            for ( auto & fn : inWhichModule->functions.each() ) {
                if ( fn->builtIn || fn->macroInit || fn->macroFunction  ) continue;
                if ( fn->privateFunction && fn->generated && fn->fromGeneric ) continue;    // instances of templates are never roots
                if ( fn->isClassMethod && fn->classParent->macroInterface ) continue;       // methods of macro interfaces
                propagateFunctionUse(fn);
            }
        }
        void RemoveUnusedSymbols ( Module & mod ) {
            auto functions = das::move(mod.functions);
            auto globals = das::move(mod.globals);
            mod.functionsByName.clear();
            // mod.globals.clear();
            for ( auto & fn : functions.each() ) {
                if ( fn->used ) {
                    if ( !mod.addFunction(fn, true) ) {
                        program->error("internal error, failed to add function " + fn->name,"","", fn->at );
                    }
                }
            }
            for ( auto & var : globals.each() ) {
                if ( var->used ) {
                    if ( !mod.addVariable(var, true) ) {
                        program->error("internal error, failed to add variable " + var->name,"","", var->at );
                    }
                }
            }
        }
    protected:
        ProgramPtr  program;
        FunctionPtr func;
        Variable *  gVar = nullptr;
        bool        builtInDependencies;
        int         logTab = 0;
    public:
        TextWriter * tw = nullptr;
    protected:
        virtual bool canVisitStructureFieldInit ( Structure * ) override { return false; }
        virtual bool canVisitArgumentInit ( Function *, const VariablePtr &, Expression * ) override { return false; }
        // global variable declaration
        virtual void preVisitGlobalLet(const VariablePtr & var) override {
            Visitor::preVisitGlobalLet(var);
            gVar = var.get();
            var->useFunctions.clear();
            var->useGlobalVariables.clear();
            var->used = false;
        }
        virtual VariablePtr visitGlobalLet(const VariablePtr & var) override {
            gVar = nullptr;
            return Visitor::visitGlobalLet(var);
        }
        // function
        virtual void preVisit(Function * f) override {
            Visitor::preVisit(f);
            func = f;
            func->useFunctions.clear();
            func->useGlobalVariables.clear();
            func->used = false;
            DAS_ASSERTF(!func->builtIn, "visitor should never call 'visit' on builtin function at top level.");
        }
        virtual FunctionPtr visit(Function * that) override {
            func.reset();
            return Visitor::visit(that);
        }
        // variable
        virtual void preVisit(ExprVar * expr) override {
            Visitor::preVisit(expr);
            if (!expr->variable) return;
            if (!expr->local && !expr->argument && !expr->block) {
                if (func) {
                    func->useGlobalVariables.insert(expr->variable.get());
                } else if (gVar) {
                    gVar->useGlobalVariables.insert(expr->variable.get());
                }
            }
        }
        // function address
        virtual void preVisit(ExprAddr * addr) override {
            Visitor::preVisit(addr);
            if (builtInDependencies || (addr->func && !addr->func->builtIn)) {
                assert(addr->func);
                if (func) {
                    func->useFunctions.insert(addr->func);
                } else if (gVar) {
                    gVar->useFunctions.insert(addr->func);
                }
            }
        }
        // function call
        virtual void preVisit(ExprCall * call) override {
            Visitor::preVisit(call);
            if ( !call->func ) return;
            if (builtInDependencies || !call->func->builtIn) {
                if (func) {
                    func->useFunctions.insert(call->func);
                } else if (gVar) {
                    gVar->useFunctions.insert(call->func);
                }
            }
        }
        // new
        virtual void preVisit(ExprNew * call) override {
            Visitor::preVisit(call);
            if ( call->initializer ) {
                if (builtInDependencies || !call->func->builtIn) {
                    assert(call->func);
                    if (func) {
                        func->useFunctions.insert(call->func);
                    } else if (gVar) {
                        gVar->useFunctions.insert(call->func);
                    }
                }
            }
        }
        // Op1
        virtual void preVisit(ExprOp1 * expr) override {
            Visitor::preVisit(expr);
            if (builtInDependencies || !expr->func->builtIn) {
                assert(expr->func);
                if (func) {
                    func->useFunctions.insert(expr->func);
                } else if (gVar) {
                    gVar->useFunctions.insert(expr->func);
                }
            }
        }
        // Op2
        virtual void preVisit(ExprOp2 * expr) override {
            Visitor::preVisit(expr);
            if (builtInDependencies || !expr->func->builtIn) {
                assert(expr->func);
                if (func) {
                    func->useFunctions.insert(expr->func);
                } else if (gVar) {
                    gVar->useFunctions.insert(expr->func);
                }
            }
        }
        // Op3
        virtual void preVisit(ExprOp3 * expr) override {
            Visitor::preVisit(expr);
            if ( expr->func && (builtInDependencies || !expr->func->builtIn) ) {
                assert(expr->func);
                if (func) {
                    func->useFunctions.insert(expr->func);
                } else if (gVar) {
                    gVar->useFunctions.insert(expr->func);
                }
            }
        }
    };

    void Program::clearSymbolUse() {
        for (auto & pm : library.modules) {
            for ( auto & var : pm->globals.each() ) {
                var->used = false;
            }
            for ( auto & fn : pm->functions.each() ) {
                fn->used = false;
            }
        }
    }

    void Program::markModuleSymbolUse(TextWriter * logs) {
        // this module public, this module export, this module init\shutdown
        clearSymbolUse();
        MarkSymbolUse vis(false);
        vis.tw = logs;
        visit(vis);
        vis.markModuleUsedFunctions(library, thisModule.get());
        vis.markModuleVarsUsed(library, thisModule.get());
    }

    void Program::markMacroSymbolUse(TextWriter * logs) {
        // this module macro init
        clearSymbolUse();
        MarkSymbolUse vis(false);
        vis.tw = logs;
        visit(vis);
        vis.markUsedFunctions(library, false, true, thisModule.get());
        vis.markVarsUsed(library, false);
    }

    void Program::markExecutableSymbolUse(TextWriter * logs) {
        clearSymbolUse();
        MarkSymbolUse vis(false);
        vis.tw = logs;
        visit(vis);
        vis.markUsedFunctions(library, false, false, nullptr);
        vis.markVarsUsed(library, false);
    }

    void Program::markFoldingSymbolUse(const vector & needRun, TextWriter * logs) {
        clearSymbolUse();
        MarkSymbolUse vis(false);
        vis.tw = logs;
        visit(vis);
        for ( auto fun : needRun ) {
            vis.propagateFunctionUse(fun);
        }
    }

    void Program::markSymbolUse(bool builtInSym, bool forceAll, bool initThis, Module * macroModule, TextWriter * logs) {
        clearSymbolUse();
        MarkSymbolUse vis(builtInSym);
        vis.tw = logs;
        visit(vis);
        vis.markUsedFunctions(library, forceAll, initThis, macroModule);
        vis.markVarsUsed(library, forceAll);
    }

    void Program::removeUnusedSymbols() {
        if ( options.getBoolOption("remove_unused_symbols",true) ) {
            ClearUnusedSymbols cvis;
            visit(cvis);
            MarkSymbolUse vis(false);
            vis.RemoveUnusedSymbols(*thisModule);
        }
    }

    void Program::dumpSymbolUse(TextWriter & logs) {
        logs globals.each() ) {
                if ( var->used ) {
                    logs name used  ) {
                    logs module->name 

Web Proxy Viewer  |  New URL  |  Original Page