Extend minimize and processing

+ Add --no-exclude-reserved option
+ Add --list-var-dev and --list-var-call options
+ --remove-unused now also removes unused variables
+ --remove-unused now removes recursively
This commit is contained in:
zawz 2020-11-25 16:55:35 +01:00
parent b3f02ce06d
commit 7e5c505a3f
7 changed files with 313 additions and 134 deletions

View file

@ -15,17 +15,25 @@ extern const std::regex regex_null;
#define RESERVED_VARIABLES "HOME", "PATH", "SHELL", "PWD", "OPTIND", "OPTARG"
std::regex var_exclude_regex(std::string const& in);
void require_rescan_all();
void require_rescan_var();
void require_rescan_fct();
void require_rescan_cmd();
std::regex var_exclude_regex(std::string const& in, bool include_reserved);
std::regex fct_exclude_regex(std::string const& in);
void list_vars(_obj* in, std::regex const& exclude);
void list_var_defs(_obj* in, std::regex const& exclude);
void list_var_calls(_obj* in, std::regex const& exclude);
void list_fcts(_obj* in, std::regex const& exclude);
void list_cmds(_obj* in, std::regex const& exclude);
void minimize_var(_obj* in, std::regex const& exclude);
void minimize_fct(_obj* in, std::regex const& exclude);
void delete_unused_fct(_obj* in, std::regex const& exclude);
// void delete_unused_var(_obj* in, std::regex const& exclude);
bool delete_unused_fct(_obj* in, std::regex const& exclude);
bool delete_unused_var(_obj* in, std::regex const& exclude);
void delete_unused(_obj* in, std::regex const& var_exclude, std::regex const& fct_exclude);
#endif //MINIMIZE_HPP

View file

@ -254,11 +254,14 @@ public:
std::string const& firstarg_string();
size_t arglist_size();
// preceding var assigns
std::vector<std::pair<std::string,arg*>> var_assigns;
// get var assigns in special cmds (export, unset, read)
std::vector<subarg*> arg_vars();
bool is_argvar();
std::vector<subarg*> subarg_vars();
arglist* args;

View file

@ -150,15 +150,19 @@ int main(int argc, char* argv[])
// processing before output
if(options['m'])
opt_minimize=true;
if(options["remove-unused"])
delete_unused( sh, re_var_exclude, re_fct_exclude );
if(options["minimize-var"])
minimize_var( sh, re_var_exclude );
if(options["minimize-fct"])
minimize_fct( sh, re_fct_exclude );
if(options["remove-unused"])
delete_unused_fct( sh, re_fct_exclude );
if(options["list-var"])
list_vars(sh, re_var_exclude);
else if(options["list-var-def"])
list_var_defs(sh, re_var_exclude);
else if(options["list-var-call"])
list_var_calls(sh, re_var_exclude);
else if(options["list-fct"])
list_fcts(sh, re_fct_exclude);
else if(options["list-cmd"])

View file

