interpretationpass.cpp
No OneTemporary

File Metadata

Created
Tue, Jul 7, 9:17 AM

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== BOTH){
return unify(flagB, flags...);
}
if (flagB == BOTH) {
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;
}
void
setSpecializedOperator(const Expression& expression, const InterpretationOperator& op){
if (Attachments::exists<Expression, InterpretationData>(expression)){
InterpretationData& data = Attachments::get<Expression, InterpretationData>(expression);
data.op = op;
} else {
Attachments::put<Expression, InterpretationData>(expression, {BOTH, op});
}
compilation::Transformations::subscribe<Expression, compilation::TargetInterpretation>(expression);
}
InterpretationResolution
recognizeTags(const map<std::string, Expression>& tags){
auto i = tags.find("interpretation");
if (i== tags.end()){
return BOTH;
}
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 BOTH;
}
void
recognizeTags(const Expression& e){
InterpretationData tag{recognizeTags(e.tags), NONE};
Attachments::put<Expression, InterpretationData>(e, tag);
}
InterpretationResolution
recognizeTags(const ManagedFnPtr& f){
return recognizeTags(f->getTags());
}
InterpretationPass::InterpretationPass(PassManager* manager)
: AbstractPass(manager) {}
InterpretationResolution
InterpretationPass::process(const Expression& expression, PassContext context, const std::string& decl){
recognizeTags(expression);
InterpretationResolution resolution = BOTH;
switch (expression.__state){
case Expression::NUMBER:
case Expression::STRING: {
break;
}
case Expression::IDENT: {
resolution = Parent::processSymbol(expression.getValueString(), context);
break;
}
case Expression::COMPOUND:
break;
default: { resolution = INTR_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
for (const Expression &op: expression.getOperands()) {
resolution = unify(resolution, process(op, context));
}
list<ManagedFnPtr> callees = man->root->getFunctionVariants(expression.getValueString());
if (callees.size()!=1){
resolution = CMPL_ONLY;
break;
}
ManagedFnPtr callee = callees.front();
const Symbol& symbCalleeFunc{0, callee->getEntryScope()};
//recursion-aware processing:
// - skip self recursion
const Symbol& symbSelfFunc{0, context.function->getEntryScope()};
if (symbSelfFunc == symbCalleeFunc){
break;
}
// - in order to recognize indirect recursion mark this function resolution as POSTPONED
auto& cache = getSymbolCache();
if (!cache.isCached(symbSelfFunc)){
cache.setCachedValue(symbSelfFunc, POSTPONED);
}
InterpretationResolution resCallee = process(callee);
if (resCallee == POSTPONED){
assert(false && "Indirect recursion detected: can't decide on interpretation resolution");
}
resolution = unify(resolution, resCallee);
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})){
setSpecializedOperator(expression, IF_INTERPRET_CONDITION);
flagCondition = BOTH;
}
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];
getSymbolCache().setCachedValue(scopeBody->findSymbol(nameEl), InterpretationResolution(flagInput));
const std::string& nameAccum = expression.bindings[1];
getSymbolCache().setCachedValue(scopeBody->findSymbol(nameAccum), InterpretationResolution(flagAccumInit));
InterpretationResolution flagBody = Parent::process(expression.blocks.front(), context);
//special case: FOLD_INTERPRET_INPUT
if (checkConstraints<QUERY_INTR_ONLY>({flagInput})){
setSpecializedOperator(expression, FOLD_INTERPRET_INPUT);
flagInput = BOTH;
}
resolution = unify(flagInput, flagAccumInit, flagBody);
break;
}
case Operator::INDEX: {
resolution = unify(
process(expression.operands[0], context),
Parent::processSymbol(expression.getValueString(), 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})){
setSpecializedOperator(expression, SWITCH_INTERPRET_CONDITION);
flagHeaders = BOTH;
}
//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;
Parent::process(expression, context, decl);
break;
}
}
InterpretationResolution resolutionExpected = Attachments::get<Expression, InterpretationData>(expression, {BOTH, NONE})
.resolution;
resolution = unify(resolution, resolutionExpected);
if (resolution == INTR_ONLY){
Attachments::put<Expression, InterpretationData>(expression, {INTR_ONLY, NONE});
compilation::Transformations::subscribe<Expression, compilation::TargetInterpretation>(expression);
}
return resolution;
}
InterpretationResolution
InterpretationPass::process(ManagedFnPtr function){
InterpretationResolution resExpected = recognizeTags(function);
//mark preliminary function resolution same as expected
if (resExpected != BOTH){
const Symbol& symbSelfFunc{0, function->getEntryScope()};
getSymbolCache().setCachedValue(symbSelfFunc, move(resExpected));
}
CodeScope* entry = function->getEntryScope();
auto& cache = getSymbolCache();
std::vector<std::string> args = entry->__bindings;
for (int argNo = 0, size = args.size(); argNo< size; ++argNo){
Symbol symbArg = entry->findSymbol(args[argNo]);
InterpretationResolution resArg = recognizeTags(entry->findDeclaration(symbArg).tags);
cache.setCachedValue(symbArg, move(resArg));
}
InterpretationResolution resActual = Parent::process(function);
return unify(resActual, resExpected);
}
}
-

Event Timeline