Page Menu
Home
Xreate
Search
Configure Global Search
Log In
Docs
Questions
Repository
Issues
Patches
Internal API
Files
F3995444
interpretationpass.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Tue, Jul 7, 9:17 AM
Size
10 KB
Mime Type
text/x-c++
Expires
Thu, Jul 9, 9:17 AM (18 h, 3 m)
Engine
blob
Format
Raw Data
Handle
271207
Attached To
rXR Xreate
interpretationpass.cpp
View Options
/*
* 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
Log In to Comment