@ -19,6 +19,64 @@ std::set<std::string> m_excluded_var, m_excluded_fct, m_excluded_cmd;
bool b_gotvar=false, b_gotfct=false, b_gotcmd=false;
// requires
void require_rescan_var()
{
b_gotvar = false;
m_vars.clear();
m_vardefs.clear();
m_varcalls.clear();
m_excluded_var.clear();
}
void require_rescan_fct()
{
b_gotcmd = false;
m_fcts.clear();
m_excluded_fct.clear();
}
void require_rescan_cmd()
{
b_gotfct = false;
m_cmds.clear();
m_excluded_cmd.clear();
}
void require_rescan_all()
{
require_rescan_var();
require_rescan_fct();
require_rescan_cmd();
}
// tools
countmap_t combine_maps(countmap_t const& a, countmap_t const& b)
{
countmap_t ret;
for(auto it: a)
{
if(!ret.insert( it ).second)
ret[it.first] += it.second;
}
for(auto it: b)
{
if(!ret.insert( it ).second)
ret[it.first] += it.second;
}
return ret;
}
void list_map(countmap_t const& map)
{
uint32_t max=0;
for(auto it: map)
if(it.second > max)
max=it.second;
for(auto it: map)
printf("%*d %s\n", (uint32_t)log10(max)+1, it.second, it.first.c_str());
}
std::vector<std::string> get_list(std::string const& in)
{
return split(in, ", \t\n");
@ -34,17 +92,21 @@ std::regex gen_regex_from_list(std::vector<std::string> const& in)
return std::regex(re);
}
std::vector<std::string> gen_var_excludes(std::string const& in)
std::vector<std::string> gen_var_excludes(std::string const& in, bool include_reserved)
{
std::vector<std::string> ret = {RESERVED_VARIABLES, strf("[0-9%s]", SPECIAL_VARS)};
std::vector<std::string> ret;
if(include_reserved)
{
ret = {RESERVED_VARIABLES, strf("[0-9%s]", SPECIAL_VARS)};
}
auto t = get_list(in);
ret.insert(ret.end(), t.begin(), t.end());
return ret;
}
std::regex var_exclude_regex(std::string const& in)
std::regex var_exclude_regex(std::string const& in, bool include_reserved)
{
return gen_regex_from_list(gen_var_excludes(in));
return gen_regex_from_list(gen_var_excludes(in, include_reserved));
}
std::regex fct_exclude_regex(std::string const& in)
{
@ -65,14 +127,44 @@ bool is_varname(std::string const& in)
return true;
}
std::vector<subarg*> cmd::arg_vars()
// object extensions //
std::string get_varname(std::string const& in)
{
size_t i=in.find('=');
if(i!=std::string::npos)
return in.substr(0, i);
else
return in;
}
std::string get_varname(arg* in)
{
if(in->sa.size() < 1 || in->sa[0]->type != _obj::subarg_string)
return "";
std::string str = in->sa[0]->generate(0);
if(in->sa.size() >= 1 && is_varname(str))
return get_varname(str);
return "";
}
bool cmd_is_argvar(std::string const& in)
{
return in == "export" || in == "unset" || in == "local" || in == "read";
}
bool cmd::is_argvar()
{
return cmd_is_argvar(this->firstarg_string());
}
std::vector<subarg*> cmd::subarg_vars()
{
std::vector<subarg*> ret;
if(args==nullptr || args->size()<=0)
return ret;
std::string cmdname=this->firstarg_string();
if(cmdname == "export" || cmdname == "unset" || cmdname == "local" || cmdname == "read")
if(this->is_argvar())
{
for(uint32_t i=1; i<args->size(); i++)
{
@ -87,21 +179,11 @@ std::vector<subarg*> cmd::arg_vars()
return ret;
}
std::string get_varname(subarg* in)
{
if(in->type != _obj::subarg_string)
return "";
std::string& t=dynamic_cast<string_subarg*>(in)->val;
size_t i=t.find('=');
if(i!=std::string::npos)
return t.substr(0, i);
else
return t;
}
/** RECURSIVES **/
/** VAR RECURSE **/
// GET //
bool get_var(_obj* in, countmap_t* defmap, countmap_t* callmap)
bool r_get_var(_obj* in, countmap_t* defmap, countmap_t* callmap)
{
switch(in->type)
{
@ -125,11 +207,14 @@ bool get_var(_obj* in, countmap_t* defmap, countmap_t* callmap)
for(auto it: t->var_assigns)
if(!defmap->insert( std::make_pair(it.first, 1) ).second)
(*defmap)[it.first]++;
for(auto it: t->arg_vars())
if(t->is_argvar())
{
std::string varname=get_varname(it);
if(!defmap->insert( std::make_pair(varname, 1) ).second)
(*defmap)[varname]++;
for(uint32_t i=1; i<t->args->size(); i++)
{
std::string varname=get_varname(t->args->args[i]);
if( varname != "" && !defmap->insert( std::make_pair(varname, 1) ).second )
(*defmap)[varname]++;
}
}
}; break;
default: break;
@ -137,7 +222,38 @@ bool get_var(_obj* in, countmap_t* defmap, countmap_t* callmap)
return true;
}
bool replace_varname(_obj* in, std::map<std::string,std::string>* varmap)
bool r_get_cmd(_obj* in, countmap_t* all_cmds)
{
switch(in->type)
{
case _obj::block_cmd: {
cmd* t = dynamic_cast<cmd*>(in);
std::string cmdname = t->firstarg_string();
if(cmdname != "" && !all_cmds->insert( std::make_pair(cmdname, 1) ).second)
(*all_cmds)[cmdname]++;
}; break;
default: break;
}
return true;
}
bool r_get_fct(_obj* in, countmap_t* fct_map)
{
switch(in->type)
{
case _obj::block_function: {
function* t = dynamic_cast<function*>(in);
if(!fct_map->insert( std::make_pair(t->name, 1) ).second)
(*fct_map)[t->name]++;
}; break;
default: break;
}
return true;
}
// REPLACE //
bool r_replace_var(_obj* in, std::map<std::string,std::string>* varmap)
{
switch(in->type)
{
@ -167,10 +283,10 @@ bool replace_varname(_obj* in, std::map<std::string,std::string>* varmap)
if(el!=varmap->end())
it->first = el->second;
}
for(auto it: t->arg_vars())
for(auto it: t->subarg_vars())
{
string_subarg* t = dynamic_cast<string_subarg*>(it);
auto el=varmap->find(get_varname(t));
auto el=varmap->find(get_varname(t->val));
if(el!=varmap->end())
{
size_t tpos=t->val.find('=');
@ -186,38 +302,7 @@ bool replace_varname(_obj* in, std::map<std::string,std::string>* varmap)
return true;
}
/** FCT RECURSE **/
bool get_cmd(_obj* in, countmap_t* all_cmds)
{
switch(in->type)
{
case _obj::block_cmd: {
cmd* t = dynamic_cast<cmd*>(in);
std::string cmdname = t->firstarg_string();
if(cmdname != "" && !all_cmds->insert( std::make_pair(cmdname, 1) ).second)
(*all_cmds)[cmdname]++;
}; break;
default: break;
}
return true;
}
bool get_fct(_obj* in, countmap_t* fct_map)
{
switch(in->type)
{
case _obj::block_function: {
function* t = dynamic_cast<function*>(in);
if(!fct_map->insert( std::make_pair(t->name, 1) ).second)
(*fct_map)[t->name]++;
}; break;
default: break;
}
return true;
}
bool replace_fctname(_obj* in, std::map<std::string,std::string>* fctmap)
bool r_replace_fct(_obj* in, std::map<std::string,std::string>* fctmap)
{
switch(in->type)
{
@ -242,7 +327,9 @@ bool replace_fctname(_obj* in, std::map<std::string,std::string>* fctmap)
return true;
}
bool delete_fcts(_obj* in, std::set<std::string>* fcts)
// DELETE //
bool r_delete_fct(_obj* in, std::set<std::string>* fcts)
{
switch(in->type)
{
@ -268,7 +355,63 @@ bool delete_fcts(_obj* in, std::set<std::string>* fcts)
return true;
}
/** name things **/
bool r_delete_var(_obj* in, std::set<std::string>* vars)
{
switch(in->type)
{
case _obj::_list: {
list* t = dynamic_cast<list*>(in);
for(uint32_t i=0; i<t->cls.size(); i++)
{
block* tb = t->cls[i]->first_block();
bool to_delete=false;
if(tb != nullptr && tb->type == _obj::block_cmd)
{
cmd* c = dynamic_cast<cmd*>(tb);
for(uint32_t j=0; j<c->var_assigns.size(); j++)
{
if( vars->find(c->var_assigns[j].first) != vars->end() )
{
delete c->var_assigns[j].second;
c->var_assigns.erase(c->var_assigns.begin()+j);
j--;
}
}
if(c->is_argvar())
{
for(uint32_t j=1; j<c->args->size(); j++)
{
std::string varname=get_varname(c->args->args[j]);
if( varname != "" && vars->find( varname ) != vars->end() )
{
delete c->args->args[j];
c->args->args.erase(c->args->args.begin()+j);
j--;
}
}
if(c->args->size()<=1)
to_delete=true;
}
if(c->var_assigns.size()<=0 && c->arglist_size()<=0)
to_delete=true;
}
if(to_delete)
{
delete t->cls[i];
t->cls.erase(t->cls.begin()+i);
i--;
}
}
}
default: break;
}
return true;
}
/** NAME MINIMIZING **/
char nchar(uint32_t n)
{
@ -308,53 +451,6 @@ std::string minimal_name(uint32_t n)
}
}
countmap_t combine_maps(countmap_t const& a, countmap_t const& b)
{
countmap_t ret;
for(auto it: a)
{
if(!ret.insert( it ).second)
ret[it.first] += it.second;
}
for(auto it: b)
{
if(!ret.insert( it ).second)
ret[it.first] += it.second;
}
return ret;
}
void varmap_get(_obj* in, std::regex const& exclude)
{
if(!b_gotvar)
{
b_gotvar=true;
recurse(get_var, in, &m_vardefs, &m_varcalls);
m_vars = combine_maps(m_vardefs, m_varcalls);
m_excluded_var = prune_matching(m_vars, exclude);
}
}
void fctmap_get(_obj* in, std::regex const& exclude)
{
if(!b_gotfct)
{
b_gotfct=true;
recurse(get_fct, in, &m_fcts);
m_excluded_fct = prune_matching(m_fcts, exclude);
}
}
void cmdmap_get(_obj* in, std::regex const& exclude)
{
if(!b_gotcmd)
{
b_gotcmd=true;
recurse(get_cmd, in, &m_cmds);
m_excluded_fct = prune_matching(m_cmds, exclude);
}
}
std::map<std::string,std::string> gen_minimal_map(countmap_t const& vars, std::set<std::string> excluded)
{
std::map<std::string,std::string> ret;
@ -372,6 +468,41 @@ std::map<std::string,std::string> gen_minimal_map(countmap_t const& vars, std::s
return ret;
}
// map getters
void varmap_get(_obj* in, std::regex const& exclude)
{
if(!b_gotvar)
{
b_gotvar=true;
recurse(r_get_var, in, &m_vardefs, &m_varcalls);
m_vars = combine_maps(m_vardefs, m_varcalls);
m_excluded_var = prune_matching(m_vars, exclude);
}
}
void fctmap_get(_obj* in, std::regex const& exclude)
{
if(!b_gotfct)
{
b_gotfct=true;
recurse(r_get_fct, in, &m_fcts);
m_excluded_fct = prune_matching(m_fcts, exclude);
}
}
void cmdmap_get(_obj* in, std::regex const& exclude)
{
if(!b_gotcmd)
{
b_gotcmd=true;
recurse(r_get_cmd, in, &m_cmds);
m_excluded_fct = prune_matching(m_cmds, exclude);
}
}
// calls
void minimize_var(_obj* in, std::regex const& exclude)
{
// countmap_t vars;
@ -382,7 +513,8 @@ void minimize_var(_obj* in, std::regex const& exclude)
// create mapping
varmap=gen_minimal_map(m_vars, m_excluded_var);
// perform replace
recurse(replace_varname, in, &varmap);
recurse(r_replace_var, in, &varmap);
require_rescan_var();
}
void minimize_fct(_obj* in, std::regex const& exclude)
@ -399,10 +531,12 @@ void minimize_fct(_obj* in, std::regex const& exclude)
// create mapping
fctmap=gen_minimal_map(m_fcts, allcmds);
// perform replace
recurse(replace_fctname, in, &fctmap);
recurse(r_replace_fct, in, &fctmap);
require_rescan_fct();
require_rescan_cmd();
}
void delete_unused_fct(_obj* in, std::regex const& exclude)
bool delete_unused_fct(_obj* in, std::regex const& exclude)
{
std::set<std::string> unused;
// get fcts and cmds
@ -416,10 +550,16 @@ void delete_unused_fct(_obj* in, std::regex const& exclude)
}
// perform deletion
if(unused.size()>0)
recurse(delete_fcts, in, &unused);
{
recurse(r_delete_fct, in, &unused);
require_rescan_all();
return true;
}
else
return false;
}
void delete_unused_var(_obj* in, std::regex const& exclude)
bool delete_unused_var(_obj* in, std::regex const& exclude)
{
std::set<std::string> unused;
// get fcts and cmds
@ -432,17 +572,18 @@ void delete_unused_var(_obj* in, std::regex const& exclude)
}
// perform deletion
if(unused.size()>0)
recurse(delete_fcts, in, &unused);
{
recurse(r_delete_var, in, &unused);
require_rescan_all();
return true;
}
else
return false;
}
void list_map(countmap_t const& map)
void delete_unused(_obj* in, std::regex const& var_exclude, std::regex const& fct_exclude)
{
uint32_t max=0;
for(auto it: map)
if(it.second > max)
max=it.second;
for(auto it: map)
printf("%*d %s\n", (uint32_t)log10(max)+1, it.second, it.first.c_str());
while(delete_unused_fct(in, fct_exclude) || delete_unused_var(in, var_exclude));
}
void list_vars(_obj* in, std::regex const& exclude)
@ -451,6 +592,18 @@ void list_vars(_obj* in, std::regex const& exclude)
list_map(m_vars);
}
void list_var_defs(_obj* in, std::regex const& exclude)
{
varmap_get(in, exclude);
list_map(m_vardefs);
}
void list_var_calls(_obj* in, std::regex const& exclude)
{
varmap_get(in, exclude);
list_map(m_varcalls);
}
void list_fcts(_obj* in, std::regex const& exclude)
{
fctmap_get(in, exclude);

View file

@ -31,10 +31,13 @@ ztd::option_set gen_options()
ztd::option("minimize-fct", false, "Minimize function names"),
ztd::option("exclude-var", true, "List of matching regex to ignore for variable processing", "list"),
ztd::option("exclude-fct", true, "List of matching regex to ignore for function processing", "list"),
ztd::option("list-var", false, "List all variables defined and invoked in the script"),
ztd::option("no-exclude-reserved",false, "Don't exclude reserved variables"),
ztd::option("list-var", false, "List all variables set and invoked in the script"),
ztd::option("list-var-def", false, "List all variables set in the script"),
ztd::option("list-var-call", false, "List all variables invoked in the script"),
ztd::option("list-fct", false, "List all functions defined in the script"),
ztd::option("list-cmd", false, "List all commands invoked in the script"),
// ztd::option("unset-var", false, "Add 'unset' to vars"),
// ztd::option("unset-var", false, "Add 'unset' to all vars at the start of the script to avoid environment interference"),
ztd::option("remove-unused", false, "Remove unused functions")
);
return ret;
@ -46,9 +49,9 @@ void get_opts()
g_include=!options["no-include"].activated;
g_resolve=!options["no-resolve"].activated;
if(options["exclude-var"])
re_var_exclude=var_exclude_regex(options["exclude-var"]);
re_var_exclude=var_exclude_regex(options["exclude-var"], !options["no-exclude-reserved"]);
else
re_var_exclude=var_exclude_regex("");
re_var_exclude=var_exclude_regex("", !options["no-exclude-reserved"]);
if(options["exclude-fct"])
re_fct_exclude=fct_exclude_regex(options["exclude-fct"]);
}

View file

@ -319,7 +319,7 @@ std::pair< std::vector<arg*> , bool > resolve_arg(arg* in, shmain* parent, bool
// -- RECURSIVE CALL --
bool resolve_recurse(_obj* o, shmain* parent)
bool r_resolve(_obj* o, shmain* parent)
{
switch(o->type)
{
@ -409,10 +409,10 @@ bool resolve_recurse(_obj* o, shmain* parent)
// recursive call of resolve
void resolve(_obj* in, shmain* parent)
{
recurse(resolve_recurse, in, parent);
recurse(r_resolve, in, parent);
}
void resolve(shmain* sh)
{
recurse(resolve_recurse, sh, sh);
recurse(r_resolve, sh, sh);
}

View file

@ -104,6 +104,14 @@ cmd* subshell::single_cmd()
return nullptr;
}
size_t cmd::arglist_size()
{
if(args==nullptr)
return 0;
else
return args->size();
}
cmd* brace::single_cmd()
{
if( lst->size() == 1 && // only one condlist