dfapass.cpp
No OneTemporary

File Metadata

Created
Wed, Jul 8, 3:00 PM

dfapass.cpp

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Author: pgess <v.melnychenko@xreate.org>
*
* dfapass.cpp
*/
/**
* \file dfapass.h
* \brief Data Flow Analysis(DFA)
*/
//DEBT DFA represent VersionaPass in declarative form using applyDependencies
// applyDependencies(expression, context, cache, decl);
//DEBT DFA prepare static annotations and represent InterpretationPass in declarative form
// applyStaticAnnotations(expression, context, cache, decl);
//DEBT DFA Eliminate dfa schemes
#include "pass/dfapass.h"
#include "xreatemanager.h"
#include "clasplayer.h"
#include <boost/format.hpp>
#include <boost/variant/variant.hpp>
using namespace std;
namespace xreate {namespace dfa {
DFAPass::DFAPass(PassManager* manager)
: AbstractPass(manager)
, graph{new DFAGraph()}
, clasp(manager->clasp) { }
void
DFAPass::processCallInstance(const Expression& expr, PassContext context, const SymbolNode& result) {
const string &nameCalleeFunction=expr.getValueString();
//TODO implement processFnCall/Uncertain
list<ManagedFnPtr> variantsCalleeFunction=man->root->getFunctionSpecializations(nameCalleeFunction);
vector<SymbolNode> operands;
operands.reserve(expr.getOperands().size());
for(const Expression& arg : expr.getOperands()) {
operands.push_back(process(arg, context));
}
//Set calling relations:
DFACallInstanceType type=variantsCalleeFunction.size()>1?WEAK:STRONG;
for(ManagedFnPtr function : variantsCalleeFunction) {
CodeScope *scopeRemote=function->getEntryScope();
DFACallInstance callInstance;
callInstance.id=expr.id;
callInstance.fnName=function->getName();
callInstance.type=type;
std::vector<SymbolNode>::const_iterator nodeActual=operands.begin();
for(const std::string &identFormal : scopeRemote->__bindings) {
const ScopedSymbol symbolFormal{scopeRemote->__identifiers.at(identFormal), versions::VERSION_NONE};
SymbolPacked symbolFormalPacked=clasp->pack(Symbol{symbolFormal, scopeRemote}, nameCalleeFunction+":"+identFormal);
callInstance.args.push_back(std::make_pair(symbolFormalPacked, *nodeActual));
++nodeActual;
}
callInstance.retActual=result;
SymbolNode retFormal=SymbolNode(clasp->pack(Symbol{ScopedSymbol::RetSymbol, scopeRemote}, nameCalleeFunction+":[ret]"));
graph->addCallInstance(std::move(callInstance));
}
}
void
DFAPass::processDependencies(const SymbolNode& node, const Expression& expression, PassContext context, ProcessingCache& cache) {
cache.operands.reserve(expression.getOperands().size());
for(const Expression &op : expression.getOperands()) {
const SymbolNode& subnodeOperand=process(op, context);
cache.operands.push_back(subnodeOperand);
graph->addDependency(node, subnodeOperand);
}
cache.blocks.reserve(expression.blocks.size());
for(CodeScope* block : expression.blocks) {
const SymbolNode& subnodeBlock=process(block, context);
cache.blocks.push_back(subnodeBlock);
graph->addDependency(node, subnodeBlock);
}
}
SymbolNode
DFAPass::process(const Expression& expression, PassContext context, const std::string& varDecl) {
SymbolNode result;
if(Attachments::exists<SymbolAlias>(expression)){
Symbol varSymbol=Attachments::get<SymbolAlias>(expression);
result=clasp->pack(varSymbol, varDecl);
} else if(expression.__state==Expression::IDENT&&expression.tags.size()==0){
Symbol varSymbol=Attachments::get<IdentifierSymbol>(expression);
result=clasp->pack(varSymbol, expression.getValueString());
} else {
result=SymbolAnonymous{expression.id};
}
graph->printInplaceAnnotations(result, expression);
switch(expression.__state) {
case Expression::COMPOUND: {
switch(expression.op) {
case Operator::CALL: {
processCallInstance(expression, context, result);
break;
}
case Operator::IF: {
const SymbolNode& scopeA=process(expression.blocks.front(), context, "ifTrue" + std::to_string(expression.id));
const SymbolNode& scopeB=process(expression.blocks.back(), context, "ifFalse" + std::to_string(expression.id));
const SymbolNode& condition=process(expression.operands.at(0), context);
graph->addDependency(result, scopeA);
graph->addDependency(result, scopeB);
graph->addDependency(result, condition);
graph->printWeakAlias(result, scopeA);
graph->printWeakAlias(result, scopeB);
break;
}
case Operator::SWITCH:
case Operator::SWITCH_VARIANT: {
for(CodeScope* block : expression.blocks) {
const SymbolNode& subnodeBlock=process(block, context, "case"+to_string(block->getBody().id));
graph->addDependency(result, subnodeBlock);
graph->printWeakAlias(result, subnodeBlock);
}
const SymbolNode& condition=process(expression.operands.at(0), context);
graph->addDependency(result, condition);
break;
}
default: {
ProcessingCache cache;
processDependencies(result, expression, context, cache);
break;
}
}
break;
}
case Expression::IDENT: {
SymbolNode symbIdent=AbstractPass<SymbolNode>::process(expression, context, varDecl);
if(!(result==symbIdent)){
graph->addDependency(result, symbIdent);
graph->printAlias(result, symbIdent);
}
break;
}
case Expression::NUMBER:
case Expression::STRING: {
break;
}
case Expression::INVALID:
case Expression::BINDING: {
assert(false);
break;
}
}
return result;
}
SymbolNode
DFAPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl) {
if (!hintBlockDecl.empty()) {
Symbol symbRet{ScopedSymbol::RetSymbol, scope};
clasp->pack(symbRet, hintBlockDecl + ":[ret]");
}
for(const std::string& binding : scope->__bindings) {
Symbol bindingSymbol{scope->getSymbol(binding), scope};
SymbolPacked bindingPacked=clasp->pack(bindingSymbol, binding);
getSymbolCache().setCachedValue(bindingSymbol, SymbolNode(bindingPacked));
}
return AbstractPass<SymbolNode>::process(scope, context, hintBlockDecl);
}
SymbolNode
DFAPass::process(ManagedFnPtr function) {
clasp->pack(Symbol{ScopedSymbol::RetSymbol, function->getEntryScope()}, function->getName()+to_string(function.id())+":[ret]");
SymbolNode result=AbstractPass<SymbolNode>::process(function);
graph->printFunctionRet(function, result);
return result;
}
void
DFAPass::finish() {
clasp->registerReport(graph);
//Declare symbols:
graph->printSymbols(clasp);
AbstractPass::finish();
}
} //end of namespace dfa
template<>
dfa::SymbolNode
defaultValue() {
assert(false);
}
} //end of xreate namespace
/**
* \class xreate::dfa::DFAPass
* \details Provides DFA, important analysis for reasoning. Iterates over AST and stores collected data in DFAGraph
*/

Event Timeline