interpretationpass.cpp
No OneTemporary

File Metadata

Created
Fri, Mar 13, 8:22 PM

interpretationpass.cpp

/*
* File: interpretationpass.cpp
* Author: pgess
*
* Created on July 5, 2016, 5:21 PM
*/
#include "pass/interpretationpass.h"
//#include "compilation/transformations.h"
#include <compilation/targetinterpretation.h>
#include "ast.h"
//DEBT implement InterpretationPass purely in clasp
//DEBT represent InterpretationPass as general type inference
using namespace std;
namespace xreate{
enum InterpretationQuery{QUERY_INTR_ONLY, QUERY_CMPL_ONLY};
template<>
InterpretationResolution
defaultValue<InterpretationResolution>(){
return CMPL_ONLY;
}
InterpretationResolution
unify(InterpretationResolution flag) {
return flag;
}
template<typename FLAG_A, typename FLAG_B, typename... FLAGS>
InterpretationResolution
unify(FLAG_A flagA, FLAG_B flagB, FLAGS... flags) {
if (flagA== ANY){
return unify(flagB, flags...);
}
if (flagB == ANY) {
return unify(flagA, flags...);
}
assert(flagA == flagB);
return flagA;
}
namespace detail {
template<InterpretationQuery FLAG_REQUIRED>
bool checkConstraints(InterpretationResolution flag) {
return ( (flag==INTR_ONLY && FLAG_REQUIRED == QUERY_INTR_ONLY)
|| (flag==CMPL_ONLY && FLAG_REQUIRED == QUERY_CMPL_ONLY));
}
}
template<InterpretationQuery FLAG_REQUIRED>
bool checkConstraints(std::vector<InterpretationResolution>&& flags) {
assert(flags.size());
InterpretationResolution flag = flags.front();
return detail::checkConstraints<FLAG_REQUIRED>(flag);
}
template<InterpretationQuery FLAG_REQUIRED_A, InterpretationQuery FLAG_REQUIRED_B, InterpretationQuery... FLAGS>
bool checkConstraints(std::vector<InterpretationResolution>&& flags) {
assert(flags.size());
InterpretationResolution flag = flags.front();
flags.pop_back();
if (detail::checkConstraints<FLAG_REQUIRED_A>(flag)){
return checkConstraints<FLAG_REQUIRED_B, FLAGS...>(move(flags));
}
return false;
}
bool
InterpretationData::isDefault() const{
return (resolution == ANY && op == NONE);
}
namespace details {
InterpretationResolution
recognizeTags(const map<std::string, Expression>& tags){
auto i = tags.find("interpretation");
if (i== tags.end()){
return ANY;
}
assert(i->second.op == Operator::CALL);
const string& cmd = i->second.operands.at(0).getValueString();
//TODO make consistent names of annotation and resolution
if (cmd == "force"){
return INTR_ONLY;
} else if (cmd == "suppress"){
return CMPL_ONLY;
}
return ANY;
}
}
void
recognizeTags(const Expression& e){
InterpretationData tag{details::recognizeTags(e.tags), NONE};
if (!tag.isDefault())
Attachments::put<InterpretationData>(e, tag);
}
InterpretationResolution
recognizeTags(const ManagedFnPtr& f){
return details::recognizeTags(f->getTags());
}
InterpretationPass::InterpretationPass(PassManager* manager)
: AbstractPass(manager) {
Attachments::init<FunctionInterpretationData>();
Attachments::init<InterpretationData>();
}
void InterpretationPass::run(){
ManagedFnPtr f = man->root->begin<Function>();
auto& visitedSymbols = getSymbolCache();
while (f.isValid()) {
const Symbol& symbolFunction{ScopedSymbol::RetSymbol, f->getEntryScope()};
if (!visitedSymbols.isCached(symbolFunction)){
visitedSymbols.setCachedValue(symbolFunction, process(f));
}
++f;
}
}
InterpretationResolution
InterpretationPass::process(const Expression& expression, PassContext context, const std::string& decl){
recognizeTags(expression);
InterpretationResolution resolution = ANY;
InterpretationOperator op = NONE;
switch (expression.__state){
case Expression::VARIANT:
case Expression::NUMBER:
case Expression::STRING: {
break;
}
case Expression::IDENT: {
resolution = Parent::processSymbol(Attachments::get<Symbol>(expression), context);
break;
}
case Expression::COMPOUND:
break;
default: { resolution = CMPL_ONLY; break;}
}
if (expression.__state == Expression::COMPOUND)
switch(expression.op){
case Operator::EQU:
case Operator::NE: {
InterpretationResolution left = process(expression.operands[0], context);
InterpretationResolution right = process(expression.operands[1], context);
resolution = unify(left, right);
break;
}
case Operator::LOGIC_AND: {
assert(expression.operands.size() == 1);
resolution = process (expression.operands[0], context);
break;
}
case Operator::CALL: {
//TODO cope with static/dynamic context
//TODO BUG here: if several variants they all are processed as CMPL careless of signature
list<ManagedFnPtr> callees = man->root->getFunctionVariants(expression.getValueString());
if (callees.size()!=1){
resolution = CMPL_ONLY;
break;
}
ManagedFnPtr callee = callees.front();
const Symbol& symbCalleeFunc{ScopedSymbol::RetSymbol, callee->getEntryScope()};
//recursion-aware processing:
// - skip self recursion
const Symbol& symbSelfFunc{ScopedSymbol::RetSymbol, context.function->getEntryScope()};
if (!(symbSelfFunc == symbCalleeFunc)){
InterpretationResolution resCallee = processFnCall(callee, context);
assert(resCallee != FUNC_POSTPONED && "Indirect recursion detected: can't decide on interpretation resolution");
resolution = unify(resolution, resCallee);
}
//check arguments compatibility
const FunctionInterpretationData& calleeSignature = FunctionInterpretationHelper::getSignature(callee);
for (size_t op=0, size = expression.operands.size(); op < size; ++op){
const Expression &operand = expression.operands[op];
InterpretationResolution argActual = process(operand, context);
InterpretationResolution argExpected = calleeSignature.signature[op];
//TODO use args unification result to properly process function call
unify(argActual, argExpected);
}
if (FunctionInterpretationHelper::needPartialInterpretation(callee)){
op= CALL_INTERPRET_PARTIAL;
}
break;
}
case Operator::IF:{
InterpretationResolution flagCondition = process(expression.getOperands()[0], context);
InterpretationResolution flagScope1 = Parent::process(expression.blocks.front(), context);
InterpretationResolution flagScope2 = Parent::process(expression.blocks.back(), context);
//special case: IF_INTERPRET_CONDITION
if (checkConstraints<QUERY_INTR_ONLY>({flagCondition})){
op= IF_INTERPRET_CONDITION;
flagCondition = ANY;
}
resolution = unify(flagCondition, flagScope1, flagScope2);
break;
}
case Operator::FOLD: {
InterpretationResolution flagInput = process(expression.getOperands()[0], context);
InterpretationResolution flagAccumInit = process(expression.getOperands()[1], context);
CodeScope* scopeBody = expression.blocks.front();
const std::string& nameEl = expression.bindings[0];
Symbol symbEl{ScopedSymbol{scopeBody->__identifiers.at(nameEl), VERSION_NONE}, scopeBody};
getSymbolCache().setCachedValue(symbEl, InterpretationResolution(flagInput));
const std::string& nameAccum = expression.bindings[1];
Symbol symbAccum{ScopedSymbol{scopeBody->__identifiers.at(nameAccum), VERSION_NONE}, scopeBody};
getSymbolCache().setCachedValue(symbAccum, InterpretationResolution(flagAccumInit));
InterpretationResolution flagBody = Parent::process(expression.blocks.front(), context);
//special case: FOLD_INTERPRET_INPUT
if (checkConstraints<QUERY_INTR_ONLY>({flagInput})){
op= FOLD_INTERPRET_INPUT;
flagInput = ANY;
}
resolution = unify(flagInput, flagAccumInit, flagBody);
break;
}
case Operator::INDEX: {
resolution = unify(
process(expression.operands[0], context),
process(expression.operands[1], context)
);
break;
}
case Operator::SWITCH: {
InterpretationResolution flagCondition = process(expression.operands[0], context);
bool hasDefaultCase = expression.operands[1].op == Operator::CASE_DEFAULT;
//determine conditions resolution
InterpretationResolution flagHeaders = flagCondition;
for (size_t size = expression.operands.size(), i= hasDefaultCase? 2: 1; i<size; ++i){
const Expression& exprCase = expression.operands[i];
flagHeaders = unify(flagHeaders, Parent::process(exprCase.blocks.front(), context));
}
if (checkConstraints<QUERY_INTR_ONLY>({flagHeaders})){
op= SWITCH_INTERPRET_CONDITION;
flagHeaders = ANY;
}
//determine body resolutions
resolution = flagHeaders;
for (size_t size = expression.operands.size(), i= 1; i<size; ++i){
const Expression& exprCase = expression.operands[i];
resolution = unify(resolution, Parent::process(exprCase.blocks.back(), context));
}
break;
}
case Operator::LIST:
case Operator::LIST_NAMED: {
for (const Expression &op: expression.getOperands()) {
resolution = unify(resolution, process(op, context));
}
break;
}
default: {
resolution = CMPL_ONLY;
for (const Expression &op: expression.getOperands()) {
process(op, context);
}
for (CodeScope* scope: expression.blocks) {
Parent::process(scope, context);
}
break;
}
}
InterpretationResolution resolutionExpected =
Attachments::get<InterpretationData>(expression, {ANY, NONE}).resolution;
resolution = unify(resolution, resolutionExpected);
if (resolution != resolutionExpected && (op!=NONE || resolution == INTR_ONLY)){
Attachments::put<InterpretationData>(expression, {resolution, op});
}
return resolution;
}
InterpretationResolution
InterpretationPass::processFnCall(ManagedFnPtr function, PassContext context){
const Symbol symbolFunction{ScopedSymbol::RetSymbol, function->getEntryScope()};
auto& visitedSymbols = getSymbolCache();
if (visitedSymbols.isCached(symbolFunction))
return visitedSymbols.getCachedValue(symbolFunction);
PassContext context2;
context2.function = function;
return visitedSymbols.setCachedValue(symbolFunction,
Parent::process(function->getEntryScope(), context2));
}
InterpretationResolution
InterpretationPass::process(ManagedFnPtr function){
CodeScope* entry = function->getEntryScope();
std::vector<std::string> arguments = entry->__bindings;
const Symbol& symbSelfFunc{ScopedSymbol::RetSymbol, function->getEntryScope()};
auto& cache = getSymbolCache();
const FunctionInterpretationData& fnSignature = FunctionInterpretationHelper::getSignature(function);
InterpretationResolution fnResolutionExpected = details::recognizeTags(function->getTags());
//mark preliminary function resolution as expected
if (fnResolutionExpected != ANY){
cache.setCachedValue(symbSelfFunc, move(fnResolutionExpected));
} else {
// - in order to recognize indirect recursion mark this function resolution as POSTPONED
cache.setCachedValue(symbSelfFunc, FUNC_POSTPONED);
}
//set resolution for function arguments as expected
for (int argNo = 0, size = arguments.size(); argNo< size; ++argNo){
Symbol symbArg{ScopedSymbol{entry->__identifiers.at(arguments[argNo]), VERSION_NONE}, entry};
cache.setCachedValue(symbArg, InterpretationResolution(fnSignature.signature[argNo]));
}
PassContext context;
context.function = function;
context.scope = entry;
InterpretationResolution resActual = process(CodeScope::getDeclaration(symbSelfFunc), context);
resActual = unify(resActual, fnResolutionExpected);
return cache.setCachedValue(symbSelfFunc, move(resActual));
}
const FunctionInterpretationData
FunctionInterpretationHelper::getSignature(ManagedFnPtr function){
if (Attachments::exists<FunctionInterpretationData>(function)){
return Attachments::get<FunctionInterpretationData>(function);
}
FunctionInterpretationData&& data = recognizeSignature(function);
Attachments::put<FunctionInterpretationData>(function, data);
return data;
}
FunctionInterpretationData
FunctionInterpretationHelper::recognizeSignature(ManagedFnPtr function){
CodeScope* entry = function->__entry;
FunctionInterpretationData result;
result.signature.reserve(entry->__bindings.size());
bool flagPartialInterpretation = false;
for(size_t no=0, size=entry->__bindings.size(); no < size; ++no){
const std::string& argName = entry->__bindings[no];
Symbol symbArg{ScopedSymbol{entry->__identifiers.at(argName), VERSION_NONE}, entry};
const Expression& arg = CodeScope::getDeclaration(symbArg);
InterpretationResolution argResolution = details::recognizeTags(arg.tags);
flagPartialInterpretation |= (argResolution == INTR_ONLY);
result.signature.push_back(argResolution);
}
result.flagPartialInterpretation = flagPartialInterpretation;
return result;
}
bool FunctionInterpretationHelper::needPartialInterpretation(ManagedFnPtr function){
const FunctionInterpretationData& data = getSignature(function);
return data.flagPartialInterpretation;
}
}

Event Timeline