diff --git a/core/aux/graphs_trees_depth.lp b/core/aux/graphs_trees_depth.lp new file mode 100644 index 0000000..a322358 --- /dev/null +++ b/core/aux/graphs_trees_depth.lp @@ -0,0 +1,2 @@ +graphs_tree_depth(X, 0) :- not graphs_tree_depends(X, _); graphs_node(X). +graphs_tree_depth(X, LEVEL):- LEVEL = #max{L+1, graphs_tree_depth(Y, L): graphs_tree_depth(Y, L), graphs_tree_depends(X, Y)}; graphs_node(X); LEVEL > 0. \ No newline at end of file diff --git a/core/control-context-v1.lp b/core/control-context-v1.lp new file mode 100644 index 0000000..62237fe --- /dev/null +++ b/core/control-context-v1.lp @@ -0,0 +1,24 @@ + % context propagation + +bind_scope_decision(Scope, Fn, Resolution):- cfa_call(Scope, Fn), cfa_function_specializations(Fn, Resolution), bind_scope(Scope, Resolution). +bind_scope_decision(Scope, Fn, Resolution):- cfa_call(Scope, FnChild), bind_function_demand(FnChild, Fn), cfa_function_specializations(Fn, Resolution), bind_scope(Scope, Resolution). + +bind_scope_demand(Scope, FnCallee):- cfa_call(Scope, FnCallee), cfa_function_specializations(FnCallee, _), not bind_scope_decision(Scope, FnCallee, _). + + %demand propagation +bind_scope_demand(Scope, Subject):- bind_scope_demand(ScopeChild, Subject), cfa_parent(ScopeChild, scope(Scope)). +bind_scope_demand(Scope, Subject):- cfa_call(Scope, FnChild), bind_function_demand(FnChild, Subject), not bind_scope_decision(Scope, Subject, _). +bind_function_demand(Fn, Subject):- bind_scope_demand(Scope, Subject), cfa_parent(Scope, function(Fn)). + +bind_scope(Scope, Context) :- bind_scope(ScopeParent, Context), cfa_parent(Scope, scope(ScopeParent)). +bind_scope(Scope, Context) :- bind_scope(ScopeParent, Context): cfa_call(ScopeParent, FnCurrent); cfa_call(_, FnCurrent) + , cfa_parent(Scope, function(FnCurrent)), bind_scope(_, Context), scope(Scope). + +% adhoc classes(unfinished): +%bind_func(Fn, adhoc_class(Context)) :- bind_func(Fn, adhoc(Context)), bind_scope(Scope, Context), cfa_parent(Scope, function(Fn)). + +%scope_parent(Scope, ScopeParent) :- cfa_parent(Scope, scope(ScopeParent)). +%scope_parent(Scope, ScopeParent2) :- cfa_parent(Scope, scope(ScopeParent)), scope_parent(ScopeParent, ScopeParent2). + +%scope_function(Scope, Fn) :- cfa_parent(Scope, function(Fn)). +%scope_function(Scope, Fn) :- cfa_parent(Scope, scope(ScopeParent)), scope_function(ScopeParent, Fn). diff --git a/scripts/metatests/context-latecontext3.lp b/core/control-context-v3.lp similarity index 93% copy from scripts/metatests/context-latecontext3.lp copy to core/control-context-v3.lp index ca81a77..1b651f1 100644 --- a/scripts/metatests/context-latecontext3.lp +++ b/core/control-context-v3.lp @@ -1,48 +1,52 @@ %% SCHEMA: %% specialization(Fn, Scope) - problem of what specialization of Fn should be picked up in Scope. %% resolution_dependency(Resolution, Dependency) - Dependency is necessary prerequisite for choosing Resolution. %% - + +true. + %nested scope propagation: bind_scope(Scope, Context, Info) :- bind_scope(ScopeParent, Context, Info), cfa_parent(Scope, scope(ScopeParent)). %strong/uniform inter-function propagation: bind_scope(Scope, Context,Info) :- bind_scope(ScopeParent, Context, Info): cfa_call(ScopeParent, FnCurrent); cfa_parent(Scope, function(FnCurrent)); cfa_call(_, FnCurrent); bind_scope(_, Context, Info); scope(Scope). %weak inter-function propagation bind_scope(Scope, Context, weak(ScopeParent)):- not bind_scope(Scope, Context, strong), bind_scope(ScopeParent, Context, strong), cfa_call(ScopeParent, FnCurrent), cfa_parent(Scope, function(FnCurrent)). bind_scope(Scope, Context, weak(ScopeParent, Info)):- Info<>strong, not bind_scope(Scope, Context, Info), bind_scope(ScopeParent, Context, Info), cfa_call(ScopeParent, FnCurrent), cfa_parent(Scope, function(FnCurrent)). %make decisions %%%bind_scope_decision(Scope, loop(Subject), Scope):- cfa_contextloop(Scope, Subject), demand_dependency(loop(Subject), X), bind_scope(Scope, X, strong).* %%%bind_scope_decision(Scope, loop(Subject), Scope):- cfa_call(Scope, FnChild), bind_function_demand(FnChild, loop(Subject)), demand_dependency(loop(Subject), X), bind_scope(Scope, X, strong). %on-site decision % ASSERT: ON-SITE DECISION SHOULD BE FIRST CLASS (checks at least one specialization exists) bind_scope_decision(Scope, Subject, Resolution):- bind_scope(Scope, Resolution, strong), Subject = specialization(Fn, Scope), cfa_call(Scope, Fn), cfa_function_specializations(Fn, Resolution). bind_scope_decision(ScopeSource, Subject, Resolution):- bind_scope(Scope, Resolution, weak(ScopeSource)), Subject = specialization(Fn, Scope), cfa_call(Scope, Fn), cfa_function_specializations(Fn, Resolution). bind_scope_decision(ScopeSource, Subject, resolution_dependency(Resolution, Dependency)):- bind_scope(Scope, Resolution, weak(ScopeSource, Dependency)), Subject = specialization(Fn, Scope), cfa_call(Scope, Fn), cfa_function_specializations(Fn, Resolution). %dependent decisions bind_scope_demand(Scope, dependency(Subject, Scope)) :- bind_scope_decision(Scope, Subject, resolution_dependency(_, Dependency)). +bind_scope_demand(ScopeSource, dependency(Subject, ScopeSource)) :- Dependency = weak(ScopeSource, DependencyTail), bind_scope_demand(Scope, dependency(Subject, Scope)), scope_dependencies(dependency(Subject, Scope), Dependency). bind_scope_decision(ScopeSource, dependency(Subject, Scope), Dependency) :- Dependency = weak(ScopeSource), bind_scope_demand(Scope, dependency(Subject, Scope)), scope_dependencies(dependency(Subject, Scope), Dependency). -bind_scope_demand(ScopeSource, dependency(Subject, ScopeSource)) :- Dependency = weak(ScopeSource, DependencyTail), bind_scope_demand(Scope, dependency(Subject, Scope)), scope_dependencies(dependency(Subject, Scope), Dependency). +bind_scope_decision(ScopeSource, dependency(Subject, Scope), resolution_dependency(Dependency, DependencyTail)) :- Dependency = weak(ScopeSource, DependencyTail), bind_scope_demand(Scope, dependency(Subject, Scope)), scope_dependencies(dependency(Subject, Scope), Dependency). + %dependent decision helpers: scope_dependencies(dependency(Subject, Scope), Dependency) :- bind_scope_decision(Scope, Subject, resolution_dependency(_, Dependency)). scope_dependencies(dependency(Subject, ScopeSource), DependencyTail) :- Dependency = weak(ScopeSource, DependencyTail), bind_scope_demand(Scope, dependency(Subject, Scope)), scope_dependencies(dependency(Subject, Scope), Dependency). %on-site demand % ASSERT: ON-SITE DEMAND SHOULD BE dependent OF on-site decision (check there are no specializations AT ALL) %%%bind_scope_demand(Scope, Subject):- cfa_contextloop(Scope, Subject), not bind_scope_decision(Scope, loop(Subject), _). bind_scope_demand(Scope, Subject):- Subject = specialization(FnCallee, Scope), cfa_call(Scope, FnCallee), cfa_function_specializations(FnCallee, _), not bind_scope_decision(Scope, Subject, _). %nested scope demand propagation %ASSERT: NO DECISION CHECKS. because decisions linked to a leaf(function execution sites) scopes bind_scope_demand(Scope, Subject):- bind_scope_demand(ScopeChild, Subject), cfa_parent(ScopeChild, scope(Scope)). bind_function_demand(Fn, Subject):- bind_scope_demand(Scope, Subject), cfa_parent(Scope, function(Fn)). %inter-function propagation demand bind_scope_demand(Scope, Subject):- cfa_call(Scope, FnChild), bind_function_demand(FnChild, Subject), not bind_scope_decision(Scope, Subject, _). diff --git a/core/dominators.lp b/core/dominators.lp new file mode 100644 index 0000000..e69de29 diff --git a/core/exploitation.lp b/core/exploitation.lp new file mode 100644 index 0000000..20f47d5 --- /dev/null +++ b/core/exploitation.lp @@ -0,0 +1,12 @@ +expl_sites(Data, Site) :- S=(_, Site); bind(S, exploitation_initialized(file)); bind(S, static(data(Data))). +expl_sites(Data, Site) :- S=(_, Site); bind(S, exploitation_initialized(file)); bind(S, static(ref(Root))); bind(Root, static(data(Data))). + + +expl_parent(Site, dom(Parent)) :- cfa_forwdom(Parent, range(A, B)); cfa_forwdom(Site, range(A1, B1)); A #include #include "clang/Tooling/Tooling.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CodeGenOptions.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Lex/PreprocessorOptions.h" #include #include #include +#include "../../vendors/clang-codegen-private-3.8/CodeGenModule.h" + using namespace xreate; using namespace std; using namespace clang; using namespace clang::driver; using namespace clang::tooling; using namespace clang::ast_matchers; using namespace llvm; class FinderCallbackTypeDecl : public MatchFinder::MatchCallback { public : QualType typeResult; virtual void run(const MatchFinder::MatchResult &Result) { if (const TypedefDecl* decl = Result.Nodes.getNodeAs("typename")) { typeResult = decl->getUnderlyingType(); } } }; class FinderCallbackFunction : public MatchFinder::MatchCallback { public : QualType typeResult; virtual void run(const MatchFinder::MatchResult &Result) { if (const FunctionDecl* decl = Result.Nodes.getNodeAs("function")) { typeResult = decl->getType(); } } }; void ExternData::addLibrary(Atom&& name, Atom&& package) { __dictLibraries.emplace(name.get(), package.get()); } void ExternData::addIncludeDecl(Expression&& e) { assert(e.op == Operator::LIST_NAMED); //TODO ?? implement Expression parsing(Array of Expr as vector); for(size_t i=0, size=e.operands.size(); i headers; std::transform(listHeaders.operands.begin(), listHeaders.operands.end(), std::inserter(headers, headers.end()), [](const Expression& o){ assert(o.__state == Expression::STRING); return o.getValueString(); }); entries.emplace_back(ExternEntry{package, std::move(headers)}); } } void ExternLayer::addExternalData(const std::vector& data){ entries.insert(entries.end(), data.begin(), data.end()); } ExternLayer::ExternLayer(LLVMLayer *llvm) - : __datalayout(llvm->module), __llvm(llvm) + : __llvm(llvm) {} std::vector ExternLayer::fetchPackageFlags(const ExternEntry& entry){ std::vector args; FILE* flags = popen((string("pkg-config --cflags ") + entry.package).c_str(), "r"); size_t linesize=0; char* linebuf=0; ssize_t linelen=0; while ((linelen=getdelim(&linebuf, &linesize, ' ', flags))>0) { if (linebuf[0]=='\n') continue; if (linelen==1 && linebuf[0]==' ') continue; if (linebuf[linelen-1 ] == ' ') linebuf[linelen-1] = 0; llvm::outs() << '<' << linebuf << "> "; args.push_back(linebuf); free(linebuf); linebuf = 0; } pclose(flags); return (args); } std::vector ExternLayer::fetchPackageLibs(const ExternEntry& entry){ std::vector libs; FILE* flags = popen((string("pkg-config --libs ") + entry.package).c_str(), "r"); size_t linesize=0; char* linebuf=0; ssize_t linelen=0; while ((linelen=getdelim(&linebuf, &linesize, ' ', flags))>0) { if (linebuf[0]=='\n') continue; if (linelen==1 && linebuf[0]==' ') continue; if (linebuf[linelen-1 ] == ' ') linebuf[linelen-1] = 0; if (linelen>=2 && linebuf[0] == '-' && linebuf[1] == 'l'){ libs.push_back(linebuf + 2); } else { libs.push_back(linebuf); } llvm::outs() << '<' << linebuf << "> "; free(linebuf); linebuf = 0; } pclose(flags); return (libs); } void ExternLayer::loadLibraries(vector&& libs){ string msgErr; for (const string& lib: libs) { const string& libName = string("lib")+lib+".so"; if (!llvm::sys::DynamicLibrary::LoadLibraryPermanently(libName.c_str(), &msgErr)){ llvm::errs()<<"\n"<<"Loading library "<__externdata); // TODO use default include path from 'clang -xc++ -E' list code; std::vector args{ "-I/usr/include" ,"-I/usr/local/include" ,"-I/usr/lib/llvm-3.6/lib/clang/3.6.2/include" // ,"-I/usr/lib/gcc/x86_64-linux-gnu/4.9/include" // ,"-I/usr/include/x86_64-linux-gnu" }; std::vector libs; boost::format formatInclude("#include \"%1%\""); for(const ExternEntry& entry: entries) { llvm::outs()<<"[ExternC] Processing package: "<< entry.package << "\n"; llvm::outs()<<"[ExternC] args: "; vector&& args2 = fetchPackageFlags(entry); args.insert(args.end(), args2.begin(), args2.end()); for(const string arg: args2) { llvm::outs()<< "<" << arg << "> "; } llvm::outs()<<"\n[ExternC] libs: "; args2 = fetchPackageLibs(entry); for(const string arg: args2) { llvm::outs()<< "<" << arg << "> "; } libs.insert(libs.end(), args2.begin(), args2.end()); llvm::outs()<<"\n[ExternC] headers: "; std::transform(entry.headers.begin(), entry.headers.end(), std::inserter(code, code.begin()), [&formatInclude](const string header ) { string line = boost::str(formatInclude % header); llvm::outs()<< "<" << line << "> "; return line; }); llvm::outs() << '\n'; } loadLibraries(move(libs)); ast = buildASTFromCodeWithArgs(boost::algorithm::join(code, "\n"), args); __cgo.reset(new CodeGenOptions); - __datalayout = llvm::DataLayout(ast->getASTContext().getTargetInfo().getTargetDescription()); - __cgm.reset(new CodeGen::CodeGenModule(ast->getASTContext(), *__cgo, *__llvm->module, __datalayout, ast->getASTContext().getDiagnostics())); + __llvm->module->setDataLayout(ast->getASTContext().getTargetInfo().getDataLayoutString()); + + std::unique_ptr __hso(new HeaderSearchOptions()); + std::unique_ptr __ppo(new PreprocessorOptions()); + + __cgm.reset(new CodeGen::CodeGenModule( + ast->getASTContext(), + + *__hso, + *__ppo, + *__cgo, + *__llvm->module, + ast->getASTContext().getDiagnostics())); }; bool ExternLayer::isPointer(const clang::QualType &t) { const clang::Type * tInfo = t.getTypePtr(); assert(tInfo); return tInfo->isAnyPointerType(); } llvm::Type* ExternLayer::toLLVMType(const clang::QualType& t){ return __cgm->getTypes().ConvertType(t); } std::vector ExternLayer::getStructFields(const clang::QualType& ty) { clang::QualType t = ty; if (isPointer(ty)){ const clang::PointerType* tPtr = ty->getAs(); t = tPtr->getPointeeType(); } assert(t.getTypePtr()->isRecordType()); const RecordType *record = t->getAsStructureType(); assert(record); std::vector result; //FieldDecl* field: record->getDecl()->fields() for (auto i=record->getDecl()->field_begin(); i!= record->getDecl()->field_end(); ++i){ result.push_back(i->getName()); } return result; } clang::QualType ExternLayer::lookupType(const std::string& id){ MatchFinder finder; FinderCallbackTypeDecl callbackTypeDecl; auto matcherTypeDecl = typedefDecl(hasName(id)).bind("typename"); finder.addMatcher(matcherTypeDecl, &callbackTypeDecl); finder.matchAST(ast->getASTContext()); assert(! callbackTypeDecl.typeResult.isNull()); return callbackTypeDecl.typeResult; } llvm::Function* ExternLayer::lookupFunction(const std::string& name){ if (__functions.count(name)){ return __functions.at(name); } MatchFinder finder; FinderCallbackFunction callback; auto matcher = functionDecl(hasName(name)).bind("function"); finder.addMatcher(matcher, &callback); finder.matchAST(ast->getASTContext()); if (callback.typeResult.isNull()){ cout <<"[External Layer] " << "Unknown function: "<getTypes().ConvertType(tyFuncQual); llvm::FunctionType* tyRawFunc = llvm::dyn_cast(tyRaw); llvm::Function* function = llvm::Function::Create(tyRawFunc, llvm::GlobalValue::ExternalLinkage, name, __llvm->module); __functions.emplace(name, function); return function; } diff --git a/cpp/src/ExternLayer.h b/cpp/src/ExternLayer.h index ab41749..a126843 100644 --- a/cpp/src/ExternLayer.h +++ b/cpp/src/ExternLayer.h @@ -1,55 +1,54 @@ // // Created by pgess on 4/21/15. // #ifndef XREATE_EXTERNLAYER_H #define XREATE_EXTERNLAYER_H #include "llvmlayer.h" #include #include #include #include "ast.h" #include "clang/AST/ASTContext.h" -#include "/opt/llvm-toolchain-3.6-3.6/clang/lib/CodeGen/CodeGenModule.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CodeGenOptions.h" +#include "clang/CodeGen/CodeGenABITypes.h" namespace xreate { struct ExternData { void addLibrary(Atom&& name, Atom&& package); void addIncludeDecl(Expression&& e); std::vector entries; std::map __dictLibraries; }; class ExternLayer { public: ExternLayer(LLVMLayer* llvm); llvm::Function* lookupFunction(const std::string& name); clang::QualType lookupType(const std::string& id); std::vector getStructFields(const clang::QualType& ty); llvm::Type* toLLVMType(const clang::QualType& t); bool isPointer(const clang::QualType& t); void init(const AST* root); static std::vector fetchPackageFlags(const ExternEntry& entry); static std::vector fetchPackageLibs(const ExternEntry& entry); private: std::unique_ptr ast; std::unique_ptr __cgm; std::unique_ptr __cgo; - llvm::DataLayout __datalayout; LLVMLayer* __llvm; std::vector entries; std::map __functions; void addExternalData(const std::vector& data); void loadLibraries(std::vector&& libs); }; } #endif //XREATE_EXTERNLAYER_H diff --git a/cpp/src/analysis/DominatorsTreeAnalysisProvider.cpp b/cpp/src/analysis/DominatorsTreeAnalysisProvider.cpp new file mode 100644 index 0000000..7d08a2d --- /dev/null +++ b/cpp/src/analysis/DominatorsTreeAnalysisProvider.cpp @@ -0,0 +1,233 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +/* + * File: DominatorsTreeAnalysisProvider.cpp + * Author: pgess + * + * Created on May 13, 2016, 11:39 AM + */ + +#include "analysis/cfagraph.h" +#include "analysis/DominatorsTreeAnalysisProvider.h" + +#include "llvm/ADT/GraphTraits.h" +#include "llvm/Support/GenericDomTreeConstruction.h" +#include "llvm/Support/GenericDomTree.h" + +#include +#include +#include + +using namespace std; +using namespace xreate; +using namespace boost; +using namespace boost::bimaps; + +struct ControlFlowTree; + +struct Node { + ScopePacked scope; + ControlFlowTree* tree; +}; + +/* +bool operator !=(const Node& a, const Node& b){ + return (a.tree != b.tree) || (a.scope != b.scope); +} + +Node& operator++(Node& a){ + ++a.scope; + return a; +} + */ + +struct ControlFlowTree{ + typedef bimap, multiset_of> CHILD_RELATIONS; + CHILD_RELATIONS edges; + std::vector nodes; + Node* entry = nullptr; + size_t size; + + ControlFlowTree(const size_t nodesCount): nodes(nodesCount), size(nodesCount){ + } + + static ControlFlowTree* build(const ClaspLayer* engine){ + ControlFlowTree* tree = new ControlFlowTree(engine->getScopesCount()); + + xreate::analysis::CFAGraph* graph = engine->dataCFA.get(); + + for (const auto& edge: graph->__parentScopeRelations){ + tree->edges.insert(CHILD_RELATIONS::value_type(edge.second, edge.first)); + } + + for (const auto& edge: graph->__callRelations){ + unsigned int calleeFunction = edge.right; + ScopePacked caller = edge.left; + + auto range = graph->__parentFunctionRelations.right.equal_range(calleeFunction); + for (auto& i=range.first; i!= range.second; ++i){ + tree->edges.insert(CHILD_RELATIONS::value_type(caller, i->second)); + } + } + + for (size_t i=0; isize; ++i){ + tree->nodes[i]= Node{(unsigned int) i, tree}; + } + + return tree; + } + + std::list getRootFunctions() const{ + size_t idMax = size; + size_t id =0; + std::list results; + auto i = edges.right.begin(); + + while (id < idMax) { + if (i!= edges.right.end() && i->first == id){ + i = edges.right.upper_bound(i->first); + + } else { + results.push_back(id); + } + + ++id; + } + + return std::move(results); + } +}; + +namespace llvm { + template <> struct GraphTraits { + typedef Node* nodes_iterator; + typedef Node NodeType; + + typedef std::function Transformer; + typedef typename boost::iterators::transform_iterator ChildIteratorType; + + static ChildIteratorType child_begin(const nodes_iterator& node) { + auto range = node->tree->edges.left.equal_range(node->scope); + Transformer x = [node](auto edge){return &node->tree->nodes[edge.second];}; + + return boost::make_transform_iterator(range.first, x); + } + + static ChildIteratorType child_end(const nodes_iterator& node) { + auto range = node->tree->edges.left.equal_range(node->scope); + Transformer x = [node](auto edge){return &node->tree->nodes[edge.second];}; + + return boost::make_transform_iterator(range.second, x); + } + }; + + template <> struct GraphTraits> { + typedef Node* nodes_iterator; + typedef Node NodeType; + + typedef std::function Transformer; + typedef typename boost::iterators::transform_iterator ChildIteratorType; + + static ChildIteratorType child_begin(const nodes_iterator& node) { + auto range = node->tree->edges.right.equal_range(node->scope); + Transformer x = [node](auto edge){return &node->tree->nodes[edge.second];}; + + return boost::make_transform_iterator(range.first, x); + } + + static ChildIteratorType child_end(const nodes_iterator& node) { + auto range = node->tree->edges.right.equal_range(node->scope); + Transformer x = [node](auto edge){return &node->tree->nodes[edge.second];}; + + return boost::make_transform_iterator(range.second, x); + } + }; + + template <> struct GraphTraits: public GraphTraits { + static NodeType* + getEntryNode(ControlFlowTree* F) { + if (F->entry) return F->entry; + + list&& roots = F->getRootFunctions(); + assert(roots.size()==1); + + return F->entry = &F->nodes[roots.front()]; + } + + static nodes_iterator nodes_begin(ControlFlowTree* F) { return &F->nodes[0]; } + static nodes_iterator nodes_end(ControlFlowTree* F) { return &F->nodes[F->size]; } + static size_t size(ControlFlowTree* F) { return F->size; } + }; +} + +class xreate::DominatorTree: public llvm::DominatorTreeBase { +public: + DominatorsTreeAnalysisProvider::Dominators dominators; + + DominatorTree(bool isPostDom): llvm::DominatorTreeBase(isPostDom) {} + + void run(ControlFlowTree& program){ + recalculate(program); + + //extract dominators info + for (auto& entry: DomTreeNodes){ + if (!entry.getFirst()) continue; + + dominators.emplace(entry.getFirst()->scope, make_pair(entry.getSecond()->getDFSNumIn(), entry.getSecond()->getDFSNumOut())); + } + } + + void print(std::ostringstream& output, const std::string& atom) const { + boost::format formatAtom(atom + "(%1%, range(%2%, %3%))."); + for (auto entry: dominators){ + output << formatAtom % (entry.first) % (entry.second.first) % (entry.second.second) + << endl; + } + } +}; + +void +DominatorsTreeAnalysisProvider::run(const ClaspLayer* engine){ + boost::scoped_ptr program(ControlFlowTree::build(engine)); + + treeForwardDominators->run(*program); + treePostDominators->run(*program); +} + +void +DominatorsTreeAnalysisProvider::print(std::ostringstream& output) const{ + treeForwardDominators->print(output, "cfa_forwdom"); + treePostDominators->print(output, "cfa_postdom"); +} + +const DominatorsTreeAnalysisProvider::Dominators& +DominatorsTreeAnalysisProvider::getForwardDominators() const{ + return treeForwardDominators->dominators; +} + +const DominatorsTreeAnalysisProvider::Dominators& +DominatorsTreeAnalysisProvider::getPostDominators() const{ + return treePostDominators->dominators; +} + +DominatorsTreeAnalysisProvider::DominatorsTreeAnalysisProvider() + : treeForwardDominators(new DominatorTree(false)) + , treePostDominators(new DominatorTree(true)) +{} + +DominatorsTreeAnalysisProvider::~DominatorsTreeAnalysisProvider() {} + +//void +//CodeScopesTree::print(){ +// typedef llvm::GraphTraits Traits; +// for (size_t i=0; i" << (*j)->scope << endl; +// } +// } +//} \ No newline at end of file diff --git a/cpp/src/analysis/DominatorsTreeAnalysisProvider.h b/cpp/src/analysis/DominatorsTreeAnalysisProvider.h new file mode 100644 index 0000000..5574891 --- /dev/null +++ b/cpp/src/analysis/DominatorsTreeAnalysisProvider.h @@ -0,0 +1,44 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +/* + * File: DominatorsTreeAnalysisProvider.h + * Author: pgess + * + * Created on May 13, 2016, 11:39 AM + */ + +#ifndef DOMINATORSTREEANALYSISPROVIDER_H +#define DOMINATORSTREEANALYSISPROVIDER_H + +#include "clasplayer.h" +#include + +namespace xreate{ + class DominatorTree; + + class DominatorsTreeAnalysisProvider: public IAnalysisData { + public: + typedef std::pair DominatedRange; + typedef std::map Dominators; + + DominatorsTreeAnalysisProvider(); + virtual ~DominatorsTreeAnalysisProvider(); + + void run(const ClaspLayer* engine); + void print(std::ostringstream& output) const; + + const Dominators& getForwardDominators() const; + const Dominators& getPostDominators() const; + + private: + boost::scoped_ptr treeForwardDominators; + boost::scoped_ptr treePostDominators; + }; +} + +#endif /* DOMINATORSTREEANALYSISPROVIDER_H */ + diff --git a/cpp/src/analysis/aux.cpp b/cpp/src/analysis/aux.cpp new file mode 100644 index 0000000..6d5192c --- /dev/null +++ b/cpp/src/analysis/aux.cpp @@ -0,0 +1,136 @@ +#include "aux.h" +#include + +namespace xreate { namespace analysis { + +using namespace std; + +list +multiplyLists(list> &&lists) { + typedef list StringList; + assert(lists.size()); + StringList result(*lists.begin()); + lists.pop_front(); + + boost::format concat("%s, %s"); + for (StringList &list: lists) { + StringList::const_iterator end = result.end(); + for (StringList::iterator expr1I = result.begin(); expr1I != end; ++expr1I) { + if (list.size() == 0) continue; + + StringList::const_iterator expr2I = list.begin(); + for (int expr2No = 0, size = list.size() - 1; expr2No < size; ++expr2No, ++expr1I) + result.push_back(str(concat %(*expr1I) %(*expr2I))); + + *expr1I = str(concat %(*expr1I) %(*expr2I)); + } + } + + return result; +} + +std::list +compile(const Expression &e){ + list result; + + switch (e.op) { + case Operator::CALL: { + assert(e.__state == Expression::COMPOUND); + + std::list> operands; + std::transform(e.operands.begin(), e.operands.end(), std::inserter(operands, operands.begin()), + [](const Expression &e) { + return compile(e); + }); + + list &&operands_ = multiplyLists(std::move(operands)); + result.push_back(boost::str(boost::format("%1%(%2%)") % (e.getValueString()) % (boost::algorithm::join(operands_, ", ")))); + break; + } + case Operator::NEG: { + assert(e.operands.size() == 1); + + const Expression &op = e.operands.at(0); + list &&rawOp = compile(op); + + assert(rawOp.size() == 1); + result.push_back((boost::format("not %1%")%(rawOp.front())).str()); + break; + }; + + case Operator::NONE: { + switch (e.__state) { + case Expression::IDENT: + result.push_back(e.getValueString()); + break; + + case Expression::NUMBER: + result.push_back(to_string(e.getValueDouble())); + break; + + default: + assert(true); + } + break; + } + + default: break; + } + +//TODO Null ad hoc ClaspLayer implementation +// if (e.isNone()){ +// result.push_back(e.__valueS); +// } + + assert(result.size()); + return result; +} + +std::list +compileNeg(const Expression &e){ + list result; + switch (e.op) { + case Operator::IMPL: { + assert(e.__state == Expression::COMPOUND); + assert(e.operands.size() == 2); + list operands1 = compile(e.operands.at(0)); + list operands2 = compile(e.operands.at(1)); + + boost::format formatNeg("%1%, not %2%"); + for (const auto &op1: operands1) + for (const auto &op2: operands2) { + result.push_back(boost::str(formatNeg %(op1) % (op2))); + } + break; + } + case Operator::NEG: { + assert(e.operands.size() == 1); + + const Expression &op = e.operands.at(0); + list &&rawOp = compile(op); + + assert(rawOp.size() == 1); + result.push_back(rawOp.front()); + break; + }; + + default: + assert(true); + } + + return result; +} + +boost::format +formatSymbol(const SymbolPacked& s){ + boost::format formatSymbNamed("(%1%, %2%)"); + boost::format formatSymbAnonymous("(anonym(%1%), %2%)"); + + if (!s.categoryTransient){ + return formatSymbNamed % s.identifier % s.scope; + } else { + return formatSymbAnonymous % s.identifier % s.scope; + } +} + +}} \ No newline at end of file diff --git a/cpp/src/analysis/aux.h b/cpp/src/analysis/aux.h new file mode 100644 index 0000000..c8bad41 --- /dev/null +++ b/cpp/src/analysis/aux.h @@ -0,0 +1,25 @@ +/* + * File: aux.h + * Author: pgess + * + * Created on June 26, 2016, 6:49 PM + */ + +#ifndef AUX_H +#define AUX_H + +#include "ast.h" +#include "clasplayer.h" + +#include +#include + +namespace xreate { namespace analysis { + std::list compile(const Expression &e); + std::list compileNeg(const Expression &e); + std::list multiplyLists(std::list> &&lists); + boost::format formatSymbol(const SymbolPacked& s); +}} + +#endif /* AUX_H */ + diff --git a/cpp/src/analysis/cfagraph.cpp b/cpp/src/analysis/cfagraph.cpp new file mode 100644 index 0000000..be428ed --- /dev/null +++ b/cpp/src/analysis/cfagraph.cpp @@ -0,0 +1,166 @@ +/* + * File: CFAGraph.cpp + * Author: pgess + * + * Created on June 27, 2016, 2:09 PM + */ + +#include "analysis/cfagraph.h" +#include "analysis/aux.h" + +using namespace xreate::analysis; +using namespace std; + +void +CFAGraph::print(std::ostringstream& output) const { + const std::string& atomBinding = Config::get("clasp.bindings.function"); + const std::string& atomBindingScope = Config::get("clasp.bindings.scope"); + + //show function tags + int counterTags = 0; + std::ostringstream bufFunctionNames; + boost::format formatFunction("function(%1%)."); + boost::format formatBind(atomBinding + "(%1%, %2%)."); + for (auto function: this->__nodesFunction.left) { + const auto tags = this->__functionTags.equal_range(function.first); + if (tags.first == tags.second) { + //no tags + bufFunctionNames << "; " << function.second ; + continue; + } + + output << formatFunction % (function.second) << std::endl; + for (const auto& tag_: boost::make_iterator_range(tags)){ + const Expression& tag = tag_.second; + + list tagRaw = xreate::analysis::compile(tag); + assert(tagRaw.size() == 1); + + output << formatBind + % (function.second) + % (tagRaw.front()) + << endl; + ++counterTags; + } + } + + if (bufFunctionNames.tellp()){ + output << formatFunction % (bufFunctionNames.str().substr(2)) << std::endl; + } + + if (counterTags == 0) { + output << "%no functtion tags at all" << endl; + } + + //declare scopes + boost::format formatScope("scope(0..%1%)."); + output << formatScope % (__clasp->getScopesCount() - 1) << std::endl; + + //show context rules: + for (auto rule: this->__contextRules) { + output << ContextRule(rule.second).compile(rule.first) << std::endl; + }; + + //show scope tags: + counterTags = 0; + boost::format formatScopeBind(atomBindingScope + "(%1%, %2%, strong)."); + for (auto entry: this->__scopeTags) { + ScopePacked scopeId = entry.first; + const Expression& tag = entry.second; + list tagRaw = xreate::analysis::compile(tag); + assert(tagRaw.size() == 1); + + output << formatScopeBind % scopeId %(tagRaw.front()) << endl; + ++counterTags; + } + + if (counterTags == 0) { + output << "%scope tags: no tags at all" << endl; + } + + output << endl << "%\t\tStatic analysis: CFA" << endl; + + //parent connections + //TOTEST CFG parent function + boost::format formatFunctionParent("cfa_parent(%1%, function(%2%))."); + for (const auto &relation: this->__parentFunctionRelations) { + const string& function = this->__nodesFunction.left.at(relation.right); + + output << formatFunctionParent % relation.left % function << endl; + } + + //TOTEST CFG parent scope + boost::format formatScopeParent("cfa_parent(%1%, scope(%2%))."); + for (const auto &relation: this->__parentScopeRelations) { + output << formatScopeParent % relation.first % relation.second << endl; + } + + //call connections + boost::format formatCall("cfa_call(%1%, %2%)."); + + for (const auto &relation: this->__callRelations) { + const ScopePacked scopeFrom = relation.left; + const string& functionTo = this->__nodesFunction.left.at(relation.right); + + output << formatCall % (scopeFrom) % (functionTo) << endl; + } + + //function specializations descrtiption + //SECTIONTAG late-context cfa_function_specializations + boost::format formatSpecializations("cfa_function_specializations(%1%, %2%)."); + const list& functions = __clasp->ast->getAllFunctions(); + for (auto f: functions){ + if (f->guardContext.isValid()){ + list guardRaw = xreate::analysis::compile(f->guardContext); + assert(guardRaw.size() == 1); + output << formatSpecializations % (f->getName()) % (guardRaw.front()) << endl; + } + } +} + +void +CFAGraph::addFunctionAnnotations(const std::string& function, const std::map& tags) { + unsigned int fid = registerNodeFunction(function); + + for (auto& tag: tags){ + __functionTags.emplace(fid, tag.second); + } +} + +void +CFAGraph::addScopeAnnotations(const ScopePacked& scope, const std::vector& tags){ + for (Expression tag: tags){ + __scopeTags.emplace(scope, tag); + } +} + +void +CFAGraph::addContextRules(const ScopePacked& scope, const std::vector& rules){ + for (Expression rule: rules){ + __contextRules.emplace(scope, rule); + } +} + +void +CFAGraph::addCallConnection(const ScopePacked& scopeFrom, const std::string& functionTo) { + unsigned int idFuncTo = registerNodeFunction(functionTo); + + __callRelations.insert(CALL_RELATIONS::value_type(scopeFrom, idFuncTo)); +} + +void +CFAGraph::addParentConnection(const ScopePacked& scope, const std::string& functionParent){ + __parentFunctionRelations.insert(PARENT_FUNCTION_RELATIONS::value_type(scope, registerNodeFunction(functionParent))); +} + +void +CFAGraph::addParentConnection(const ScopePacked& scope, const ScopePacked& scopeParent){ + __parentScopeRelations.emplace(scope, scopeParent); +} + +unsigned int +CFAGraph::registerNodeFunction(const std::string& fname){ + auto pos = __nodesFunction.left.insert(make_pair(__nodesFunction.size(), fname)); + + return pos.first->first; +} diff --git a/cpp/src/analysis/cfagraph.h b/cpp/src/analysis/cfagraph.h new file mode 100644 index 0000000..a60499a --- /dev/null +++ b/cpp/src/analysis/cfagraph.h @@ -0,0 +1,56 @@ +/* + * File: CFAGraph.h + * Author: pgess + * + * Created on June 27, 2016, 2:09 PM + */ + +#ifndef CFAGRAPH_H +#define CFAGRAPH_H + +#include "clasplayer.h" + +namespace xreate {namespace analysis { + + class CFAGraph: public IAnalysisData { + public: + typedef boost::bimap> PARENT_FUNCTION_RELATIONS; + PARENT_FUNCTION_RELATIONS __parentFunctionRelations; + std::map __parentScopeRelations; + + typedef boost::bimap< + boost::bimaps::multiset_of, + boost::bimaps::multiset_of, + boost::bimaps::set_of_relation<> + > CALL_RELATIONS; + + CALL_RELATIONS __callRelations; + + boost::bimap __nodesFunction; + std::multimap __functionTags; + std::multimap __scopeTags; + std::multimap __contextRules; + + void print(std::ostringstream& output) const; + CFAGraph(ClaspLayer* engine): __clasp(engine){} + + void addFunctionAnnotations(const std::string& function, const std::map& tags); + void addScopeAnnotations(const ScopePacked& scope, const std::vector&tags); + void addContextRules(const ScopePacked& scope, const std::vector&rules); + + void addCallConnection(const ScopePacked& scopeFrom, const std::string& functionTo); + void addParentConnection(const ScopePacked& scope, const std::string& functionParent); + void addParentConnection(const ScopePacked& scope, const ScopePacked& scopeParent); + // void addScopeRetIdentifier(const ScopePacked& scope, const SymbolPacked& identifier); + + private: + ClaspLayer* __clasp; + + unsigned int registerNodeFunction(const std::string& fname); + + }; + +}} + +#endif /* CFAGRAPH_H */ + diff --git a/cpp/src/analysis/dfagraph.cpp b/cpp/src/analysis/dfagraph.cpp new file mode 100644 index 0000000..360035b --- /dev/null +++ b/cpp/src/analysis/dfagraph.cpp @@ -0,0 +1,237 @@ +#include "analysis/dfagraph.h" +#include "analysis/aux.h" + +#include + + +using namespace xreate; +using namespace xreate::analysis; +using namespace std; + +namespace xreate {namespace analysis { +void +DFAGraph::print(std::ostringstream& output) const { + std::set symbols; + + output << endl << "%\t\tStatic analysis: DFA" << endl; + + std::vector>::const_iterator i1; + std::vector::const_iterator i2; + + boost::format formatDfaConnection("dfa_connection(%1%, %2%, %3%)."); + for (i1= this->__edges.begin(), i2 = this->__data.begin(); i1!= this->__edges.end(); ++i1, ++i2 ) + { + string edgeName; + switch (*i2) + { + case DFGConnection::WEAK: edgeName = "weak"; break; + case DFGConnection::STRONG: edgeName = "strong"; break; + case DFGConnection::PROTOTYPE: edgeName = "proto"; break; + } + + output << formatDfaConnection + %formatSymbol(i1->first) + %formatSymbol(i1->second) + %edgeName + << " %" <__clasp->getHintForPackedSymbol(i1->first) << " - " << this->__clasp->getHintForPackedSymbol(i1->second) + <first); + symbols.insert(i1->second); + } + + boost::format formatDfaDependency("dfa_dependency(%1%, %2%)."); + for (auto i= this->__dependencies.begin(); i!= this->__dependencies.end(); ++i){ + output<first) + %formatSymbol(i->second) + << " %" + << this->__clasp->getHintForPackedSymbol(i->first) << " - " + << this->__clasp->getHintForPackedSymbol(i->second) + <& tag: this->__tags) + { + for (string variant: xreate::analysis::compile(tag.second)) { + output << formatBind + % formatSymbol(tag.first) + % (variant) + << "%" << this->__clasp->getHintForPackedSymbol(tag.first) + << endl; + } + + symbols.insert(tag.first); + } + + for (const SymbolPacked& s: symbols) + { + output << "v(" << formatSymbol(s) << ")." + << " %" << this->__clasp->getHintForPackedSymbol(s) + < { + public: + void operator()(const SymbolPacked& symbol){ + __graph->__tags.emplace(symbol, move(__tag)); + } + + void operator()(SymbolTransient& symbol){ + symbol.tags.push_back(move(__tag)); + } + + void operator()(const SymbolInvalid& symbol){ + assert(false && "Undefined behaviour"); + } + + VisitorAddTag(DFAGraph* const dfagraph, Expression&& tag): + __graph(dfagraph), __tag(tag) {} + + private: + DFAGraph* const __graph; + Expression __tag; +}; + +class VisitorAddLink: public boost::static_visitor<> { +public: + void operator()(const SymbolPacked& nodeFrom){ + if (!__graph->isConnected(__nodeTo, nodeFrom)) + { + __graph->__edges.emplace_back(__nodeTo, nodeFrom); + __graph->__data.push_back(__link); + + DFAGraph::EdgeId eid = __graph->__edges.size()-1; + __graph->__outEdges.emplace(nodeFrom, eid); + } + } + + void operator()(const SymbolTransient& symbolFrom){ + switch (__link){ + case DFGConnection::WEAK: { + //virtual symbol to hold transient annotations + SymbolPacked symbPivot = __graph->createAnonymousSymbol(symbolFrom.scope); + + __graph->addConnection(symbPivot, symbolFrom, DFGConnection::STRONG); + __graph->addConnection(__nodeTo, symbPivot, DFGConnection::WEAK); + break; + } + + case DFGConnection::STRONG: { + for (const Expression& tag: symbolFrom.tags){ + __graph->__tags.emplace(__nodeTo, tag); + } + break; + } + + default: + assert(false && "Undefined behavior"); + } + } + + void operator()(const SymbolInvalid&){ + if (__link == DFGConnection::STRONG) return; + if (__link == DFGConnection::WEAK) return; + + assert(false && "Undefined behavior"); + } + + VisitorAddLink(DFAGraph* const dfagraph, const SymbolPacked& nodeTo, DFGConnection link): + __graph(dfagraph), __nodeTo(nodeTo), __link(link) {} + +private: + DFAGraph* const __graph; + SymbolPacked __nodeTo; + DFGConnection __link; +}; + +class VisitorGetDependencyConnection: public boost::static_visitor> { +public: + list + operator()(const SymbolPacked& nodeFrom){ + return {nodeFrom}; + } + + list + operator()(const SymbolTransient& nodeFrom){ + return nodeFrom.dependencies; + } + + list + operator()(const SymbolInvalid&){ + assert(false && "Undefined behavior"); + } + + VisitorGetDependencyConnection(DFAGraph* const g): graph(g){} + DFAGraph* const graph; +}; + +class VisitorSetDependencyConnection: public boost::static_visitor<> { +public: + void operator()(SymbolPacked& nodeTo){ + VisitorGetDependencyConnection visitorGetDepenencies(graph); + auto deps = boost::apply_visitor(visitorGetDepenencies, nodeFrom); + + for (const SymbolPacked& dep: deps){ + graph->__dependencies.emplace(nodeTo, dep); + } + } + + void operator()(SymbolTransient& nodeTo){ + VisitorGetDependencyConnection visitorGetDepenencies(graph); + auto deps = boost::apply_visitor(visitorGetDepenencies, nodeFrom); + + for (const SymbolPacked& dep: deps){ + nodeTo.dependencies.push_back(dep); + } + } + + void operator()(SymbolInvalid&){ + assert(false && "Undefined behavior"); + } + + VisitorSetDependencyConnection(DFAGraph* const g, SymbolNode s): graph(g), nodeFrom(s){} + DFAGraph* const graph; + SymbolNode nodeFrom; +}; + +bool +DFAGraph::isConnected(const SymbolPacked& identifierTo, const SymbolPacked& identifierFrom) +{ + auto range = __outEdges.equal_range(identifierFrom); + + for(std::multimap::iterator edge = range.first; edge != range.second; ++edge) + { + if (__edges[edge->second].second == identifierTo) + return true; + } + + return false; +} + +void +DFAGraph::addConnection(const SymbolPacked& nodeTo, const SymbolNode& nodeFrom, DFGConnection link) { + VisitorAddLink visitor(this, nodeTo, link); + boost::apply_visitor(visitor, nodeFrom); +} + +void +DFAGraph::addDependencyConnection(SymbolNode& identifierTo, SymbolNode& identifierFrom){ + VisitorSetDependencyConnection visitor(this, identifierFrom); + boost::apply_visitor(visitor, identifierTo); +} + +void +DFAGraph::addAnnotation(SymbolNode& node, Expression&& tag) { + VisitorAddTag visitor(this, move(tag)); + boost::apply_visitor(visitor, node); +} + +SymbolPacked +DFAGraph::createAnonymousSymbol(const ScopePacked& scope){ + return SymbolPacked{__countAnonymousSymbols++, scope, true}; +} + +}} \ No newline at end of file diff --git a/cpp/src/analysis/dfagraph.h b/cpp/src/analysis/dfagraph.h new file mode 100644 index 0000000..374ab14 --- /dev/null +++ b/cpp/src/analysis/dfagraph.h @@ -0,0 +1,57 @@ +/* + * File: dfa.h + * Author: pgess + * + * Created on June 27, 2016, 1:50 PM + */ + +#ifndef DFA_H +#define DFA_H + +#include "clasplayer.h" + +namespace xreate {namespace analysis { + + struct SymbolTransient { + std::list tags; + ScopePacked scope; + std::list dependencies; + }; + + struct SymbolInvalid { }; + + typedef boost::variant SymbolNode; + + class DFAGraph: public IAnalysisData{ + friend class VisitorAddTag; + friend class VisitorAddLink; + friend class VisitorGetDependencyConnection; + friend class VisitorSetDependencyConnection; + + + public: + DFAGraph(ClaspLayer* engine): __clasp(engine){} + + SymbolPacked createAnonymousSymbol(const ScopePacked& scope); + void addAnnotation(SymbolNode& identifier, Expression&& tag); + void addConnection(const SymbolPacked& identifierTo, const SymbolNode& identifierFrom, DFGConnection link); + void addDependencyConnection(SymbolNode& identifierTo, SymbolNode& identifierFrom); + bool isConnected(const SymbolPacked& identifierTo, const SymbolPacked& identifierFrom); + + void print(std::ostringstream& output) const; + + private: + typedef unsigned int EdgeId; + std::vector> __edges; + std::multimap __outEdges; + std::vector __data; + std::multimap __tags; + std::multimap __dependencies; + + unsigned int __countAnonymousSymbols=0; + ClaspLayer* __clasp; + }; +}} + +#endif /* DFA_H */ + diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp index 6d5f2ad..1552a18 100644 --- a/cpp/src/ast.cpp +++ b/cpp/src/ast.cpp @@ -1,701 +1,774 @@ #include "ast.h" #include "ExternLayer.h" #include #include #include using namespace std; namespace xreate{ +class ExpressionHints{ +public: + static bool + isStringValueValid(const Expression& e){ + switch (e.__state){ + case Expression::INVALID: + case Expression::VARIANT: + assert(false); + + case Expression::IDENT: + case Expression::STRING: + return true; + + case Expression::NUMBER: + case Expression::BINDING: + return false; + + case Expression::COMPOUND: { + switch (e.op){ + case Operator::CALL: + case Operator::INDEX: + return true; + + default: return false; + } + } + } + + return false; + } + + static bool + isDoubleValueValid(const Expression& e){ + switch (e.__state){ + case Expression::NUMBER: + return true; + + case Expression::INVALID: + case Expression::VARIANT: + assert(false); + + case Expression::IDENT: + case Expression::STRING: + case Expression::COMPOUND: + case Expression::BINDING: + return false; + } + + return false; + } +}; class TypesResolver { private: const AST* ast; std::map scope; std::map signatures; ExpandedType expandType(const TypeAnnotation &t, const std::vector &args = std::vector()){ return TypesResolver(ast, scope, signatures)(t, args); } std::vector expandOperands(const std::vector& operands) { std::vector pack; pack.reserve(operands.size()); std::transform(operands.begin(), operands.end(), std::inserter(pack, pack.end()), [this](const TypeAnnotation& t){ return expandType(t); }); return pack; } public: TypesResolver(const AST* root, const std::map& scopeOuter = std::map(), std::map signaturesOuter = std::map()) : ast(root), scope(scopeOuter), signatures(signaturesOuter) { } ExpandedType operator()(const TypeAnnotation &t, const std::vector &args = std::vector()) { //assert(args.size() == t.bindings.size()); // invalid number of arguments for (size_t i=0; i elTy = expandType(t.__operands.at(0)); return ExpandedType(TypeAnnotation(tag_array, elTy, t.__size)); } case TypeOperator::STRUCT: { assert(t.__operands.size()); std::vector&& pack = expandOperands(t.__operands); auto tnew = TypeAnnotation(TypeOperator::STRUCT, move(pack)); tnew.fields = t.fields; return ExpandedType(move(tnew)); }; case TypeOperator::CALL: { std::string alias = t.__valueCustom; //find in local scope: TypeAnnotation ty; if (scope.count(alias)) { ty = scope.at(alias); } else if (ast->__indexTypeAliases.count(alias)){ ty = ast->__indexTypeAliases.at(alias); } else { assert(false && "Undefined or external type"); } std::vector&& operands = expandOperands(t.__operands); TypeAnnotation signature(TypeOperator::CALL, move(operands)); signature.__valueCustom = alias; if (signatures.count(signature)) { auto link = TypeAnnotation(TypeOperator::LINK, {}); link.conjuctionId = signatures.at(signature); return ExpandedType(move(link)); } int cid = signatures.size(); signatures[signature] = cid; TypeAnnotation tyResult = expandType(ty, operands); tyResult.conjuctionId = cid; return ExpandedType(move(tyResult)); }; case TypeOperator::CUSTOM: { std::string alias = t.__valueCustom; /* if (signatures.count(alias)) { return ExpandedType(TypeAnnotation(TypeOperator::LINK, {t})); } signatures[alias].emplace(t); */ //find in local scope: if (scope.count(alias)) { return expandType(scope.at(alias)); } // find in general scope: if(ast->__indexTypeAliases.count(alias)) { return expandType(ast->__indexTypeAliases.at(t.__valueCustom)); } //if type is unknown keep it as is. return ExpandedType(TypeAnnotation(t)); }; case TypeOperator::ACCESS: { std::string alias = t.__valueCustom; ExpandedType tyAlias= ExpandedType(TypeAnnotation()); //find in local scope: if (scope.count(alias)) { tyAlias = expandType(scope.at(alias)); //find in global scope: } else if((ast->__indexTypeAliases.count(alias))) { tyAlias = expandType(ast->__indexTypeAliases.at(alias)); } else { assert(false && "Undefined or external type"); } assert(tyAlias->__operator == TypeOperator::STRUCT); for (const string& field: t.fields){ auto fieldIt = std::find(tyAlias->fields.begin(), tyAlias->fields.end(), field); assert(fieldIt != tyAlias->fields.end() && "unknown field"); int fieldId = fieldIt - tyAlias->fields.begin(); tyAlias = expandType(tyAlias->__operands.at(fieldId)); } return tyAlias; } case TypeOperator::TUPLE: { assert(t.__operands.size()); std::vector pack; pack.reserve(t.__operands.size()); std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(pack, pack.end()), [this](const TypeAnnotation& t){ return expandType(t); }); return ExpandedType(TypeAnnotation(TypeOperator::TUPLE, move(pack))); } case TypeOperator::VARIANT: { return ExpandedType(TypeAnnotation(t)); } case TypeOperator::NONE: { return ExpandedType(TypeAnnotation(t)); } default: assert(false); } assert(false); return ExpandedType(TypeAnnotation()); } }; TypeAnnotation::TypeAnnotation() { } TypeAnnotation::TypeAnnotation(const Atom &typ) : __value(typ.get()) { ; } TypeAnnotation::TypeAnnotation (TypePrimitive typ) : __value(typ) {} TypeAnnotation::TypeAnnotation(TypeOperator op, std::initializer_list operands) : __operator(op), __operands(operands) { } TypeAnnotation::TypeAnnotation (TypeOperator op, std::vector&& operands) : __operator(op), __operands(operands) {} TypeAnnotation::TypeAnnotation (llvm_array_tag, TypeAnnotation typ, int size) :TypeAnnotation(TypeOperator::ARRAY, {typ}) { __size=size; } bool TypeAnnotation::operator< (const TypeAnnotation& t) const{ if (__operator != t.__operator) return __operator < t.__operator; if (__operator == TypeOperator::NONE) return __value < t.__value; if (__operator == TypeOperator::CALL || __operator == TypeOperator::CUSTOM || __operator == TypeOperator::ACCESS){ if (__valueCustom != t.__valueCustom) return __valueCustom < t.__valueCustom; } return __operands < t.__operands; } /* TypeAnnotation (struct_tag, std::initializer_list) {} */ void TypeAnnotation::addBindings(std::vector>&& params) { bindings.reserve(bindings.size() + params.size()); std::transform(params.begin(), params.end(), std::inserter(bindings, bindings.end()), [](const Atom& ident){return ident.get(); }); } void TypeAnnotation::addFields(std::vector>&& listFields) { fields.reserve(fields.size() + listFields.size()); std::transform(listFields.begin(), listFields.end(), std::inserter(fields, fields.end()), [](const Atom& ident){return ident.get(); }); } Expression::Expression(const Atom& number) : __state(NUMBER), op(Operator::NONE), __valueD(number.get()) { } Expression::Expression(const Atom& a) : __state(STRING), op(Operator::NONE), __valueS(a.get()) { } Expression::Expression(const Atom &ident) : __state(IDENT), op(Operator::NONE), __valueS(ident.get()) { } Expression::Expression(const Operator &oprt, std::initializer_list params) : __state(COMPOUND), op(oprt) { if (op == Operator::CALL) { assert(params.size() > 0); Expression arg = *params.begin(); assert(arg.__state == Expression::IDENT); __valueS = std::move(arg.__valueS); operands.insert(operands.end(), params.begin()+1, params.end()); return; } operands.insert(operands.end(), params.begin(), params.end()); } void Expression::setOp(Operator oprt) { op = oprt; switch (op) { case Operator::NONE: __state = INVALID; break; default: __state = COMPOUND; break; } } void Expression::addArg(Expression &&arg) { operands.push_back(arg); } void Expression::addBindings(std::initializer_list> params) { addBindings(params.begin(), params.end()); } void -Expression::bindType(TypeAnnotation&& t) +Expression::bindType(TypeAnnotation t) { - type = t; + type = move(t); } void Expression::addBlock(ManagedScpPtr scope) { blocks.push_back(scope.operator ->()); } const std::vector& Expression::getOperands() const { return operands; } double Expression::getValueDouble() const { return __valueD; } const std::string& Expression::getValueString() const { return __valueS; } void Expression::setValue(const Atom&& v){ __valueS = v.get(); } void Expression::setValueDouble(double value){ __valueD = value; } bool Expression::isValid() const{ return (__state != INVALID); } +bool +Expression::isDefined() const{ + return (__state != BINDING); +} + Expression::Expression() : __state(INVALID), op(Operator::NONE) {} +bool +Expression::operator==(const Expression& other) const{ + assert(!this->blocks.size()); + assert(!other.blocks.size()); + + if (this->__state != other.__state) return false; + + if (ExpressionHints::isStringValueValid(*this)){ + if (this->__valueS != other.__valueS) return false; + } + + if (ExpressionHints::isDoubleValueValid(*this)){ + if (this->__valueD != other.__valueD) return false; + } + + if (this->__state != Expression::COMPOUND){ + return true; + } + + if (this->operands.size() != other.operands.size()){ + return false; + } + + for (size_t i=0; ioperands.size(); ++i){ + if (!(this->operands[i]==other.operands[i])) return false; + } + + return true; +} + AST::AST() { } void AST::addInterfaceData(const ASTInterface& interface, Expression&& data ) { __interfacesData.emplace(interface, move(data)); } void AST::addDFAData(Expression &&data) { __dfadata.push_back(data); } void AST::addExternData(ExternData &&data) { __externdata.insert(__externdata.end(), data.entries.begin(), data.entries.end()); } void AST::add(Function* f) { __functions.push_back(f); __indexFunctions.emplace(f->getName(), __functions.size()-1); } void AST::add(MetaRuleAbstract *r) { __rules.push_back(r); } void -AST::add(TypeAnnotation&& t, Atom&& alias){ +AST::add(TypeAnnotation t, Atom alias){ if (t.__operator == TypeOperator::VARIANT){ for (int i=0, size=t.fields.size(); i< size; ++i){ __dictVariants.emplace(t.fields[i], make_pair(t, i)); } } - __indexTypeAliases.emplace(alias.get(), t); + __indexTypeAliases.emplace(alias.get(), move(t)); } ManagedScpPtr AST::add(CodeScope* scope) { this->__scopes.push_back(scope); return ManagedScpPtr(this->__scopes.size()-1, &this->__scopes); } std::string AST::getModuleName() { const std::string name = "moduleTest"; return name; } ManagedPtr AST::findFunction(const std::string& name) { - int count = __indexFunctions.count(name); + int count = __indexFunctions.count(name); if (!count) { return ManagedFnPtr::Invalid(); } assert(count ==1); auto range = __indexFunctions.equal_range(name); return ManagedPtr(range.first->second, &this->__functions); } std::list AST::getAllFunctions() const{ const size_t size = __functions.size(); std::list result; for (size_t i=0; i__functions)); } return result; } //TASK select default specializations std::list AST::getFunctionVariants(const std::string& name) const{ auto functions = __indexFunctions.equal_range(name); std::list result; std::transform(functions.first, functions.second, inserter(result, result.end()), [this](auto f){return ManagedFnPtr(f.second, &this->__functions);}); return result; } template<> ManagedPtr AST::begin() {return ManagedPtr(0, &this->__functions);} template<> ManagedPtr AST::begin() {return ManagedPtr(0, &this->__scopes);} template<> ManagedPtr AST::begin() {return ManagedPtr(0, &this->__rules);} Expanded AST::expandType(const TypeAnnotation &t) const { return TypesResolver(this)(t); } Expanded AST::findType(const std::string& name){ // find in general scope: if(__indexTypeAliases.count(name)) return expandType(__indexTypeAliases.at(name)); //if type is unknown keep it as is. TypeAnnotation t(TypeOperator::CUSTOM, {}); t.__valueCustom = name; return ExpandedType(move(t)); } void AST::recognizeVariantIdentifier(Expression& identifier){ + +// TODO get rid of findSymbol. Determine symbol while AST parsing. Re-find symbols not found while first pass. +// * move to codescope +// * use findSymbol to find Symbol +// * register var as alias to +// * ident __doubleValue holds VID of an alias + assert(identifier.__state == Expression::IDENT); std::string name = identifier.getValueString(); if (__dictVariants.count(name)){ auto record = __dictVariants.at(name); const TypeAnnotation& typ = record.first; identifier.__state = Expression::VARIANT; identifier.setValueDouble(record.second); identifier.type = typ; } } Function::Function(const Atom& name) : __entry(new CodeScope(0)) { __name = name.get(); } void Function::addTag(Expression&& tag, const TagModifier mod) { - __tags.emplace_back(tag, mod); + string name = tag.getValueString(); + __tags.emplace(move(name), move(tag)); } -const std::vector& -Function::getAnnotations() const +const std::map& +Function::getTags() const { return __tags; } CodeScope* Function::getEntryScope() const { return __entry; } void -CodeScope::addArg(Atom && name, TypeAnnotation&& typ) -{ - registerVar(std::move(const_cast(name.get())), std::move(typ)); - __args.push_back(name.get()); -} - - ; - -void -Function::addArg(Atom && name, TypeAnnotation&& typ) +Function::addBinding(Atom && name, Expression&& argument) { - __entry->addArg(move(name), move(typ)); + __entry->addBinding(move(name), move(argument)); } void Function::setReturnType(const TypeAnnotation &rtyp) { - __entry->__definitions[0] = rtyp; + __entry->__declarations[0].type = rtyp; } const std::string& Function::getName() const { return __name; } +Symbol +CodeScope::registerIdentifier(Atom &&name) +{ + __identifiers.emplace(name.get(), ++__vCounter); + return {__vCounter, this}; +} + +void +CodeScope::addBinding(Atom && name, Expression&& argument) +{ + __bindings.push_back(name.get()); + Symbol binding = registerIdentifier(move(name)); + argument.__state = Expression::BINDING; + __declarations[binding.identifier] = move(argument); +} + +void +CodeScope::addDeclaration(Atom && name, Expression&& body) +{ + Symbol s = registerIdentifier(move(name)); + __declarations[s.identifier] = move(body); +} + CodeScope::CodeScope(CodeScope* parent) :__parent(parent) {} CodeScope::~CodeScope() {} -VID -CodeScope::registerVar(std::string&& name, TypeAnnotation &&typ) -{ - __vartable[name] = ++__vCounter; - __definitions[__vCounter] = typ; - return __vCounter; -} -void -CodeScope::addDeclaration(const Atom &&name, TypeAnnotation &&typ, Expression&& body) -{ - VID id = registerVar(std::move(const_cast(name.get())), move(typ)); - __declarations[id] = body; -} + void CodeScope::setBody(const Expression &body) { __body = body; } -TypeAnnotation& -CodeScope::findDefinition(const Symbol& symbol) -{ - CodeScope* self = symbol.scope; - assert(self->__definitions.count(symbol.identifier)); - return self->__definitions[symbol.identifier]; -} - -//TODO get rid of findSymbol. Determine symbol while AST parsing. Refind symbols not found while first pass. Symbol CodeScope::findSymbol(const std::string &name) { - //search var in current block - if (__vartable.count(name)) + //search identifier in the current block + if (__identifiers.count(name)) { - VID vId = __vartable.at(name); + VID vId = __identifiers.at(name); Symbol result{vId, this}; return result; } - //search in parent scope + //search in the parent scope if (__parent) { return __parent->findSymbol(name); } //exception: Ident not found std::cout << "Unknown symbol: "<< name << std::endl; assert(false && "Symbol not found"); } -bool -CodeScope:: hasDeclaration(const Symbol& symbol) -{ - CodeScope* self = symbol.scope; - return (self->__declarations.count(symbol.identifier)); -} - const Expression& CodeScope::findDeclaration(const Symbol& symbol) { CodeScope* self = symbol.scope; - - if (! self->__declarations.count(symbol.identifier)) - { - // no declaration exists - assert(false); - } - return self->__declarations[symbol.identifier]; } void RuleArguments::add(const Atom &arg, DomainAnnotation typ) { emplace_back(arg.get(), typ); } void RuleGuards::add(Expression&& e) { push_back(e); } MetaRuleAbstract:: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards) : __args(std::move(args)), __guards(std::move(guards)) {} MetaRuleAbstract::~MetaRuleAbstract(){} RuleWarning:: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message) : MetaRuleAbstract(std::move(args), std::move(guards)), __message(message.get()), __condition(condition) {} RuleWarning::~RuleWarning(){} void RuleWarning::compile(ClaspLayer& layer) { //TODO restore addRuleWarning //layer.addRuleWarning(*this); } bool operator< (const Symbol& s1, const Symbol& s2) { return (s1.scope < s2.scope) || (s1.scope==s2.scope && s1.identifier #include #include #include #include #include #include -#include "attachments.h" #include "utils.h" #include -namespace llvm{ +namespace llvm { class Value; } namespace xreate { -struct String_t{}; -struct Identifier_t {}; -struct Number_t {}; -struct Type_t {}; + struct String_t { + }; -template -class Atom {}; + struct Identifier_t { + }; -//DEBT hold for all atoms/identifiers Parser::Token data, like line:col position -template<> class Atom -{ -public: - Atom(const std::wstring& value) - { - char buffer[32]; - wcstombs(buffer, value.c_str(), 32); + struct Number_t { + }; - __value = buffer; - } - Atom(std::string && name): __value(name) {} + struct Type_t { + }; - const std::string& get() const{return __value; } -private: - std::string __value; -}; + template + class Atom { + }; -template<> class Atom -{ -public: - Atom(wchar_t* value) - { - __value = wcstol(value, 0, 10); - } + //DEBT hold for all atoms/identifiers Parser::Token data, like line:col position - Atom(int value) - : __value(value) - {} - double get()const {return __value; } -private: - double __value; -}; - -template<> class Atom -{ -public: - Atom(const std::wstring& value){ - assert(value.size()); - __value = std::string(++value.begin(), --value.end()); - } + template<> class Atom { + public: - const std::string& get() const {return __value; } + Atom(const std::wstring& value) { + char buffer[32]; + wcstombs(buffer, value.c_str(), 32); -private: - std::string __value; -}; + __value = buffer; + } -enum class TypePrimitive {Bool, Int, Float, Num, String, I32, I8}; + Atom(std::string && name) : __value(name) { + } -template<> class Atom -{ -public: - Atom(wchar_t* value) - { - char buffer_[32]; - wcstombs(buffer_, value, 32); - std::string buffer(buffer_); - - if (buffer=="bool"){ - __value = TypePrimitive ::Bool; - } else if (buffer=="int") { - __value = TypePrimitive::Int; - } else if (buffer=="float") { - __value = TypePrimitive::Float; - } else if (buffer=="num") { - __value = TypePrimitive::Num; - } else if (buffer=="string") { - __value = TypePrimitive::String; + const std::string& get() const { + return __value; } - } + private: + std::string __value; + }; - Atom() - { - } + template<> class Atom { + public: - TypePrimitive get() const - { - return __value; - } + Atom(wchar_t* value) { + __value = wcstol(value, 0, 10); + } -private: - TypePrimitive __value; -}; + Atom(int value) + : __value(value) { + } -typedef Atom TypeAtom; + double get()const { + return __value; + } + private: + double __value; + }; + template<> class Atom { + public: + + Atom(const std::wstring& value) { + assert(value.size()); + __value = std::string(++value.begin(), --value.end()); + } -enum class TypeOperator{NONE, CALL, CUSTOM, VARIANT, ARRAY, TUPLE, STRUCT, ACCESS, LINK}; -struct llvm_array_tag {}; struct struct_tag{}; + const std::string& get() const { + return __value; + } + + private: + std::string __value; + }; + + enum class TypePrimitive { + Bool, Num, Int, I32, I8, Float, String, + }; + + template<> class Atom { + public: + + Atom(wchar_t* value) { + char buffer_[32]; + wcstombs(buffer_, value, 32); + std::string buffer(buffer_); + + if (buffer == "bool") { + __value = TypePrimitive::Bool; + } else if (buffer == "num") { + __value = TypePrimitive::Num; + } else if (buffer == "int") { + __value = TypePrimitive::Int; + } else if (buffer == "i8") { + __value = TypePrimitive::I8; + } else if (buffer == "i32") { + __value = TypePrimitive::I32; + } else if (buffer == "float") { + __value = TypePrimitive::Float; + + } else if (buffer == "string") { + __value = TypePrimitive::String; + } + } + + Atom() { + } + + TypePrimitive get() const { + return __value; + } + + private: + TypePrimitive __value; + }; + + typedef Atom TypeAtom; + + enum class TypeOperator { + NONE, CALL, CUSTOM, VARIANT, ARRAY, TUPLE, STRUCT, ACCESS, LINK + }; + + struct llvm_array_tag { + }; + + struct struct_tag { + }; const llvm_array_tag tag_array = llvm_array_tag(); const struct_tag tag_struct = struct_tag(); -class TypeAnnotation -{ -public: - TypeAnnotation(); - TypeAnnotation (const Atom& typ); - TypeAnnotation (TypePrimitive typ); - TypeAnnotation (llvm_array_tag, TypeAnnotation typ, int size); - - TypeAnnotation (TypeOperator op, std::initializer_list operands); - TypeAnnotation (TypeOperator op, std::vector&& operands); - void addBindings(std::vector>&& params); - void addFields(std::vector>&& listFields); - bool operator< (const TypeAnnotation& t) const; - // TypeAnnotation (struct_tag, std::initializer_list); - - - TypeOperator __operator = TypeOperator::NONE; - - std::vector __operands; - TypePrimitive __value; - std::string __valueCustom; - int conjuctionId=-1; //conjunction point id (relevant for recursive types) - - uint64_t __size = 0; - std::vector fields; - std::vector bindings; -private: -}; - -enum class Operator -{ -ADD, SUB, MUL, DIV, EQU, LSS, GTR, NEG, LIST, LIST_RANGE, LIST_NAMED, CALL, NONE, IMPL/* implication */, MAP, FOLD, LOOP_CONTEXT, INDEX, IF, SWITCH, SWITCH_ADHOC, CASE, CASE_DEFAULT, LOGIC_AND, ADHOC, CONTEXT_RULE, SEQUENCE -}; - -class Function; -class AST; -class CodeScope; -class MetaRuleAbstract; - -template -struct ManagedPtr -{ - static ManagedPtr Invalid(){ - return ManagedPtr(); - } - ManagedPtr(): __storage(0) {} + class TypeAnnotation { + public: + TypeAnnotation(); + TypeAnnotation(const Atom& typ); + TypeAnnotation(TypePrimitive typ); + TypeAnnotation(llvm_array_tag, TypeAnnotation typ, int size); - ManagedPtr(unsigned int id, const std::vector* storage) - : __id(id), __storage(storage) - {} + TypeAnnotation(TypeOperator op, std::initializer_list operands); + TypeAnnotation(TypeOperator op, std::vector&& operands); + void addBindings(std::vector>&& params); + void addFields(std::vector>&& listFields); + bool operator<(const TypeAnnotation& t) const; + // TypeAnnotation (struct_tag, std::initializer_list); - Target& - operator*() const - { - assert(isValid() && "Invalid Ptr"); - return *__storage->at(__id); - } - void operator=(const ManagedPtr& other) - { - __id = other.__id; - __storage = other.__storage; - } + TypeOperator __operator = TypeOperator::NONE; - bool - operator == (const ManagedPtr& other) - { - return isValid() && (__id == other.__id); - } + std::vector __operands; + TypePrimitive __value; + std::string __valueCustom; + int conjuctionId = -1; //conjunction point id (relevant for recursive types) - Target* - operator->() const noexcept - { - assert(isValid() && "Invalid Ptr"); - return __storage->at(__id); - } + uint64_t __size = 0; + std::vector fields; + std::vector bindings; + private: + }; - inline bool isValid() const - { - return (__storage) && (0 <= __id) && (__id < __storage->size()); - } + enum class Operator { + ADD, SUB, MUL, DIV, EQU, NE, NEG, LSS, LSE, GTR, GTE, LIST, LIST_RANGE, LIST_NAMED, CALL, NONE, IMPL/* implication */, MAP, FOLD, FOLD_INF, LOOP_CONTEXT, INDEX, IF, SWITCH, SWITCH_ADHOC, CASE, CASE_DEFAULT, LOGIC_AND, ADHOC, CONTEXT_RULE, SEQUENCE + }; - inline operator bool() const { - return isValid(); - } + class Function; + class AST; + class CodeScope; + class MetaRuleAbstract; - ManagedPtr& operator++() - { - ++__id; - return *this; - } + template + struct ManagedPtr { - inline unsigned int id() const - { - return __id; - } + static ManagedPtr Invalid() { + return ManagedPtr(); + } -private: - unsigned int __id =0; - const std::vector * __storage=0; -}; - -typedef ManagedPtr ManagedFnPtr; -typedef ManagedPtr ManagedScpPtr; -typedef ManagedPtr ManagedRulePtr; -const ManagedScpPtr NO_SCOPE = ManagedScpPtr(UINT_MAX, 0); - -struct Expression -{ - friend class CodeScope; - friend class ClaspLayer; - friend class CFGPass; - - Expression(const Operator &oprt, std::initializer_list params); - Expression(const Atom& ident); - Expression(const Atom& number); - Expression(const Atom& a); - Expression(); - - void setOp(Operator oprt); - void addArg(Expression&& arg); - void addBindings(std::initializer_list> params); - void bindType(TypeAnnotation&& t); + ManagedPtr() : __storage(0) { + } - template - void addBindings(InputIt paramsBegin, InputIt paramsEnd); - - void addBlock(ManagedScpPtr scope); - - const std::vector& getOperands() const; - double getValueDouble() const; - void setValueDouble(double value); - const std::string& getValueString() const; - void setValue(const Atom&& v); - bool isValid() const; - - enum {INVALID, COMPOUND, IDENT, NUMBER, STRING, VARIANT} __state = INVALID; - Operator op; - std::vector bindings; - std::map __indexBindings; - std::vector operands; - TypeAnnotation type; - - std::map tags; - std::list blocks; -private: - std::string __valueS; - double __valueD; - - -}; - -template -void Expression::addBindings(InputIt paramsBegin, InputIt paramsEnd) { - size_t index = bindings.size(); - - std::transform(paramsBegin, paramsEnd, std::inserter(bindings, bindings.end()), - [&index, this] (const Atom atom){ - std::string key = atom.get(); - this->__indexBindings[key] = index++; - return key; - }); -} + ManagedPtr(unsigned int id, const std::vector* storage) + : __id(id), __storage(storage) { + } + + Target& + operator*() const { + assert(isValid() && "Invalid Ptr"); + return *__storage->at(__id); + } + + void operator=(const ManagedPtr& other) { + __id = other.__id; + __storage = other.__storage; + } + + bool + operator==(const ManagedPtr& other) { + return isValid() && (__id == other.__id); + } -typedef std::list ExpressionList; -enum class TagModifier -{NONE, ASSERT, REQUIRE}; + Target* + operator->() const noexcept { + assert(isValid() && "Invalid Ptr"); + return __storage->at(__id); + } + + inline bool isValid() const { + return (__storage) && (0 <= __id) && (__id < __storage->size()); + } + + inline operator bool() const { + return isValid(); + } -enum class DomainAnnotation -{FUNCTION, VARIABLE}; + ManagedPtr& operator++() { + ++__id; + return *this; + } + + inline unsigned int id() const { + return __id; + } -class RuleArguments: public std::vector> -{ -public: - void add(const Atom& name, DomainAnnotation typ); -}; + private: + unsigned int __id = 0; + const std::vector * __storage = 0; + }; + + typedef ManagedPtr ManagedFnPtr; + typedef ManagedPtr ManagedScpPtr; + typedef ManagedPtr ManagedRulePtr; + const ManagedScpPtr NO_SCOPE = ManagedScpPtr(UINT_MAX, 0); + + //To update ExpressionHints in case of any changes + struct Expression { + friend class CodeScope; + friend class ClaspLayer; + friend class CFAPass; + friend class ExpressionHints; + + Expression(const Operator &oprt, std::initializer_list params); + Expression(const Atom& ident); + Expression(const Atom& number); + Expression(const Atom& a); + Expression(); + + void setOp(Operator oprt); + void addArg(Expression&& arg); + void addBindings(std::initializer_list> params); + void bindType(TypeAnnotation t); + + template + void addBindings(InputIt paramsBegin, InputIt paramsEnd); + + void addBlock(ManagedScpPtr scope); + + const std::vector& getOperands() const; + double getValueDouble() const; + void setValueDouble(double value); + const std::string& getValueString() const; + void setValue(const Atom&& v); + bool isValid() const; + bool isDefined() const; + + + bool operator==(const Expression& other) const; + + enum { + INVALID, COMPOUND, IDENT, NUMBER, STRING, VARIANT, BINDING + } __state = INVALID; + Operator op; + std::vector bindings; + std::map __indexBindings; + std::vector operands; + TypeAnnotation type; + + mutable std::map tags; + mutable Attachments tagsInternal; + std::list blocks; + + private: + std::string __valueS; + double __valueD; + }; + + template + void Expression::addBindings(InputIt paramsBegin, InputIt paramsEnd) { + size_t index = bindings.size(); + + std::transform(paramsBegin, paramsEnd, std::inserter(bindings, bindings.end()), + [&index, this] (const Atom atom) { + std::string key = atom.get(); + this->__indexBindings[key] = index++; + return key; + }); + } -class RuleGuards: public std::vector -{ -public: - void add(Expression&& e); -}; + typedef std::list ExpressionList; + enum class TagModifier { + NONE, ASSERT, REQUIRE + }; -class ClaspLayer; -class LLVMLayer; + enum class DomainAnnotation { + FUNCTION, VARIABLE + }; + class RuleArguments : public std::vector> + { + public: + void add(const Atom& name, DomainAnnotation typ); + }; -class MetaRuleAbstract -{ -public: - MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards); - virtual ~MetaRuleAbstract(); - virtual void compile(ClaspLayer& layer) =0; -protected: - RuleArguments __args; - RuleGuards __guards; -}; + class RuleGuards : public std::vector { + public: + void add(Expression&& e); + }; -class RuleWarning: public MetaRuleAbstract -{ - friend class ClaspLayer; -public: - RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message); - virtual void compile(ClaspLayer& layer); - ~RuleWarning(); -private: - std::string __message; - Expression __condition; -}; + class ClaspLayer; + class LLVMLayer; -typedef unsigned int VID; + class MetaRuleAbstract { + public: + MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards); + virtual ~MetaRuleAbstract(); + virtual void compile(ClaspLayer& layer) = 0; + protected: + RuleArguments __args; + RuleGuards __guards; + }; + class RuleWarning : public MetaRuleAbstract { + friend class ClaspLayer; + public: + RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message); + virtual void compile(ClaspLayer& layer); + ~RuleWarning(); + private: + std::string __message; + Expression __condition; + }; -/* -class Expression: ExpressionAbstract -{ - friend class CFGPass; + typedef unsigned int VID; -public: - llvm::Value* compile(LLVMLayer& l, Function* f, std::string* hintRetVar=0) const; -}; -*/ + /* + class Expression: ExpressionAbstract + { + friend class CFGPass; -typedef std::pair VariableDefinition; -typedef std::pair VariableDeclaration; + public: + llvm::Value* compile(LLVMLayer& l, Function* f, std::string* hintRetVar=0) const; + }; + */ -typedef std::pair Tag; -struct Symbol -{ - VID identifier; - CodeScope * scope; -}; + typedef std::pair Tag; -struct SymbolTags_t{}; + struct Symbol { + VID identifier; + CodeScope * scope; + }; -template<> -struct AttachmentsDict { - typedef std::map Data; - static const unsigned int key = 2; -}; + bool operator<(const Symbol& s1, const Symbol& s2); + bool operator==(const Symbol& s1, const Symbol& s2); -bool operator< (const Symbol& s1, const Symbol& s2); -bool operator== (const Symbol& s1, const Symbol& s2); + class CodeScope { + friend class Function; + friend class PassManager; -class CodeScope -{ - friend class Function; - friend class PassManager; + public: + CodeScope(CodeScope* parent = 0); + void setBody(const Expression& body); + void addDeclaration(Atom && name, Expression&& body); + void addBinding(Atom && name, Expression&& argument); + Symbol findSymbol(const std::string &name); + static const Expression& findDeclaration(const Symbol& symbol); -public: - CodeScope(CodeScope* parent=0); - void setBody(const Expression& body); - void addDeclaration(const Atom &&name, TypeAnnotation &&typ, Expression&& body); + ~CodeScope(); - void addArg(Atom && name, TypeAnnotation&& typ); + std::vector __bindings; + Expression __body; //TODO move __body to __declarations[0] + std::map __identifiers; + /** + * definition of return type has variable index Zero(0) + */ + //TODO move __definitions to SymbolsAttachments data + std::unordered_map __declarations; + std::vector tags; + std::vector contextRules; + + private: + VID __vCounter = 0; + CodeScope* __parent; + + Symbol registerIdentifier(Atom && name); + }; - //TODO exclude forceCompile partz - Symbol findSymbol(const std::string &name); - static const Expression& findDeclaration(const Symbol& symbol); - static TypeAnnotation& findDefinition(const Symbol& symbol); - static bool hasDeclaration(const Symbol& symbol); + class Function { + friend class Expression; + friend class CodeScope; + friend class AST; - ~CodeScope(); + public: + Function(const Atom& name); - std::vector __args; - Expression __body; //TODO move __body to __declarations[0] + void addBinding(Atom && name, Expression&& argument); + void addTag(Expression&& tag, const TagModifier mod); - SymbolAttachments attachments; - std::map __vartable; - /** - * definition of return type has variable index Zero(0) - */ - //TODO move __definitions to SymbolsAttachments data - std::unordered_map __definitions; - std::unordered_map __declarations; - std::vector tags; - std::vector contextRules; -protected: - VID __vCounter=1; - CodeScope* __parent; - std::list __storage; - VID registerVar(std::string&& name, TypeAnnotation &&typ); -}; + void setReturnType(const TypeAnnotation& rtyp); -class Function -{ - friend class Expression; - friend class CodeScope; - friend class AST; + const std::string& getName() const; + const std::map& getTags() const; + CodeScope* getEntryScope() const; + CodeScope* __entry; + std::string __name; + bool isPrefunction = false; //SECTIONTAG adhoc Function::isPrefunction flag -public: - Function(const Atom& name); + Expression guardContext; + private: - void addArg(Atom && name, TypeAnnotation&& typ); - void addTag(Expression&& tag, const TagModifier mod); + std::map __tags; + }; - void setReturnType(const TypeAnnotation& rtyp); - const std::string& getName() const; - const std::vector& getAnnotations() const; - CodeScope* getEntryScope() const; - CodeScope* __entry; - std::string __name; - bool isPrefunction = false; //SECTIONTAG adhoc Function::isPrefunction flag + class ExternData; - Expression guardContext; -private: + struct ExternEntry { + std::string package; + std::vector headers; + }; - std::vector __tags; -}; + typedef Expanded ExpandedType; + enum ASTInterface { + CFA, DFA, Extern, Adhoc + }; -class ExternData; + struct FunctionSpecialization { + std::string guard; + size_t id; + }; -struct ExternEntry { - std::string package; - std::vector headers; -}; + struct FunctionSpecializationQuery { + std::unordered_set context; + }; -typedef Expanded ExpandedType; + template<> + struct AttachmentsStorage { -enum ASTInterface { - CFA, DFA, Extern, Adhoc -}; + static Attachments* + get(const Symbol& s) { + return &s.scope->findDeclaration(s).tagsInternal; + } + }; -struct FunctionSpecialization { - std::string guard; - size_t id; -}; + template<> + struct AttachmentsStorage { -struct FunctionSpecializationQuery { - std::unordered_set context; -}; + static Attachments* + get(const Expression& e) { + return &e.tagsInternal; + } + }; -class AST -{ -public: - AST(); + class AST { + public: + AST(); - //TASK extern and DFA interfaces move into addInterfaceData + //TASK extern and DFA interfaces move into addInterfaceData /** * DFA Interface */ - void addDFAData(Expression&& data); + void addDFAData(Expression&& data); /** * Extern Interface */ - void addExternData(ExternData&& data); + void addExternData(ExternData&& data); - void addInterfaceData(const ASTInterface& interface, Expression&& data ); - void add(Function* f); + void addInterfaceData(const ASTInterface& interface, Expression&& data); + void add(Function* f); - void add(MetaRuleAbstract* r); - ManagedScpPtr add(CodeScope* scope); + void add(MetaRuleAbstract* r); + ManagedScpPtr add(CodeScope* scope); - std::string getModuleName(); - ManagedPtr findFunction(const std::string& name); + std::string getModuleName(); + ManagedPtr findFunction(const std::string& name); - typedef std::multimap FUNCTIONS_REGISTRY; - std::list getAllFunctions() const; - std::list getFunctionVariants(const std::string& name) const; + typedef std::multimap FUNCTIONS_REGISTRY; + std::list getAllFunctions() const; + std::list getFunctionVariants(const std::string& name) const; - template - ManagedPtr begin(); + template + ManagedPtr begin(); - std::vector __externdata; - std::list __dfadata; //TODO move to more appropriate place - std::list __rawImports; //TODO move to more appropriate place - std::multimap __interfacesData; //TODO CFA data here. + std::vector __externdata; + std::list __dfadata; //TODO move to more appropriate place + std::list __rawImports; //TODO move to more appropriate place + std::multimap __interfacesData; //TODO CFA data here. -private: - std::vector __rules; - std::vector __functions; - std::vector __scopes; + private: + std::vector __rules; + std::vector __functions; + std::vector __scopes; - FUNCTIONS_REGISTRY __indexFunctions; + FUNCTIONS_REGISTRY __indexFunctions; - // ***** TYPES SECTION ***** - public: -std::map __indexTypeAliases; -ExpandedType expandType(const TypeAnnotation &t) const; -ExpandedType findType(const std::string& name); -void add(TypeAnnotation&& t, Atom&& alias); -void recognizeVariantIdentifier(Expression& identifier); + // ***** TYPES SECTION ***** + public: + std::map __indexTypeAliases; + ExpandedType expandType(const TypeAnnotation &t) const; + ExpandedType findType(const std::string& name); + void add(TypeAnnotation t, Atom alias); + void recognizeVariantIdentifier(Expression& identifier); - private: -std::map> __dictVariants; -ExpandedType expandType(const TypeAnnotation &t, std::map scope, - const std::vector &args = std::vector()) const; + private: + std::map> __dictVariants; + ExpandedType expandType(const TypeAnnotation &t, std::map scope, + const std::vector &args = std::vector()) const; - // ***** TYPES SECTION END ***** -}; + // ***** TYPES SECTION END ***** + }; template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); } #endif // AST_H diff --git a/cpp/src/attachments.cpp b/cpp/src/attachments.cpp index d8c8af3..83a54d1 100644 --- a/cpp/src/attachments.cpp +++ b/cpp/src/attachments.cpp @@ -1,23 +1,30 @@ // // Created by pgess on 3/15/15. // #include "attachments.h" -#include "ast.h" -void xreate::SymbolAttachments::put(xreate::Symbol const &symbol, unsigned int key, void *data) { - symbol.scope->attachments.__data[key].emplace(symbol.identifier, data); -} +namespace xreate { + void* xreate::Attachments::put(unsigned int key, void *data) { + auto result = __data.emplace(key, data); + + void* ptrOld = nullptr; + if (!result.second){ + ptrOld = result.first->second; + result.first->second = data; + } + + return ptrOld; + } -void *xreate::SymbolAttachments::get(xreate::Symbol const &symbol, unsigned int key, void *def) { - if (symbol.scope->attachments.__data[key].count(symbol.identifier)) - return symbol.scope->attachments.__data[key].at(symbol.identifier); + void *xreate::Attachments::get(unsigned int key) { + assert(__data.count(key)); + return __data.at(key); + } - return def; -} - -bool -xreate::SymbolAttachments::exists(const Symbol& symbol, unsigned int key) -{ - return symbol.scope->attachments.__data.count(key) && symbol.scope->attachments.__data.at(key).count(symbol.identifier); -} + bool + xreate::Attachments::exists(unsigned int key) + { + return __data.count(key)>0; + } +} \ No newline at end of file diff --git a/cpp/src/attachments.h b/cpp/src/attachments.h index 08b8579..a62cd20 100644 --- a/cpp/src/attachments.h +++ b/cpp/src/attachments.h @@ -1,143 +1,124 @@ // // Created by pgess on 3/15/15. // #ifndef _XREATE_ATTACHMENTS_H_ #define _XREATE_ATTACHMENTS_H_ #include #include #include namespace xreate { - //Attachemnt Tags: - struct IsDeclVisited{}; - struct IsImplementationOnTheFly{}; - - //Atachments dictionary + //Attachments dictionary template struct AttachmentsDict { // typedef void Data; + // static const unsigned int key (current unreserved - 5); }; - - template<> - struct AttachmentsDict - { - typedef bool Data; - static const unsigned int key = 0; - }; - - template<> - struct AttachmentsDict + + template + struct AttachmentsStorage { - typedef bool Data; - static const unsigned int key = 3; + //static Attachments* get(const T&); }; + namespace detail { + template + typename std::enable_if::value, void*>::type + __wrap(const Typ& value){ + return value; + } + + template + typename std::enable_if::value, Typ>::type + __unwrap(void* value){ + return reinterpret_cast(value); + } + + template + typename std::enable_if::value, void*>::type + __wrap(const Typ& value){ + Typ* holder = new Typ(value); + return holder; + } + + template + typename std::enable_if::value, Typ&>::type + __unwrap(void* value){ + return *reinterpret_cast(value); + } - class Symbol; - typedef unsigned int VID; - - class AttachmentsImpl - { - friend class SymbolAttachments; - - }; - - //TODO copy function to copy whole data from symbol to symbol: copy(sTo, sFrom); - class SymbolAttachments + template + typename std::enable_if::value, void>::type + __delete(void* value){ + delete reinterpret_cast(value); + } + + template + typename std::enable_if::value, void>::type + __delete(void* value){ + delete reinterpret_cast(value); + } + } + + //TODO copy whole data from symbol to symbol: copy(sTo, sFrom); + class Attachments { public: //TODO add specialization for pointers template using Data = typename AttachmentsDict::Data; - template - using Input = typename std::conditional>::value, Data, Data&&>::type; - - template - static typename std::enable_if>::value>::type - put(const Symbol& symbol, Input data) + template + static void put(const Holder& holder, const Data& data) { const unsigned int key = AttachmentsDict::key; - put(symbol, key, (void*) data); - } + Attachments* self = AttachmentsStorage::get(holder); - template - static typename std::enable_if>::value>::type - put(const Symbol& symbol, Input data) - { - const unsigned int key = AttachmentsDict::key; - Data* holder = new Data(data); - put(symbol, key, (void*) holder); - } - - /* - template - using Tag2 = std::enable_if, Tag>:: - static void put(const Symbol& symbol, typename AttachmentsDict::Data && data) - { - typedef typename AttachmentsDict::Data Typ; - Typ* ptr = new Typ(data); - - AttachmentsImpl::put(symbol, ptr); - } - */ - - template - static typename AttachmentsDict::Data& get(const Symbol& symbol, typename AttachmentsDict::Data&& valueDefault) - { - typedef typename AttachmentsDict::Data Typ; - const unsigned int key = AttachmentsDict::key; - - Typ* def = new Typ(valueDefault); - Typ* result = static_cast (get(symbol, key, def)); - - if (result != def) delete def; //TODO check is there some mem leaks? - return *result; + void* dataWaste = self->put(key, detail::__wrap(data)); + detail::__delete>(dataWaste); } - template - static typename std::enable_if>::value, Data>::type - get(const Symbol& symbol) + template + static Data& get(const Holder& holder) { const unsigned int key = AttachmentsDict::key; - Data result = reinterpret_cast> (get(symbol, key, nullptr)); + Attachments* self = AttachmentsStorage::get(holder); - assert(result != nullptr); // data not found for the symbol - return result; + return detail::__unwrap>(self->get(key)); } - - template - static typename std::enable_if>::value, Data&>::type - get(const Symbol& symbol) + + template + static Data get(const Holder& holder, Data&& dataDefault) { + if (! exists(holder)){ + return dataDefault; + } + const unsigned int key = AttachmentsDict::key; + Attachments* self = AttachmentsStorage::get(holder); - Data* result = reinterpret_cast*> (get(symbol, key, nullptr)); - - assert(result != nullptr); // data not found for the symbol - return *result; + return detail::__unwrap>(self->get(key)); } - template - static bool exists(const Symbol& symbol) + template + static bool exists(const Holder& holder) { const unsigned int key = AttachmentsDict::key; - return exists(symbol, key); + Attachments* self = AttachmentsStorage::get(holder); + return self->exists(key); } private: - typedef std::map Attachment; - std::map __data; - - static void put(const Symbol& symbol, unsigned int key, void* data); - static void* get(const Symbol& symbol, unsigned int key, void *def); - static bool exists(const Symbol& symbol, unsigned int key); + std::map __data; + void* put(unsigned int key, void *data); + void* get(unsigned int key); + bool exists(unsigned int key); }; } #endif //_XREATE_ATTACHMENTS_H_ diff --git a/cpp/src/clasplayer.cpp b/cpp/src/clasplayer.cpp index 21237f6..c1a6b7c 100644 --- a/cpp/src/clasplayer.cpp +++ b/cpp/src/clasplayer.cpp @@ -1,689 +1,274 @@ #include "clasplayer.h" #include #include "utils.h" #include #include #include +#include "analysis/aux.h" +#include "analysis/DominatorsTreeAnalysisProvider.h" +#include "analysis/cfagraph.h" +#include "analysis/dfagraph.h" + using namespace std; //TODO escape identifiers started from upper case symbol namespace xreate { void ClaspLayer::printWarnings(std::ostream& out) { const std::string warningTag = "warning"; auto warningsRange = __model.equal_range(warningTag); for (auto warning=warningsRange.first; warning!= warningsRange.second; ++warning) { unsigned int warningId; - Gringo::Value params; - std::tie(warningId, params) = parse(warning->second); + Gringo::Symbol params; + std::tie(warningId, params) = parse(warning->second); cout << "Warning: " << __warnings.at(warningId) << " "; params.print(out); out< warnings; cout << "Model: " << endl; const string& atomBindVar = Config::get("clasp.bindings.variable"); const string& atomBindFunc = Config::get("clasp.bindings.function"); const string& atomBindScope = Config::get("clasp.bindings.scope"); - for (Gringo::Value atom : model.atoms(Gringo::Model::ATOMS)) { + for (Gringo::Symbol atom : model.atoms(clingo_show_type_atoms)) { atom.print(cout); cout <<" | "<< endl; - if (*atom.name() == atomBindVar || *atom.name() == atomBindFunc || *atom.name() == atomBindScope){ - string name = *std::get<1>(parse(atom)).name(); + string atomName(atom.name().c_str()); + if (atomName == atomBindVar || atomName == atomBindFunc || atomName == atomBindScope){ + string name = std::get<1>(parse(atom)).name().c_str(); __model.emplace(move(name), move(atom)); } - __model.emplace(*atom.name(), move(atom)); + __model.emplace(atomName, move(atom)); } return true; } - list - multiplyLists(list> &&lists) { - typedef list StringList; - assert(lists.size()); - StringList result(*lists.begin()); - lists.pop_front(); - - boost::format concat("%s, %s"); - for (StringList &list: lists) { - StringList::const_iterator end = result.end(); - for (StringList::iterator expr1I = result.begin(); expr1I != end; ++expr1I) { - if (list.size() == 0) continue; - - StringList::const_iterator expr2I = list.begin(); - for (int expr2No = 0, size = list.size() - 1; expr2No < size; ++expr2No, ++expr1I) - result.push_back(str(concat %(*expr1I) %(*expr2I))); - - *expr1I = str(concat %(*expr1I) %(*expr2I)); - } - } - - return result; - } - void - ClaspLayer::setCFAData(CFAGraph &&graph) { - cfagraph = graph; + ClaspLayer::setCFAData(xreate::analysis::CFAGraph* graph) { + dataCFA.reset(graph); } - - void - ClaspLayer::addDFAData(DFAGraph &&graph) - { - dfaData = graph; - std::set symbols; - ostream &cout = __partGeneral; - - cout << endl << "%\t\tStatic analysis: DFA" << endl; - - std::vector>::iterator i1; - std::vector::iterator i2; - - boost::format formatDfaConnection("dfa_connection(%1%, %2%, %3%)."); - boost::format format2Args("(%1%, %2%)"); - for (i1= dfaData.__edges.begin(), i2 = dfaData.__data.begin(); i1!= dfaData.__edges.end(); ++i1, ++i2 ) - { - string edgeName; - switch (*i2) - { - case DFGConnection::OPT: edgeName = "opt"; break; - case DFGConnection::ALIAS: edgeName = "alias"; break; - case DFGConnection::PROTO: edgeName = "proto"; break; - } - - cout << formatDfaConnection - %(format2Args %(i1->first.identifier) %(i1->first.scope)).str() - %(format2Args %(i1->second.identifier) %(i1->second.scope)).str() - %edgeName - << " %" <first) << " - " << getHintForPackedSymbol(i1->second) - <first); - symbols.insert(i1->second); - } - - boost::format formatBind("bind(%1%, %2%)."); - for (const pair& tag: dfaData.__tags) - { - for (string variant: compile(tag.second)) { - cout << (formatBind - % (format2Args %(tag.first.identifier) %(tag.first.scope)) - % (variant)) - << "%" << getHintForPackedSymbol(tag.first) - << endl; - } - - symbols.insert(tag.first); - } - - for (const SymbolPacked& s: symbols) - { - cout << "v(" << format2Args % (s.identifier) % (s.scope) << ")." - << " %" << getHintForPackedSymbol(s) - < tagRaw = compile(tag.first); - assert(tagRaw.size() == 1); - - cout << formatBind - % (function.second) - % (tagRaw.front()) - << endl; - ++counterTags; - } - } - - if (bufFunctionNames.tellp()){ - cout << formatFunction % (bufFunctionNames.str().substr(2)) << std::endl; - } - - if (counterTags == 0) { - cout << "%no functtion tags at all" << endl; - } - - //declare scopes - boost::format formatScope("scope(0..%1%)."); - cout << formatScope % (__registryScopes.size() - 1) << std::endl; - - //show context rules: - for (auto rule: cfagraph.__contextRules) { - cout << ContextRule(rule.second).compile(rule.first) << std::endl; - }; - - //show scope tags: - counterTags = 0; - boost::format formatScopeBind(atomBindingScope + "(%1%, %2%)."); - for (auto entry: cfagraph.__scopeTags) { - ScopePacked scopeId = entry.first; - const Expression& tag = entry.second; - list tagRaw = compile(tag); - assert(tagRaw.size() == 1); - - cout << formatScopeBind % scopeId %(tagRaw.front()) << endl; - ++counterTags; - } - - if (counterTags == 0) { - cout << "%scope tags: no tags at all" << endl; - } - - cout << endl << "%\t\tStatic analysis: CFA" << endl; - - //parent connections - //TEST CFG parent function - boost::format formatFunctionParent("cfa_parent(%1%, function(%2%))."); - for (const auto &relation: cfagraph.__parentFunctionRelations) { - const string& function = cfagraph.__nodesFunction.left.at(relation.second); - - cout << formatFunctionParent % relation.first % function << endl; - } - - //TEST CFG parent scope - boost::format formatScopeParent("cfa_parent(%1%, scope(%2%))."); - for (const auto &relation: cfagraph.__parentScopeRelations) { - cout << formatScopeParent % relation.first % relation.second << endl; - } - - //call connections - boost::format formatCall("cfa_call(%1%, %2%)."); - - for (const auto &relation: cfagraph.__callRelations) { - const ScopePacked scopeFrom = relation.first; - const string& functionTo = cfagraph.__nodesFunction.left.at(relation.second); - - cout << formatCall % (scopeFrom) % (functionTo) << endl; - } - - //function specializations descrtiption - //SECTIONTAG late-context cfa_function_specializations - boost::format formatSpecializations("cfa_function_specializations(%1%, %2%)."); - const list& functions = ast->getAllFunctions(); - for (auto f: functions){ - if (f->guardContext.isValid()){ - list guardRaw = compile(f->guardContext); - assert(guardRaw.size() == 1); - cout << formatSpecializations % (f->getName()) % (guardRaw.front()) << endl; - } - } - } - + void ClaspLayer::addRuleWarning(const RuleWarning &rule) { //__partGeneral << rule << endl; list domains; boost::format formatDef("%1%(%2%)"); std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(domains, domains.begin()), [&formatDef](const std::pair &argument) { string domain; switch (argument.second) { case DomainAnnotation::FUNCTION: domain = "function"; break; case DomainAnnotation::VARIABLE: domain = "variable"; break; } return boost::str(formatDef % domain % argument.first); }); list vars; std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(vars, vars.begin()), [](const std::pair &argument) { return argument.first.c_str(); }); list> guardsRaw; std::transform(rule.__guards.begin(), rule.__guards.end(), std::inserter(guardsRaw, guardsRaw.begin()), [this](const Expression &guard) { - return compile(guard); + return xreate::analysis::compile(guard); }); - const list& guards = multiplyLists(std::move(guardsRaw)); - list &&branches = compileNeg(rule.__condition); + const list& guards = xreate::analysis::multiplyLists(std::move(guardsRaw)); + list &&branches = xreate::analysis::compileNeg(rule.__condition); boost::format formatWarning("warning(%1%, (%2%)):- %3%, %4%, %5%."); for (const string &guardsJoined: guards) for (const string &branch: branches) { unsigned int hook = registerWarning(string(rule.__message)); __partGeneral << formatWarning %(hook) %(boost::algorithm::join(vars, ", ")) %(branch) %(guardsJoined) %(boost::algorithm::join(domains, ", ")) < - ClaspLayer::compile(const Expression &e){ - list result; - - switch (e.op) { - case Operator::CALL: { - assert(e.__state == Expression::COMPOUND); - - std::list> operands; - std::transform(e.operands.begin(), e.operands.end(), std::inserter(operands, operands.begin()), - [](const Expression &e) { - return ClaspLayer::compile(e); - }); - - list &&operands_ = multiplyLists(std::move(operands)); - result.push_back(boost::str(boost::format("%1%(%2%)") % (e.__valueS) % (boost::algorithm::join(operands_, ", ")))); - break; - } - case Operator::NEG: { - assert(e.operands.size() == 1); - - const Expression &op = e.operands.at(0); - list &&rawOp = compile(op); - - assert(rawOp.size() == 1); - result.push_back((boost::format("not %1%")%(rawOp.front())).str()); - break; - }; - - case Operator::NONE: { - switch (e.__state) { - case Expression::IDENT: - result.push_back(e.__valueS); - break; - - case Expression::NUMBER: - result.push_back(to_string(e.__valueD)); - break; - - default: - assert(true); - } - break; - } - - default: break; - } - -//TODO Null ad hoc ClaspLayer implementation -// if (e.isNone()){ -// result.push_back(e.__valueS); -// } - - assert(result.size()); - return result; - } - - std::list - ClaspLayer::compileNeg(const Expression &e){ - list result; - switch (e.op) { - case Operator::IMPL: { - assert(e.__state == Expression::COMPOUND); - assert(e.operands.size() == 2); - list operands1 = compile(e.operands.at(0)); - list operands2 = compile(e.operands.at(1)); - - boost::format formatNeg("%1%, not %2%"); - for (const auto &op1: operands1) - for (const auto &op2: operands2) { - result.push_back(boost::str(formatNeg %(op1) % (op2))); - } - break; - } - case Operator::NEG: { - assert(e.operands.size() == 1); - - const Expression &op = e.operands.at(0); - list &&rawOp = compile(op); - - assert(rawOp.size() == 1); - result.push_back(rawOp.front()); - break; - }; - - default: - assert(true); - } - - return result; - } + unsigned int ClaspLayer::registerWarning(std::string &&message) { static int warningId = 0; __warnings.emplace(warningId, message); return warningId++;; } void ClaspLayer::involveImports() { ostream &out = __partGeneral; for (string fn: ast->__rawImports) { std::ifstream file(fn); if (!file) continue; while(!file.eof()){ string line; std::getline(file, line); out << line << endl; } } } void - ClaspLayer::addRawScript(std::string&& script){ + ClaspLayer::addRawScript(std::string&& script){ __partGeneral << script; } void ClaspLayer::run() { involveImports(); - involveCFAData(); + this->dataDFA->print(__partGeneral); + this->dataCFA->print(__partGeneral); + + DominatorsTreeAnalysisProvider providerDominators; + providerDominators.run(this); + providerDominators.print(__partGeneral); + ostringstream program; program << __partTags.str() << __partGeneral.str(); cout << FYEL(program.str()) << endl; std::vector args{"clingo", nullptr}; DefaultGringoModule moduleDefault; Gringo::Scripts scriptsDefault(moduleDefault); - ClingoLib ctl(scriptsDefault, 0, args.data()); + ClingoLib ctl(scriptsDefault, 0, args.data(), {}, 0); ctl.add("base", {}, program.str()); ctl.ground({{"base", {}}}, nullptr); // solve Gringo::SolveResult result = ctl.solve([this](Gringo::Model const &model) { - this->onModel(model); + this->handlerSolution(model); return true; }, {}); - if (result == Gringo::SolveResult::SAT) { + if (result.satisfiable() == Gringo::SolveResult::Satisfiable) { cout << FGRN("SUCCESSFULLY") << endl; } else { cout << FRED("UNSUCCESSFULLY") << endl; } // invoke all query plugins to process clasp data for (auto q: __queries) { q.second->init(this); } } ClaspLayer::ClaspLayer() { } ClaspLayer::ModelFragment ClaspLayer::query(const std::string& atom) { if (! __model.count(atom)){ return boost::none; } return ModelFragment(__model.equal_range(atom)); } ScopePacked - ClaspLayer::pack(CodeScope* const scope) { + ClaspLayer::pack(CodeScope* const scope) { auto pos = __indexScopes.emplace(scope, __indexScopes.size()); if (pos.second) __registryScopes.push_back(scope); return pos.first->second; } + + size_t + ClaspLayer::getScopesCount() const{ + return __registryScopes.size(); + } SymbolPacked - ClaspLayer::pack(const Symbol& symbol, std::string hintSymbolName) + ClaspLayer::pack(const Symbol& symbol, std::string hintSymbolName) { SymbolPacked result; result.scope = pack(symbol.scope); result.identifier = symbol.identifier; __indexSymbolNameHints.emplace(result, hintSymbolName); return result; } - + Symbol - ClaspLayer::unpack(const SymbolPacked& symbol) + ClaspLayer::unpack(const SymbolPacked& symbol) { return Symbol{symbol.identifier, __registryScopes[symbol.scope]}; }; std::string - ClaspLayer::getHintForPackedSymbol(const SymbolPacked& symbol){ - auto result = __indexSymbolNameHints.find(symbol); - return (result == __indexSymbolNameHints.end())? "" : result->second; - } - -/* -void AspOutPrinter::reportSolution(const Clasp::Solver&, const Clasp::Enumerator&, bool complete) { - if (complete) std::cout << "No more models!" << std::endl; - else std::cout << "More models possible!" << std::endl; -} - - -void AspOutPrinter::reportModel(const Clasp::Solver& s, const Clasp::Enumerator&) { - std::cout << "Model " << s.stats.solve.models << ": \n"; -// get the symbol table from the solver - const Clasp::AtomIndex& symTab = *s.strategies().symTab; - for (Clasp::AtomIndex::const_iterator it = symTab.begin(); it != symTab.end(); ++it) - { -// print each named atom that is true w.r.t the current assignment - } - std::cout << std::endl; -} - -*/ -/***************************************** - * CFAGraph - ***************************************** - */ - void - CFAGraph::addFunctionAnnotations(const std::string& function, const std::vector&tags) { - unsigned int fid = registerNodeFunction(function); - - for (Tag tag: tags){ - __functionTags.emplace(fid, tag); - } - } - - void - CFAGraph::addScopeAnnotations(const ScopePacked& scope, const std::vector& tags){ - for (Expression tag: tags){ - __scopeTags.emplace(scope, tag); - } - } - - void - CFAGraph::addContextRules(const ScopePacked& scope, const std::vector& rules){ - for (Expression rule: rules){ - __contextRules.emplace(scope, rule); - } - } - - void - CFAGraph::addCallConnection(const ScopePacked& scopeFrom, const std::string& functionTo) { - unsigned int idFuncTo = registerNodeFunction(functionTo); - - __callRelations.emplace(scopeFrom, idFuncTo); - } - - void - CFAGraph::addParentConnection(const ScopePacked& scope, const std::string& functionParent){ - __parentFunctionRelations.emplace(scope, registerNodeFunction(functionParent)); - } - - void - CFAGraph::addParentConnection(const ScopePacked& scope, const ScopePacked& scopeParent){ - __parentScopeRelations.emplace(scope, scopeParent); - } - - unsigned int - CFAGraph::registerNodeFunction(const std::string& fname){ - auto pos = __nodesFunction.left.insert(make_pair(__nodesFunction.size(), fname)); - - return pos.first->first; - } - - - -/***************************************** - * DFAGraph - ***************************************** - */ - - class VisitorAddTag: public boost::static_visitor<> { - public: - void operator()(const SymbolPacked& symbol){ - __graph->__tags.emplace(symbol, move(__tag)); - } - - void operator()(SymbolTransient& symbol){ - symbol.tags.push_back(move(__tag)); - } - - void operator()(const SymbolInvalid& symbol){ - assert(false && "Undefined behaviour"); - } - - VisitorAddTag(DFAGraph* const dfagraph, Expression&& tag): - __graph(dfagraph), __tag(tag) {} - - private: - DFAGraph* const __graph; - Expression __tag; - }; - - class VisitorAddLink: public boost::static_visitor<> { - public: - void operator()(const SymbolPacked& nodeFrom){ - if (!__graph->isConnected(__nodeTo, nodeFrom)) - { - __graph->__edges.emplace_back(__nodeTo, nodeFrom); - __graph->__data.push_back(__link); - - DFAGraph::EdgeId eid = __graph->__edges.size()-1; - __graph->__outEdges.emplace(nodeFrom, eid); - } - } - - void operator()(const SymbolTransient& symbolFrom){ - if (__link != DFGConnection::ALIAS){ - assert(false && "Undefined behaviour"); - } - - for (const Expression& tag: symbolFrom.tags){ - __graph->__tags.emplace(__nodeTo, tag); - } - } - - void operator()(const SymbolInvalid&){ - if (__link == DFGConnection::ALIAS) return; - if (__link == DFGConnection::OPT) return; - - assert(false && "Undefined behaviour"); - } - - VisitorAddLink(DFAGraph* const dfagraph, const SymbolPacked& nodeTo, DFGConnection link): - __graph(dfagraph), __nodeTo(nodeTo), __link(link) {} - - private: - DFAGraph* const __graph; - SymbolPacked __nodeTo; - DFGConnection __link; - }; - - bool - DFAGraph::isConnected(const SymbolPacked& identifierTo, const SymbolPacked& identifierFrom) - { - auto range = __outEdges.equal_range(identifierFrom); - - for(std::multimap::iterator edge = range.first; edge != range.second; ++edge) - { - if (__edges[edge->second].second == identifierTo) - return true; + ClaspLayer::getHintForPackedSymbol(const SymbolPacked& symbol){ + if (!symbol.categoryTransient) { + auto result = __indexSymbolNameHints.find(symbol); + return (result == __indexSymbolNameHints.end())? "" : result->second; + + } else { + return "anonym(" + to_string(symbol.identifier) + ")"; } - - return false; } - - void - DFAGraph::addConnection(const SymbolPacked& nodeTo, const SymbolNode& nodeFrom, DFGConnection link) { - VisitorAddLink visitor(this, nodeTo, link); - boost::apply_visitor(visitor, nodeFrom); - } - - void - DFAGraph::addAnnotation(SymbolNode& node, Expression&& tag) { - VisitorAddTag visitor(this, move(tag)); - boost::apply_visitor(visitor, node); - } - + bool operator==(const SymbolPacked& s1, const SymbolPacked& s2) { return s1.identifier == s2.identifier && s1.scope == s2.scope; } bool operator<(const SymbolPacked& s1, const SymbolPacked& s2) { return s1.scope < s2.scope || (s1.scope == s2.scope && s1.identifier < s2.identifier); } IQuery* - ClaspLayer::registerQuery(IQuery *query, const QueryId& id) { + ClaspLayer::registerQuery(IQuery *query, const QueryId& id) { return __queries.emplace(id, query).first->second; } IQuery* - ClaspLayer::getQuery(const QueryId& id){ + ClaspLayer::getQuery(const QueryId& id){ assert(__queries.count(id) && "Undefined query"); return __queries.at(id); } } + diff --git a/cpp/src/clasplayer.h b/cpp/src/clasplayer.h index f920106..76d83f3 100644 --- a/cpp/src/clasplayer.h +++ b/cpp/src/clasplayer.h @@ -1,239 +1,227 @@ #ifndef CLASPLAYER_H #define CLASPLAYER_H #include "ast.h" #include "contextrule.h" #include #include #include #include +#include #include +#include #include namespace xreate { - typedef unsigned int ScopePacked; + typedef unsigned int ScopePacked; - class CFAGraph { - friend class ClaspLayer; - - public: - void addFunctionAnnotations(const std::string& function, const std::vector&tags); - void addScopeAnnotations(const ScopePacked& scope, const std::vector&tags); - void addContextRules(const ScopePacked& scope, const std::vector&rules); - - void addCallConnection(const ScopePacked& scopeFrom, const std::string& functionTo); - void addParentConnection(const ScopePacked& scope, const std::string& functionParent); - void addParentConnection(const ScopePacked& scope, const ScopePacked& scopeParent); -// void addScopeRetIdentifier(const ScopePacked& scope, const SymbolPacked& identifier); - - private: - std::map __parentFunctionRelations; - std::map __parentScopeRelations; - std::set> __callRelations; - boost::bimap __nodesFunction; - std::multimap __functionTags; - std::multimap __scopeTags; - std::multimap __contextRules; - - unsigned int registerNodeFunction(const std::string& fname); - }; - - - - struct SymbolPacked - { + struct SymbolPacked { VID identifier; ScopePacked scope; + bool categoryTransient = false; }; - struct SymbolTransient{ - std::list tags; - }; - - struct SymbolInvalid{}; - - typedef boost::variant SymbolNode; - bool operator==(const SymbolPacked& s1, const SymbolPacked& s2); bool operator<(const SymbolPacked& s1, const SymbolPacked& s2); - enum class DFGConnection{ - ALIAS, OPT, PROTO}; - - class VisitorAddTag; - class VisitorAddLink; + enum class DFGConnection { + STRONG, WEAK, PROTOTYPE + }; - class DFAGraph - { - friend class ClaspLayer; - friend class VisitorAddTag; - friend class VisitorAddLink; + class IAnalysisData { public: - void addAnnotation(SymbolNode& identifier, Expression&& tag); - void addConnection(const SymbolPacked& identifierTo, const SymbolNode& identifierFrom, DFGConnection link); - bool isConnected(const SymbolPacked& identifierTo, const SymbolPacked& identifierFrom); - - private: - typedef unsigned int EdgeId; - std::vector> __edges; - std::multimap __outEdges; - std::vector __data; - std::multimap __tags; + void print(std::ostringstream& output) const; + virtual ~IAnalysisData(){}; }; - - class IQuery { + + class IQuery { public: - virtual void init(ClaspLayer* clasp)=0; + virtual void init(ClaspLayer* clasp) = 0; virtual ~IQuery() {} }; - enum class QueryId{ - ContainersQuery, - ContextQuery, - PtrvalidQuery + enum class QueryId { + ContainersQuery, + ContextQuery, + PtrvalidQuery }; + namespace analysis{ + class DFAGraph; + class CFAGraph; + } + class ClaspLayer { - friend class ContextRule; + friend class ContextRule; + //PROVIDERS: public: - AST *ast; - DFAGraph dfaData; - CFAGraph cfagraph; + boost::scoped_ptr dataDFA; + void setDFAData(xreate::analysis::DFAGraph* graph); - ClaspLayer(); + boost::scoped_ptr dataCFA; + void setCFAData(xreate::analysis::CFAGraph* graph); + + void addRawScript(std::string&& script); + + private: + void involveImports(); + + //QUERIES + public: IQuery* registerQuery(IQuery* query, const QueryId& id); IQuery* getQuery(const QueryId& id); - void addFunctionTags(const std::string &function, const std::vector &tags); - void setCFAData(CFAGraph &&graph); - void addDFAData(DFAGraph &&graph); - void addRuleWarning(const RuleWarning &rule); - - void run(); template - static std::tuple parse(const Gringo::Value& atom); + static std::tuple parse(const Gringo::Symbol& atom); - typedef std::multimap::const_iterator ModelIterator; - typedef boost::optional> ModelFragment; + typedef std::multimap::const_iterator ModelIterator; + typedef boost::optional> ModelFragment; ModelFragment query(const std::string& atom); - ScopePacked pack(CodeScope* const scope); - SymbolPacked pack(const Symbol& symbol, std::string hintSymbolName=""); + size_t getScopesCount() const; + SymbolPacked pack(const Symbol& symbol, std::string hintSymbolName = ""); + ScopePacked pack(CodeScope * const scope); Symbol unpack(const SymbolPacked& symbol); std::string getHintForPackedSymbol(const SymbolPacked& symbol); - void addRawScript(std::string&& script); private: - // all query plugins to process clasp data std::map __queries; - std::multimap __model; - std::map __warnings; - std::ostringstream __partTags; - std::ostringstream __partGeneral; + std::multimap __model; std::map __indexSymbolNameHints; - std::unordered_map __indexScopes; std::vector __registryScopes; - void printWarnings(std::ostream& out); - bool onModel(Gringo::Model const &model); - static std::list compile(const Expression &e); - static std::list compileNeg(const Expression &e); + //WARNINGS + //TODO move to separate provider/query + public: + void addRuleWarning(const RuleWarning &rule); unsigned int registerWarning(std::string &&message); - void involveImports(); - void involveCFAData(); + + private: + std::map __warnings; + void printWarnings(std::ostream& out); + + //DEFAULT + public: + AST *ast; + + ClaspLayer(); + void run(); + + private: + std::ostringstream __partTags; + std::ostringstream __partGeneral; + + bool handlerSolution(Gringo::Model const &model); }; template struct ParseImplAtom { - static typ get(const Gringo::Value& atom) - { + + static typ get(const Gringo::Symbol& atom) { return atom.num(); } }; template<> struct ParseImplAtom { - static std::string get(const Gringo::Value& atom) - { - return *atom.string(); - }}; + static std::string get(const Gringo::Symbol& atom) { + switch (atom.type()) { + case Gringo::SymbolType::Str: return atom.string().c_str(); + case Gringo::SymbolType::Fun: return atom.name().c_str(); + + default: break; + } + + assert(false && "Inappropriate symbol type"); + } + }; template<> struct ParseImplAtom { - static SymbolPacked get(const Gringo::Value& atom) - { + + static SymbolPacked get(const Gringo::Symbol& atom) { auto result = ClaspLayer::parse(atom); return SymbolPacked{std::get<0>(result), std::get<1>(result)}; - }}; + } + }; template<> - struct ParseImplAtom { - static Gringo::Value get(const Gringo::Value& atom) - { + struct ParseImplAtom { + + static Gringo::Symbol get(const Gringo::Symbol& atom) { return atom; - }}; + } + }; template<> struct ParseImplAtom { - static Expression get(const Gringo::Value& atom) - { - switch (atom.type()){ - case Gringo::Value::NUM: return Expression(atom.num()); - case Gringo::Value::ID: return Expression((std::string(atom.string()))); - case Gringo::Value::FUNC: { - Expression result(Operator::CALL, {Expression(std::string(atom.name()))}); - for(const Gringo::Value& arg: atom.args()){ - result.addArg(ParseImplAtom::get(arg)); - } - - return result; - } - - default: { - assert(false); - } - } - }}; + + static Expression get(const Gringo::Symbol& atom) { + switch (atom.type()) { + case Gringo::SymbolType::Num: return Expression(atom.num()); + case Gringo::SymbolType::Str: return Expression(std::string(atom.string().c_str())); + + case Gringo::SymbolType::Fun: + { + //ID + if (!atom.args().size){ + return Expression(std::string(atom.name().c_str())); + } + + //FUNC + Expression result(Operator::CALL,{Expression(std::string(atom.name().c_str()))}); + for (const Gringo::Symbol& arg : atom.args()) { + result.addArg(ParseImplAtom::get(arg)); + } + + return result; + } + + default: + { + assert(false); + } + } + } + }; template struct Parse_Impl { - static void parse(Tuple& tup, Gringo::FWValVec::const_iterator arg) - { + + static void parse(Tuple& tup, Gringo::SymSpan::iterator arg) { const size_t tupleSize = std::tuple_size::value; - typedef typename std::tuple_element::type ElType; + typedef typename std::tuple_element < tupleSize - index, Tuple>::type ElType; - ElType& el = std::get(tup); + ElType& el = std::get < tupleSize - index > (tup); - Gringo::Value atom = *arg; + Gringo::Symbol atom = *arg; el = ParseImplAtom::get(atom); - Parse_Impl::parse(tup, ++arg); + Parse_Impl ::parse(tup, ++arg); } }; template - struct Parse_Impl - { - static void parse(Tuple& tup, Gringo::FWValVec::const_iterator arg) - {} - }; + struct Parse_Impl { + static void parse(Tuple& tup, Gringo::SymSpan::iterator arg) { + } + }; template std::tuple - ClaspLayer::parse(const Gringo::Value& atom) - { - typedef std::tuple Tuple; + ClaspLayer::parse(const Gringo::Symbol& atom) { + typedef std::tuple < Types...> Tuple; Tuple tup; - Parse_Impl::value>::parse(tup, atom.args().begin()); + Parse_Impl::value>::parse(tup, atom.args().first); return tup; } } #endif diff --git a/cpp/src/compilation/instr-containers.cpp b/cpp/src/compilation/advanced.cpp similarity index 57% rename from cpp/src/compilation/instr-containers.cpp rename to cpp/src/compilation/advanced.cpp index 2cbf0a0..db651c0 100644 --- a/cpp/src/compilation/instr-containers.cpp +++ b/cpp/src/compilation/advanced.cpp @@ -1,575 +1,449 @@ -#include "instr-containers.h" -#include "llvmlayer.h" -#include "ast.h" +/* + * File: InstructionsAdvanced.cpp + * Author: pgess + * + * Created on June 26, 2016, 6:00 PM + */ + +#include +#include "compilation/advanced.h" +#include "compilation/containers.h" + #include "query/context.h" #include "query/containers.h" #include "query/ptrvalid.h" +#include "llvmlayer.h" +#include "ast.h" + using namespace std; using namespace llvm; using namespace xreate; using namespace xreate::containers; +using namespace xreate::compilation; #define NAME(x) (hintRetVar.empty()? x : hintRetVar) #define UNUSED(x) (void)(x) #define EXPAND_CONTEXT \ LLVMLayer* llvm = context.pass->man->llvm; \ compilation::CodeScopeUnit* scope = context.scope; \ compilation::FunctionUnit* function = context.function; -Instructions::Instructions(compilation::Context ctx) +Advanced::Advanced(compilation::Context ctx) : context(ctx), tyNum (static_cast (ctx.pass->man->llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::Num))))) {} llvm::Value* -Instructions::compileMapSolid(const Expression &expr, const std::string hintRetVar) { +Advanced::compileMapSolid(const Expression &expr, const std::string hintRetVar) { EXPAND_CONTEXT //initialization std::string varIn = expr.getOperands()[0].getValueString(); Symbol symbolIn = scope->scope->findSymbol(varIn); ImplementationRec implIn = containers::Query::queryImplementation(symbolIn).extract(); // impl of input list size_t size = implIn.size; CodeScope* scopeLoop = expr.blocks.front(); - std::string varEl = scopeLoop->__args[0]; + std::string varEl = scopeLoop->__bindings[0]; Iterator* it = Iterator::create(context, symbolIn); llvm::Value *rangeFrom = it->begin(); llvm::Value *rangeTo = it->end(); //definitions ArrayType* tyNumArray = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::Num, size)))); llvm::IRBuilder<> &builder = llvm->builder; llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "loop", function->raw); llvm::BasicBlock *blockBeforeLoop = builder.GetInsertBlock(); llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "postloop", function->raw); Value* dataOut = llvm->builder.CreateAlloca(tyNumArray, ConstantInt::get(tyNum, size), NAME("map")); // * initial check Value* condBefore = builder.CreateICmpSLE(rangeFrom, rangeTo); builder.CreateCondBr(condBefore, blockLoop, blockAfterLoop); // create PHI: builder.SetInsertPoint(blockLoop); llvm::PHINode *stateLoop = builder.CreatePHI(tyNum, 2, "mapIt"); stateLoop->addIncoming(rangeFrom, blockBeforeLoop); // loop body: Value* elIn = it->get(stateLoop, varEl); compilation::CodeScopeUnit* scopeLoopUnit = function->getScopeUnit(scopeLoop); scopeLoopUnit->bindArg(elIn, move(varEl)); Value* elOut = scopeLoopUnit->compile(); Value *pElOut = builder.CreateGEP(dataOut, ArrayRef(std::vector{ConstantInt::get(tyNum, 0), stateLoop})); builder.CreateStore(elOut, pElOut); //next iteration preparing Value *stateLoopNext = builder.CreateAdd(stateLoop,llvm::ConstantInt::get(tyNum, 1)); stateLoop->addIncoming(stateLoopNext, blockLoop); //next iteration checks: Value* condAfter = builder.CreateICmpSLE(stateLoopNext, rangeTo); builder.CreateCondBr(condAfter, blockLoop, blockAfterLoop); //finalization: builder.SetInsertPoint(blockAfterLoop); return dataOut; } Value* -Instructions::compileArrayIndex(const Symbol &dataSymbol, std::vector indexes, std::string hintRetVar) +Advanced::compileArrayIndex(const Symbol &dataSymbol, std::vector indexes, std::string hintRetVar) { EXPAND_CONTEXT UNUSED(function); //TODO find out symbol identifier in order to name it in raw llvm; llvm::Value* data = scope->compileSymbol(dataSymbol); const Expression& decl = CodeScope::findDeclaration(dataSymbol); + //TODO review array index compilation strategy if (decl.op == Operator::LIST) { assert(indexes.size() == 1); return llvm->builder.CreateExtractElement(data, indexes[0], NAME("el")); } indexes.insert(indexes.begin(), llvm::ConstantInt::get(tyNum, 0)); Value *pEl = llvm->builder.CreateGEP(data, llvm::ArrayRef(indexes)); return llvm->builder.CreateLoad(pEl, NAME("el")); } Value* -Instructions::compileStructIndex(llvm::Value* aggregate, const ExpandedType& t, const std::string& idx){ +Advanced::compileStructIndex(llvm::Value* aggregate, const ExpandedType& t, const std::string& idx){ EXPAND_CONTEXT UNUSED(scope); TypeUtils types(llvm); std::vector&& fields = types.getStructFields(t); for (unsigned i=0, size = fields.size(); i refs; llvm::IntegerType* tyInt = llvm::Type::getInt32Ty(llvm::getGlobalContext()); llvm::ConstantInt* zero = llvm::ConstantInt::get(tyInt, 0, false); llvm::BasicBlock *blockSafe = llvm::BasicBlock::Create(llvm::getGlobalContext(), "safe", function->raw); - // safety check: not null ptr - Symbol s; - if (! QueryPtrValid::assertValidPtr(s)){ - PointerType* tyAggr = dyn_cast(aggregate->getType()); - llvm::Value* null = llvm::ConstantPointerNull::get(tyAggr); - Value* condNull = llvm->builder.CreateICmpNE(aggregate, null); + // TODO review safety check: not null ptr + // SECTIONTAG validptr exception + Symbol s; + if (! QueryPtrValid::assertValidPtr(s)){ + PointerType* tyAggr = dyn_cast(aggregate->getType()); + llvm::Value* null = llvm::ConstantPointerNull::get(tyAggr); + Value* condNull = llvm->builder.CreateICmpNE(aggregate, null); - llvm::BasicBlock *blockException = llvm::BasicBlock::Create(llvm::getGlobalContext(), "exception", function->raw); - llvm->builder.CreateCondBr(condNull, blockSafe, blockException); - llvm->initExceptionBlock(blockException); - } + llvm::BasicBlock *blockException = llvm::BasicBlock::Create(llvm::getGlobalContext(), "exception", function->raw); + llvm->builder.CreateCondBr(condNull, blockSafe, blockException); + llvm->initExceptionBlock(blockException); + } - llvm->builder.SetInsertPoint(blockSafe); + llvm->builder.SetInsertPoint(blockSafe); std::vector indexes; //dereference pointer if (types.isPointer(t)){ indexes.push_back(zero); } - indexes.push_back(ConstantInt::get(tyInt, i)); - - Value* addr = llvm->builder.CreateGEP(aggregate, indexes); - return llvm->builder.CreateLoad(addr); + indexes.push_back(ConstantInt::get(tyInt, i)); - } + Value* addr = llvm->builder.CreateGEP(aggregate, indexes); + return llvm->builder.CreateLoad(addr); + } } assert(false && "not found required struct field"); + return nullptr; } llvm::Value* -Instructions::compileFold(const Expression& fold, const std::string& hintRetVar) +Advanced::compileFold(const Expression& fold, const std::string& hintRetVar) { EXPAND_CONTEXT assert(fold.op == Operator::FOLD); //initialization: Symbol varInSymbol = scope->scope->findSymbol(fold.getOperands()[0].getValueString()); Implementation info = Query::queryImplementation(varInSymbol); Iterator* it = Iterator::create(context, varInSymbol); - llvm::Value* rangeFrom = it->begin(); - llvm::Value* rangeTo = it->end(); + llvm::Value* rangeBegin = it->begin(); + llvm::Value* rangeEnd = it->end(); llvm::Value* accumInit = scope->process(fold.getOperands()[1]); std::string varIn = fold.getOperands()[0].getValueString(); std::string varAccum = fold.bindings[1]; std::string varEl = fold.bindings[0]; - llvm::Value* valSat = nullptr; - bool flagHasSaturation = false; //false; // TODO add `saturation` ann. + TransformerSaturation* transformerSaturation = context.pass->transformations->get(); llvm::BasicBlock *blockBeforeLoop = llvm->builder.GetInsertBlock(); llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold", function->raw); + llvm::BasicBlock *blockBody = llvm::BasicBlock::Create(llvm::getGlobalContext(), "body", function->raw); llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "postfold", function->raw); - llvm::BasicBlock *blockEarly = llvm::BasicBlock::Create(llvm::getGlobalContext(), "earlyret", function->raw); - - - // * initial check - Value* condBefore = llvm->builder.CreateICmpNE(rangeFrom, rangeTo); - llvm->builder.CreateCondBr(condBefore, blockLoop, blockEarly); - llvm->builder.SetInsertPoint(blockEarly); - llvm->builder.CreateRet(accumInit); - - //TODO implement saturation; add unittests; - // Saturation check - if (flagHasSaturation) - { - Value* condSat = llvm->builder.CreateICmpNE(accumInit, valSat); - llvm->builder.CreateCondBr(condSat, blockLoop, blockAfterLoop); - } + llvm->builder.CreateBr(blockLoop); // * create phi llvm->builder.SetInsertPoint(blockLoop); - llvm::PHINode *accum = llvm->builder.CreatePHI(tyNum, 2, NAME("accum")); + llvm::PHINode *accum = llvm->builder.CreatePHI(accumInit->getType(), 2, NAME("accum")); accum->addIncoming(accumInit, blockBeforeLoop); - llvm::PHINode *stateLoop = llvm->builder.CreatePHI(rangeFrom->getType(), 2, "foldIt"); - stateLoop->addIncoming(rangeFrom, blockBeforeLoop); + llvm::PHINode *itLoop = llvm->builder.CreatePHI(rangeBegin->getType(), 2, "foldIt"); + itLoop->addIncoming(rangeBegin, blockBeforeLoop); // * loop body + llvm->builder.SetInsertPoint(blockBody); CodeScope* scopeLoop = fold.blocks.front(); compilation::CodeScopeUnit* loopUnit = function->getScopeUnit(scopeLoop); - Value* elIn = it->get(stateLoop); + Value* elIn = it->get(itLoop); loopUnit->bindArg(accum, move(varAccum)); loopUnit->bindArg(elIn, move(varEl)); Value* accumNext = loopUnit->compile(); + // * computing next iteration state + Value *itLoopNext = it->advance(itLoop); + accum->addIncoming(accumNext, llvm->builder.GetInsertBlock()); + itLoop->addIncoming(itLoopNext, llvm->builder.GetInsertBlock()); + llvm->builder.CreateBr(blockLoop); + // * break checks, continue checks - if (flagHasSaturation) + //!! only after compiled Loop Body in order to fetch saturation expression + llvm->builder.SetInsertPoint(blockLoop); + if (transformerSaturation->exists()) { - llvm::BasicBlock *blockChecks = llvm::BasicBlock::Create(llvm::getGlobalContext(), "checks", function->raw); - Value* condSat = llvm->builder.CreateICmpNE(accumNext, valSat); - llvm->builder.CreateCondBr(condSat, blockChecks, blockAfterLoop); - llvm->builder.SetInsertPoint(blockChecks); + transformerSaturation->inject(blockBeforeLoop, blockAfterLoop, context); } - // * computing next iteration state - Value *stateLoopNext = it->move(stateLoop); - accum->addIncoming(accumNext, llvm->builder.GetInsertBlock()); - stateLoop->addIncoming(stateLoopNext, llvm->builder.GetInsertBlock()); - // * next iteration checks - Value* condAfter = llvm->builder.CreateICmpNE(stateLoopNext, rangeTo); - llvm->builder.CreateCondBr(condAfter, blockLoop, blockAfterLoop); + // * next iteration checks + Value* condRange = llvm->builder.CreateICmpNE(itLoop, rangeEnd); + llvm->builder.CreateCondBr(condRange, blockBody, blockAfterLoop); // finalization: llvm->builder.SetInsertPoint(blockAfterLoop); return accum; } llvm::Value* -Instructions::compileLoopContext(const Expression& expression, const std::string& hintRetVar){ +Advanced:: compileFoldInf(const Expression& fold, const std::string& hintRetVar){ + EXPAND_CONTEXT + assert(fold.op == Operator::FOLD_INF); + + std::string accumName = fold.bindings[0]; + llvm::Value* accumInit = scope->process(fold.getOperands()[0]); + + llvm::BasicBlock *blockBeforeLoop = llvm->builder.GetInsertBlock(); + llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold", function->raw); + llvm::BasicBlock *blockBody = llvm::BasicBlock::Create(llvm::getGlobalContext(), "body", function->raw); + llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "postfold", function->raw); + TransformerSaturation* transformerSaturation = context.pass->transformations->get(); + + llvm->builder.CreateBr(blockLoop); + + // * create phi + llvm->builder.SetInsertPoint(blockLoop); + llvm::PHINode *accum = llvm->builder.CreatePHI(accumInit->getType(), 2, NAME("accum")); + accum->addIncoming(accumInit, blockBeforeLoop); + + // * loop body + llvm->builder.SetInsertPoint(blockBody); + CodeScope* scopeLoop = fold.blocks.front(); + compilation::CodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); + unitLoop->bindArg(accum, move(accumName)); + Value* accumNext = unitLoop->compile(); + + // * computing next iteration state + accum->addIncoming(accumNext, llvm->builder.GetInsertBlock()); + llvm->builder.CreateBr(blockLoop); + + // * break checks, continue checks + assert(transformerSaturation->exists()); + llvm->builder.SetInsertPoint(blockLoop); + transformerSaturation->inject(blockBeforeLoop, blockAfterLoop, context); + llvm->builder.CreateBr(blockBody); + + // finalization: + llvm->builder.SetInsertPoint(blockAfterLoop); + return accum; +} + +llvm::Value* +Advanced::compileLoopContext(const Expression& expression, const std::string& hintRetVar){ EXPAND_CONTEXT llvm::IRBuilder<>& builder = llvm->builder; ContextQuery* queryContext = reinterpret_cast (context.pass->man->clasp->getQuery(QueryId::ContextQuery)); ScopePacked scopeOuterId = context.pass->man->clasp->pack(scope->scope); - const ContextDomain& contextScopeOuter = queryContext->getContext(scopeOuterId); + const Domain& contextScopeOuter = queryContext->getContext(scopeOuterId); std::string classSelected = expression.operands[0].getValueString(); std::list elementsSelected; for (const Expression& c: contextScopeOuter){ if (c.op == Operator::CALL && c.getValueString() == classSelected){ assert(c.operands.size()); elementsSelected.push_back(c.operands[0]); } } assert(expression.blocks.size()); CodeScope* scopeInner = expression.blocks.front(); compilation::CodeScopeUnit* scopeInnerUnit = function->getScopeUnit(scopeInner); ScopePacked scopeInnerId = context.pass->man->clasp->pack(scopeInner); llvm::Value* result = nullptr; for (const Expression& element: elementsSelected){ std::string blockName = "context" + element.getValueString(); llvm::BasicBlock *blockInner = llvm::BasicBlock::Create(llvm::getGlobalContext(), blockName, function->raw); builder.CreateBr(blockInner); builder.SetInsertPoint(blockInner); queryContext->forceContext(scopeInnerId, {element}); scopeInnerUnit->reset(); result = scopeInnerUnit->compile(); } return result; } llvm::Value* -Instructions::compileIf(const Expression& exprIf, const std::string& hintRetVar) +Advanced::compileIf(const Expression& exprIf, const std::string& hintRetVar) { EXPAND_CONTEXT //initialization: const Expression& condExpr = exprIf.getOperands()[0]; llvm::IRBuilder<>& builder = llvm->builder; llvm::Type* tyResultType = llvm->toLLVMType(llvm->ast->expandType(exprIf.type)); llvm::BasicBlock *blockAfter = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifAfter", function->raw); llvm::BasicBlock *blockTrue = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifTrue", function->raw); llvm::BasicBlock *blockFalse = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifFalse", function->raw); llvm::Value* cond = scope->process(condExpr); llvm->builder.CreateCondBr(cond, blockTrue, blockFalse); builder.SetInsertPoint(blockTrue); CodeScope* scopeTrue = exprIf.blocks.front(); llvm::Value* resultTrue = function->getScopeUnit(scopeTrue)->compile(); builder.CreateBr(blockAfter); builder.SetInsertPoint(blockFalse); CodeScope* scopeFalse = exprIf.blocks.back(); llvm::Value* resultFalse = function->getScopeUnit(scopeFalse)->compile(); builder.CreateBr(blockAfter); builder.SetInsertPoint(blockAfter); llvm::PHINode *ret = builder.CreatePHI(tyResultType, 2, NAME("if")); ret->addIncoming(resultTrue, blockTrue); ret->addIncoming(resultFalse, blockFalse); return ret; } - +//TODO Switch: default variant no needed when all possible conditions are considered llvm::Value* -Instructions::compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar){ +Advanced::compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar){ EXPAND_CONTEXT UNUSED(scope); UNUSED(function); assert(exprSwitch.operands.size() >= 2); assert(exprSwitch.operands[1].op == Operator::CASE_DEFAULT); int countCases = exprSwitch.operands.size()-1; llvm::IRBuilder<>& builder = llvm->builder; llvm::BasicBlock* blockProlog = builder.GetInsertBlock(); llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "switchAfter", function->raw); builder.SetInsertPoint(blockEpilog); llvm::Type* exprSwitchType = llvm->toLLVMType(ExpandedType(exprSwitch.type)); llvm::PHINode *ret = builder.CreatePHI(exprSwitchType, countCases, NAME("switch")); builder.SetInsertPoint(blockProlog); llvm::Value * conditionSwitch = scope->process(exprSwitch.operands[0]); llvm::BasicBlock *blockDefault = llvm::BasicBlock::Create(llvm::getGlobalContext(), "caseDefault", function->raw); llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(conditionSwitch, blockDefault, countCases); for (int size = exprSwitch.operands.size(), i=2; iraw); llvm::Value* condCase = function->getScopeUnit(exprSwitch.operands[i].blocks.front())->compile(); builder.SetInsertPoint(blockCase); llvm::Value* resultCase = function->getScopeUnit(exprSwitch.operands[i].blocks.back())->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultCase, builder.GetInsertBlock()); builder.SetInsertPoint(blockProlog); instructionSwitch->addCase(dyn_cast(condCase), blockCase); } //compile default block: builder.SetInsertPoint(blockDefault); CodeScope* scopeDefault = exprSwitch.operands[1].blocks.front(); llvm::Value* resultDefault = function->getScopeUnit(scopeDefault)->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultDefault, builder.GetInsertBlock()); builder.SetInsertPoint(blockEpilog); return ret; } llvm::Value* -Instructions::compileConstantArray(const Expression &expr, const std::string& hintRetVar) { +Advanced::compileConstantArray(const Expression &expr, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(scope); UNUSED(function); const size_t& __size = expr.getOperands().size(); const Expression& __data = expr; ArrayType* typList = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::I32, __size)))); Type*typI32 = llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::I32))); std::vector list; list.reserve(__size); const std::vector operands = __data.getOperands(); std::transform(operands.begin(), operands.end(), std::inserter(list, list.begin()), [typI32](const Expression& e){return ConstantInt::get(typI32, e.getValueDouble());}); Value* listSource = ConstantArray::get(typList, ArrayRef(list)); /* Value* listDest = l.builder.CreateAlloca(typList, ConstantInt::get(typI32, __size), *hintRetVar); l.buil1der.CreateMemCpy(listDest, listSource, __size, 16); */ return listSource; } llvm::Value* -Instructions::compileConstantStringAsPChar(const string& data, const std::string& hintRetVar) +Advanced::compileConstantStringAsPChar(const string& data, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(function); UNUSED(scope); Type* typPchar = PointerType::getUnqual(Type::getInt8Ty(llvm::getGlobalContext())); //ArrayType* typStr = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::I8, size+1)))); /* std::vector chars; chars.reserve(size+1); for (size_t i=0; i< size; ++i){ chars[i] = ConstantInt::get(typI8, (unsigned char) data[i]); } chars[size] = ConstantInt::get(typI8, 0); */ Value* rawData = ConstantDataArray::getString(llvm::getGlobalContext(), data); Value* rawPtrData = llvm->builder.CreateAlloca(rawData->getType(), ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), 1, false)); llvm->builder.CreateStore(rawData, rawPtrData); return llvm->builder.CreateCast(llvm::Instruction::BitCast, rawPtrData, typPchar, hintRetVar); } - - - -template -class IteratorForward; - -template<> -class IteratorForward : public Iterator { -private: - LLVMLayer* llvm; - const xreate::Symbol current; - const Symbol source; - const ImplementationLinkedList linkedlist; - CodeScope* const sourceScope; - //TODO initialize ans mark as const (three fields) - compilation::CodeScopeUnit* sourceUnit; - compilation::FunctionUnit* function; //TODO is used somewhere? - const Expression& sourceDecl; - compilation::Context context; - llvm::Type* sourceRawType =nullptr; - -public: - IteratorForward(compilation::Context ctx, const xreate::Symbol& s, const ImplementationRec& implementation) - : llvm(ctx.pass->man->llvm), current(s), source(implementation.source), linkedlist(source), sourceScope(source.scope), sourceUnit(new compilation::CodeScopeUnit(source.scope, ctx.function, ctx.pass)), - sourceDecl(CodeScope::findDeclaration(source)), - context(ctx) - { - } - - llvm::Value* begin() { - switch(sourceDecl.op) { - case xreate::Operator::LIST: - { - sourceRawType = Type::getInt32Ty(llvm::getGlobalContext()); - return ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), 0); - }; - - case xreate::Operator::LIST_RANGE:{ - assert(sourceDecl.operands.size()==2); - - llvm::Value* result = sourceUnit->process(sourceDecl.operands.at(0)); - sourceRawType = result->getType(); - - return result; - }; - - default: break; - } - - if (linkedlist){ - llvm::Value* result = sourceUnit->process(sourceDecl); - sourceRawType = result->getType(); - return result; - } - - assert(false); - } - - llvm::Value* end(){ - switch(sourceDecl.op) { - case xreate::Operator::LIST: { - size_t idLast = sourceDecl.operands.size() - 1; - return ConstantInt::get(sourceRawType, idLast); - } - - case xreate::Operator::LIST_RANGE: { - assert(sourceDecl.operands.size() == 2); - return sourceUnit->process(sourceDecl.operands.at(1)); - }; - - default: break; - } - - //return null pointer - if (linkedlist){ - return ConstantPointerNull::getNullValue(sourceRawType); - } - - assert(false && "Unknown declaration"); - return nullptr; - } - - llvm::Value* get(Value* index,const std::string& hintRetVar="") override{ - const Expression& currentDecl = CodeScope::findDeclaration(current); - - switch (currentDecl.op) { - case xreate::Operator::LIST: { - //TODO re check is it right scope(source) to compilation currentDecl. Write unittests for this. - //llvm::Value* currentValue = sourceUnit->process(currentDecl); - return Instructions(context).compileArrayIndex(current, vector{index}); - }; - - case xreate::Operator::LIST_RANGE: { - return index; - }; - - case xreate::Operator::MAP: { - assert(currentDecl.getOperands().size()==1); - assert(currentDecl.bindings.size()); - assert(currentDecl.blocks.size()); - - CodeScope* scopeLoop = currentDecl.blocks.front(); - const std::string& varIn = currentDecl.getOperands()[0].getValueString(); - std::string varEl = currentDecl.bindings[0]; - - const Symbol& symbIn = current.scope->findSymbol(varIn); - auto it = std::unique_ptr(Iterator::create(context, symbIn)); - - Value* elIn = it->get(index, varEl); - compilation::CodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); - unitLoop->bindArg(elIn, std::move(varEl)); - return unitLoop->compile(); - } - - case xreate::Operator::NONE: { - assert(currentDecl.__state==Expression::IDENT); - const Symbol& symbIn = current.scope->findSymbol(currentDecl.getValueString()); - auto it = std::unique_ptr(Iterator::create(context, symbIn)); - return it->get(index); - }; - - default: break; - } - - if (linkedlist){ - return index; - } - - assert(false && "Unknown declaration"); - return nullptr; - } - - llvm::Value* move(Value* index, const std::string& hintRetVar) override{ - switch(sourceDecl.op) - { - case xreate::Operator::LIST: - case xreate::Operator::LIST_RANGE: - return llvm->builder.CreateAdd(index, llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 1), hintRetVar); - - default: break; - } - - if (linkedlist){ - ExpandedType tySource = llvm->ast->expandType(sourceScope->findDefinition(source)); - assert(tySource->__operator == TypeOperator::ARRAY && "Linked list implementation has to have ARRAY type"); - assert(tySource->__operands.size()); - - return Instructions(context).compileStructIndex(index, ExpandedType(TypeAnnotation(tySource->__operands.at(0))), linkedlist.fieldPointer); - } - - assert(false && "Unknown declaration"); - return nullptr; - } -}; - -Iterator* -Iterator::create(compilation::Context context, const Symbol& var){ - - const Implementation& data = Query::queryImplementation(var); - - switch(data.impl){ - case ON_THE_FLY: - return new IteratorForward(context, var, data.extract()); - - default: assert(true); - } - - assert(false && "Unknown declaration"); - return nullptr; -} diff --git a/cpp/src/compilation/advanced.h b/cpp/src/compilation/advanced.h new file mode 100644 index 0000000..c829320 --- /dev/null +++ b/cpp/src/compilation/advanced.h @@ -0,0 +1,47 @@ +/* + * File: InstructionsAdvanced.h + * Author: pgess + * + * Created on June 26, 2016, 6:00 PM + */ + +#ifndef INSTRUCTIONSADVANCED_H +#define INSTRUCTIONSADVANCED_H + +#include "ast.h" +#include "llvmlayer.h" +#include "pass/compilepass.h" + +#include + +namespace xreate { + namespace compilation { + +class Advanced { +public: + Advanced(compilation::Context ctx); + llvm::Value* compileArrayIndex(const Symbol &dataSymbol, std::vector indexes, std::string ident = ""); + llvm::Value* compileStructIndex(llvm::Value* aggregate, const ExpandedType& t, const std::string& idx); + /* + * - map Computation -> Llvm_Array: Prohibited, we do not know a result size + * - map Llvm_Array -> Computation: considered in `compileGetElement` + * - map Llvm_Array -> Llvm_Array considered by this method + */ + llvm::Value* compileMapSolid(const Expression &expr, const std::string hintRetVar = ""); + llvm::Value* compileFold(const Expression& fold, const std::string& ident=""); + llvm::Value* compileFoldInf(const Expression& fold, const std::string& ident=""); + llvm::Value* compileLoopContext(const Expression& expression, const std::string& hintRetVar); + llvm::Value* compileIf(const Expression& exprIf, const std::string& ident); + llvm::Value* compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar); + llvm::Value* compileConstantStringAsPChar(const std::string &data, const std::string& hintRetVar); + llvm::Value* compileConstantArray(const Expression &expr, const std::string& hintRetVar=""); + +private: + compilation::Context context; + llvm::IntegerType* const tyNum; +}; + +}} + +#endif /* INSTRUCTIONSADVANCED_H */ + diff --git a/cpp/src/compilation/containers.cpp b/cpp/src/compilation/containers.cpp new file mode 100644 index 0000000..30a4c5b --- /dev/null +++ b/cpp/src/compilation/containers.cpp @@ -0,0 +1,22 @@ +#include "compilation/containers.h" + +using namespace std; +using namespace llvm; +using namespace xreate; +using namespace xreate::containers; + +Iterator* +Iterator::create(xreate::compilation::Context context, const xreate::Symbol& var){ + + const Implementation& data = Query::queryImplementation(var); + + switch(data.impl){ + case ON_THE_FLY: + return new IteratorForward(context, var, data.extract()); + + default: assert(true); + } + + assert(false && "Unknown declaration"); + return nullptr; +} diff --git a/cpp/src/compilation/containers.h b/cpp/src/compilation/containers.h new file mode 100644 index 0000000..e54334a --- /dev/null +++ b/cpp/src/compilation/containers.h @@ -0,0 +1,187 @@ +#ifndef CODEINSTRUCTIONS_H +#define CODEINSTRUCTIONS_H + +#include "ast.h" + +#include "llvmlayer.h" +#include "pass/compilepass.h" +#include "compilation/advanced.h" + +#include "query/context.h" +#include "query/containers.h" +#include "query/ptrvalid.h" + +namespace xreate { + namespace containers { + +using namespace llvm; + +class Iterator{ +public : + virtual llvm::Value* begin() =0; + virtual llvm::Value* end() = 0; + virtual llvm::Value* get(llvm::Value* index,const std::string& hintRetVar="") = 0; + virtual llvm::Value* advance(llvm::Value* index, const std::string& hintRetVar="")=0; + virtual ~Iterator(){}; + + static Iterator* create(xreate::compilation::Context context, const xreate::Symbol& var); +}; + +template +class IteratorForward; + +template<> +class IteratorForward : public Iterator { +private: + LLVMLayer* llvm; + const xreate::Symbol current; + const Symbol source; + const ImplementationLinkedList linkedlist; + CodeScope* const sourceScope; + //TODO initialize ans mark as const (three fields) + compilation::CodeScopeUnit* sourceUnit; + compilation::FunctionUnit* function; //TODO is used somewhere? + const Expression& sourceDecl; + compilation::Context context; + llvm::Type* sourceRawType =nullptr; + +public: + IteratorForward(compilation::Context ctx, const xreate::Symbol& s, const ImplementationRec& implementation) + : llvm(ctx.pass->man->llvm), current(s), source(implementation.source), linkedlist(source), sourceScope(source.scope), sourceUnit(new compilation::CodeScopeUnit(source.scope, ctx.function, ctx.pass)), + sourceDecl(CodeScope::findDeclaration(source)), + context(ctx) + { + } + + llvm::Value* begin() { + switch(sourceDecl.op) { + case xreate::Operator::LIST: + { + sourceRawType = llvm::Type::getInt32Ty(llvm::getGlobalContext()); + return llvm::ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), 0); + }; + + case xreate::Operator::LIST_RANGE:{ + assert(sourceDecl.operands.size()==2); + + llvm::Value* result = sourceUnit->process(sourceDecl.operands.at(0)); + sourceRawType = result->getType(); + + return result; + }; + + default: break; + } + + if (linkedlist){ + llvm::Value* result = sourceUnit->process(sourceDecl); + sourceRawType = result->getType(); + return result; + } + + assert(false); + } + + llvm::Value* end(){ + switch(sourceDecl.op) { + case xreate::Operator::LIST: { + size_t idLast = sourceDecl.operands.size() - 1; + return ConstantInt::get(sourceRawType, idLast); + } + + case xreate::Operator::LIST_RANGE: { + assert(sourceDecl.operands.size() == 2); + llvm::Value* valueEndOfRange = sourceUnit->process(sourceDecl.operands.at(1)); + llvm::Value* valueConstOne = llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 1); + + return llvm->builder.CreateAdd(valueEndOfRange, valueConstOne); + }; + + default: break; + } + + //return null pointer + if (linkedlist){ + return ConstantPointerNull::getNullValue(sourceRawType); + } + + assert(false && "Unknown declaration"); + return nullptr; + } + + llvm::Value* get(Value* index,const std::string& hintRetVar="") override{ + const Expression& currentDecl = CodeScope::findDeclaration(current); + + switch (currentDecl.op) { + case xreate::Operator::LIST: { + //TODO re check is it right scope(source) to compile currentDecl. Provide unittests. + //llvm::Value* currentValue = sourceUnit->process(currentDecl); + return xreate::compilation::Advanced(context).compileArrayIndex(current, std::vector{index}); + }; + + case xreate::Operator::LIST_RANGE: { + return index; + }; + + case xreate::Operator::MAP: { + assert(currentDecl.getOperands().size()==1); + assert(currentDecl.bindings.size()); + assert(currentDecl.blocks.size()); + + CodeScope* scopeLoop = currentDecl.blocks.front(); + const std::string& varIn = currentDecl.getOperands()[0].getValueString(); + std::string varEl = currentDecl.bindings[0]; + + const Symbol& symbIn = current.scope->findSymbol(varIn); + auto it = std::unique_ptr(Iterator::create(context, symbIn)); + + Value* elIn = it->get(index, varEl); + compilation::CodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); + unitLoop->bindArg(elIn, std::move(varEl)); + return unitLoop->compile(); + } + + case xreate::Operator::NONE: { + //TODO review iterator determination strategy for case of Expression::BINDING + assert(currentDecl.__state==Expression::IDENT); + const Symbol& symbIn = current.scope->findSymbol(currentDecl.getValueString()); + auto it = std::unique_ptr(Iterator::create(context, symbIn)); + return it->get(index); + }; + + default: break; + } + + if (linkedlist){ + return index; + } + + assert(false && "Unknown declaration"); + return nullptr; + } + + llvm::Value* advance(Value* index, const std::string& hintRetVar) override{ + switch(sourceDecl.op) + { + case xreate::Operator::LIST: + case xreate::Operator::LIST_RANGE: + return llvm->builder.CreateAdd(index, llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 1), hintRetVar); + + default: break; + } + + if (linkedlist){ + ExpandedType tySource = llvm->ast->expandType(CodeScope::findDeclaration(source).type); + assert(tySource->__operator == TypeOperator::ARRAY && "Linked list implementation has to have ARRAY type"); + assert(tySource->__operands.size()); + + return xreate::compilation::Advanced(context).compileStructIndex(index, ExpandedType(TypeAnnotation(tySource->__operands.at(0))), linkedlist.fieldPointer); + } + + assert(false && "Unknown declaration"); + return nullptr; + } +}; +}} + +#endif //CODEINSTRUCTIONS_H diff --git a/cpp/src/compilation/instr-containers.h b/cpp/src/compilation/instr-containers.h deleted file mode 100644 index 9fe4a08..0000000 --- a/cpp/src/compilation/instr-containers.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef CODEINSTRUCTIONS_H -#define CODEINSTRUCTIONS_H - -#include "llvmlayer.h" -#include "ast.h" -#include -#include -#include "pass/compilepass.h" - -namespace xreate { - namespace containers { - -class Iterator{ -public : - virtual llvm::Value* begin() =0; - virtual llvm::Value* end() = 0; - virtual llvm::Value* get(llvm::Value* index,const std::string& hintRetVar="") = 0; - virtual llvm::Value* move(llvm::Value* index, const std::string& hintRetVar="")=0; - virtual ~Iterator(){}; - - static Iterator* create(compilation::Context context, const Symbol& var); -}; - -class Instructions { -public: - Instructions(compilation::Context ctx); - llvm::Value* compileArrayIndex(const Symbol &dataSymbol, std::vector indexes, std::string ident = ""); - llvm::Value* compileStructIndex(llvm::Value* aggregate, const ExpandedType& t, const std::string& idx); - /* - * - map Computation -> Llvm_Array: Prohibited, we do not know a result size - * - map Llvm_Array -> Computation: considered in `compileGetElement` - * - map Llvm_Array -> Llvm_Array considered by this method - */ - llvm::Value* compileMapSolid(const Expression &expr, const std::string hintRetVar = ""); - llvm::Value* compileFold(const Expression& fold, const std::string& ident=""); - llvm::Value* compileLoopContext(const Expression& expression, const std::string& hintRetVar); - llvm::Value* compileIf(const Expression& exprIf, const std::string& ident); - llvm::Value* compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar); - llvm::Value* compileConstantStringAsPChar(const string &data, const std::string& hintRetVar); - llvm::Value* compileConstantArray(const Expression &expr, const std::string& hintRetVar=""); - -private: - compilation::Context context; - llvm::IntegerType* const tyNum; -}; - - - - }} - -#endif //CODEINSTRUCTIONS_H - -/* - template - struct InstructionClasses {}; - - template<> - struct InstructionClasses { - typedef InstructionList Impl; - }; - - template<> - struct InstructionClasses { - typedef InstructionMap Impl; - }; - - template - class CodeInstruction: public InstructionClasses::Impl - { - typedef typename InstructionClasses::Impl InstructionImpl; - - public: - CodeInstruction(CodeScope* parent) - : InstructionImpl(parent) - {} - - llvm::Value * - compileExpression(const Expression &expr, LLVMLayer &l, const std::string * const hintRetVar) - { - if (expr.op == Instruction) - return InstructionImpl::compileDefault(expr, l, hintRetVar); - - return CodeScope::compileExpression(expr, l, hintRetVar); - } - }; -} -*/ diff --git a/cpp/src/compilation/latecontextcompiler2.cpp b/cpp/src/compilation/latecontextcompiler2.cpp index 5dccbc0..915f57b 100644 --- a/cpp/src/compilation/latecontextcompiler2.cpp +++ b/cpp/src/compilation/latecontextcompiler2.cpp @@ -1,119 +1,192 @@ /* * LateContextCompiler2.cpp * * Created on: 10 февр. 2016 * Author: pgess */ +//TOTEST default variants - do not enable specialization context in order to check default variant invocation + #include "latecontextcompiler2.h" #include "llvmlayer.h" #include "pass/compilepass.h" #include "query/context.h" #include -namespace xreate { - -LateContextCompiler2::LateContextCompiler2(compilation::FunctionUnit* f, CompilePass* p) - : function(f), pass(p){} - -//TEST default variants - do not enable specialization context in order to check default variant invocation -llvm::Value* -LateContextCompiler2::findFunction(const std::string& calleeName, llvm::Function* specializationDefault){ - LLVMLayer* llvm = pass->man->llvm; - llvm::IRBuilder<>& builder = llvm->builder; - ContextQuery* context = pass->queryContext; - const string& functionName = function->function->getName(); - - const std::list& specializations = pass->man->root->getFunctionVariants(calleeName); - const FunctionContextDemand& decisions = context->getFunctionDemand(functionName); - - assert(decisions.right.count(calleeName) && "Can't determine specialization of the function"); - size_t decisionIndex = decisions.right.at(calleeName); - const ContextDomain& decisionDomain= context->getFunctionDomain(calleeName); - - llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); - llvm::Type* tyCallee = specializationDefault->getType(); - - llvm::BasicBlock* blockDefault = llvm::BasicBlock::Create(llvm::getGlobalContext(), "caseDefault", this->function->raw); - - llvm::Value* decisionRaw = builder.CreateExtractValue(this->raw, llvm::ArrayRef{decisionIndex}); - llvm::SwitchInst* instrSwitch = builder.CreateSwitch(decisionRaw, blockDefault, decisionDomain.size()); - - llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ContextDeterminationEnd", this->function->raw); - builder.SetInsertPoint(blockEpilog); - llvm::PHINode *ret = llvm->builder.CreatePHI(tyCallee, decisionDomain.size(), "callee"); - - for (const ManagedFnPtr& f: specializations){ - if (!f->guardContext.isValid()) continue; - const Code& specCode = decisionDomain.getId(f->guardContext); - llvm::ConstantInt* rawSpecCode = llvm::ConstantInt::get(ty32, specCode); +using namespace std; - llvm::BasicBlock* blockCase = llvm::BasicBlock::Create(llvm::getGlobalContext(), "case+" + f->guardContext.getValueString(), this->function->raw); - builder.SetInsertPoint(blockCase); - builder.CreateBr(blockEpilog); - ret->addIncoming(pass->getFunctionUnit(f)->compile(), blockCase); +namespace xreate { - instrSwitch->addCase(rawSpecCode, blockCase); - } +const string topicSpecializationAtom = "specialization"; +const string topicDependencyAtom = "dependency"; - //prepare default specialization - builder.SetInsertPoint(blockDefault); - builder.CreateBr(blockEpilog); - ret->addIncoming(specializationDefault, blockDefault); +LateContextCompiler2::LateContextCompiler2(compilation::FunctionUnit* f, CompilePass* p) + : function(f), pass(p){ + + ContextQuery* context = pass->queryContext; + __sizeOfDemand = context->getFunctionDemand(function->function->getName()).size(); +} - builder.SetInsertPoint(blockEpilog); - return ret; +llvm::Function* +LateContextCompiler2::findFunction(const std::string& calleeName, llvm::Function* specializationDefault, ScopePacked scopeCaller){ + const string& functionName = function->function->getName(); + ContextQuery* context = pass->queryContext; + llvm::IRBuilder<>& builder = pass->man->llvm->builder; + + const FunctionDemand& demand = context->getFunctionDemand(functionName); + const std::list& specializations = pass->man->root->getFunctionVariants(calleeName); + + //independent decision: + Expression topic(Operator::CALL, {(Atom(string(topicSpecializationAtom))), (Atom(string(calleeName))), (Atom(scopeCaller))}); + assert(demand.right.count(topic) && "Can't determine specialization for the function"); + size_t topicId = demand.right.at(topic); + llvm::Value* topicDecisionRaw = builder.CreateExtractValue(this->rawContextArgument, llvm::ArrayRef{(unsigned) topicId}); + + const Domain& specializationsDomain= context->getTopicDomain(topic); + + std::vector vectorVariants; + vectorVariants.reserve(specializationsDomain.size()); + for (const ManagedFnPtr& f: specializations){ + if (!f->guardContext.isValid()) continue; + const auto& variantId = specializationsDomain.getIdOptional(f->guardContext); + if (variantId){ + if (vectorVariants.size() < *variantId + 1) { + vectorVariants.resize(*variantId + 1); + } + + vectorVariants[*variantId] = pass->getFunctionUnit(f)->compile(); + } + } + + return + llvm::dyn_cast( + compileDecisionSelectorAsSwitch(topicDecisionRaw, vectorVariants, specializationDefault)); } llvm::Value* -LateContextCompiler2::compileArgument(const std::string& callee, ScopePacked scopeOuter){ - llvm::IRBuilder<>& builder = pass->man->llvm->builder; - ContextQuery* context = pass->queryContext; - const string& functionName = function->function->getName(); - const map& dictStaticDecisions = context->getStaticDecisions(scopeOuter); - - const FunctionContextDemand& decisionsCallee = context->getFunctionDemand(callee); - const FunctionContextDemand& decisionsSelf = context->getFunctionDemand(functionName); - - llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); - llvm::Type* tyDemand = llvm::ArrayType::get(ty32, decisionsCallee.size()); - - //builder.CreateAlloca(tyDemand, llvm::ConstantInt::get(ty32, 1)); - llvm::Value* res = llvm::ConstantArray::getNullValue(tyDemand); +LateContextCompiler2::compileContextArgument(const std::string& callee, ScopePacked scopeCaller){ + const std::string& atomDependentDecision = Config::get("clasp.context.decisions.dependent"); + llvm::IRBuilder<>& builder = pass->man->llvm->builder; + ContextQuery* context = pass->queryContext; + + const string& functionName = function->function->getName(); + const Decisions& dictStaticDecisions = context->getFinalDecisions(scopeCaller); + + const FunctionDemand& demandCallee = context->getFunctionDemand(callee); + const FunctionDemand& demandSelf = context->getFunctionDemand(functionName); + + llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); + llvm::Type* tyDemand = llvm::ArrayType::get(ty32, demandCallee.size()); + + //builder.CreateAlloca(tyDemand, llvm::ConstantInt::get(ty32, 1)); + llvm::Value* res = llvm::ConstantArray::getNullValue(tyDemand); + + for (size_t i=0, size = demandCallee.size(); irawContextArgument, llvm::ArrayRef{(unsigned) topicId}); + + } else if (dictStaticDecisions.count(topic)){ + //static final decision: + const Expression& decision = dictStaticDecisions.at(topic); + const Domain& domainOfTopic = context->getTopicDomain(topic); + const DomainId& decisionCode = domainOfTopic.getId(decision); + decisionRaw = llvm::ConstantInt::get(ty32, decisionCode); + + } else { + //dependent decision + decisionRaw = compileDependentDecision(topic, scopeCaller); + } + + res = builder.CreateInsertValue(res, decisionRaw, llvm::ArrayRef{(unsigned) i}); + } + + return res; +} - for (size_t i=0, size = decisionsCallee.size(); ifunction->getName(); + ContextQuery* context = pass->queryContext; + llvm::IRBuilder<>& builder = pass->man->llvm->builder; + llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); + + const FunctionDemand& demandSelf = context->getFunctionDemand(functionName); + const Expression topicDependency = Expression(Operator::CALL, {Atom(string(topicDependencyAtom)), topic, Atom(scopeCaller)}); + + const Domain& demandOfTopic = context->getTopicDomain(topic); + const Domain& domainOfTopicDependency = context->getTopicDomain(topicDependency); + + //dependent decision + vector vectorDecisions(domainOfTopicDependency.size(), llvm::UndefValue::get(ty32)); + for (const std::pair& entry: context->getDependentDecision(scopeCaller,topic)){ + vectorDecisions[domainOfTopicDependency.getId(entry.first)]= llvm::ConstantInt::get(ty32, demandOfTopic.getId(entry.second)); + } + + size_t topicDependencyId = demandSelf.right.at(topicDependency); + llvm::Value* decisionRaw = builder.CreateExtractValue(this->rawContextArgument, llvm::ArrayRef{(unsigned) topicDependencyId}); + + auto result = compileDecisionSelector(decisionRaw, vectorDecisions); + + return result; +} - if (dictStaticDecisions.count(key)){ - const Expression& decision = dictStaticDecisions.at(key); - const Domain& dom = context->getFunctionDomain(key); - const Code& decisionCode = dom.getId(decision); +llvm::Value* +LateContextCompiler2::compileDecisionSelector(llvm::Value* selector, std::vector vectorVariants, llvm::Value* variantDefault){ + //TODO implement variantDefault; + assert(vectorVariants.size()>0); + llvm::IRBuilder<>& builder = pass->man->llvm->builder; + llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); - res = builder.CreateInsertValue(res, llvm::ConstantInt::get(ty32, decisionCode), llvm::ArrayRef{i}); - continue; - } + llvm::Type* tyElement = vectorVariants[0]->getType(); + llvm::Type* tyVariants = llvm::VectorType::get(tyElement, vectorVariants.size()); + llvm::Value* vectorRaw = llvm::ConstantVector::getNullValue(tyVariants); + - //TEST decision propagtion - const size_t& decisionIndex = decisionsSelf.right.at(key); - llvm::Value* decision = builder.CreateExtractValue(this->raw, llvm::ArrayRef{decisionIndex}); - res = builder.CreateInsertElement(res, llvm::ConstantInt::get(ty32, i), decision); - } + for(DomainId i=0; iqueryContext; - - return context->getFunctionDomain(function->function->getName()).size(); +llvm::Value* +LateContextCompiler2::compileDecisionSelectorAsSwitch(llvm::Value* selector, std::vector vectorVariants, llvm::Value* variantDefault){ + llvm::IRBuilder<>& builder = pass->man->llvm->builder; + llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); + + llvm::BasicBlock* blockDefault = llvm::BasicBlock::Create(llvm::getGlobalContext(), "caseDefault", this->function->raw); + llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "VariantDeterminationEnd", this->function->raw); + + llvm::SwitchInst* instrSwitch = builder.CreateSwitch(selector, blockDefault, vectorVariants.size()); + + builder.SetInsertPoint(blockEpilog); + llvm::PHINode *result = builder.CreatePHI(variantDefault->getType(), vectorVariants.size(), "callee"); + + for (size_t i=0; ifunction->raw); + builder.SetInsertPoint(blockCase); + builder.CreateBr(blockEpilog); + result->addIncoming(vectorVariants[i], blockCase); + instrSwitch->addCase(llvm::ConstantInt::get(ty32, i), blockCase); + } + + builder.SetInsertPoint(blockDefault); + builder.CreateBr(blockEpilog); + result->addIncoming(variantDefault, blockDefault); + + builder.SetInsertPoint(blockEpilog); + return result; } size_t LateContextCompiler2::getFunctionDemandSize() const { - ContextQuery* context = pass->queryContext; - - return context->getFunctionDemand(function->function->getName()).size(); + return __sizeOfDemand; } } /* namespace xreate */ diff --git a/cpp/src/compilation/latecontextcompiler2.h b/cpp/src/compilation/latecontextcompiler2.h index 4ef802a..791d8d4 100644 --- a/cpp/src/compilation/latecontextcompiler2.h +++ b/cpp/src/compilation/latecontextcompiler2.h @@ -1,50 +1,54 @@ /* * LateContextCompiler2.h * * Created on: 10 февр. 2016 * Author: pgess */ +//TOTEST compile several context arguments #ifndef LATECONTEXTCOMPILER2_H_ #define LATECONTEXTCOMPILER2_H_ #include "serialization.h" namespace llvm { class Value; class Function; } namespace xreate { class CompilePass; namespace compilation { class FunctionUnit; }} namespace xreate { typedef unsigned int ScopePacked; class LateContextCompiler2 { public: - llvm::Value* raw = nullptr; + llvm::Value* rawContextArgument = nullptr; LateContextCompiler2(compilation::FunctionUnit* f, CompilePass* p); - llvm::Value* findFunction(const std::string& calleeName, llvm::Function* specializationDefault); - llvm::Value* compileArgument(const std::string& callee, ScopePacked scopeOuter); - size_t getFunctionVariantsSize() const; - size_t getFunctionDemandSize() const; + llvm::Function* findFunction(const std::string& calleeName, llvm::Function* specializationDefault, ScopePacked scopeCaller); + llvm::Value* compileContextArgument(const std::string& callee, ScopePacked scopeCaller); + size_t getFunctionDemandSize() const; private: - typedef ExpressionSerialization::Code Code; + typedef ExpressionSerialization::Code DomainId; typedef ExpressionSerialization::Serializer Domain; //boost::bimap __decisions; //std::vector __scheme; compilation::FunctionUnit* function; CompilePass* pass; + size_t __sizeOfDemand; + + llvm::Value* compileDependentDecision(const Expression& topic, ScopePacked scopeCaller); + llvm::Value* compileDecisionSelector(llvm::Value* selector, std::vector vectorVariants, llvm::Value* variantDefault=nullptr); + llvm::Value* compileDecisionSelectorAsSwitch(llvm::Value* selector, std::vector vectorVariants, llvm::Value* variantDefault); }; - } /* namespace xreate */ #endif /* LATECONTEXTCOMPILER2_H_ */ diff --git a/cpp/src/compilation/targetinterpretation.cpp b/cpp/src/compilation/targetinterpretation.cpp new file mode 100644 index 0000000..fceda31 --- /dev/null +++ b/cpp/src/compilation/targetinterpretation.cpp @@ -0,0 +1,354 @@ +/* + * File: targetinterpretation.cpp + * Author: pgess + * + * Created on June 29, 2016, 6:45 PM + */ + +#include "compilation/targetinterpretation.h" +#include "pass/interpretationpass.h" + +using namespace std; + +namespace xreate{ namespace compilation { + + const Expression EXPRESSION_FALSE = Expression(Atom(0)); + const Expression EXPRESSION_TRUE = Expression(Atom(1)); + +//Expression +//InterpretationScope::compile(const Expression& expression){} + +CodeScope* +InterpretationScope::processOperatorIf(const Expression& expression){ + const Expression& exprCondition = process(expression.getOperands()[0]); + + if (exprCondition == EXPRESSION_TRUE){ + return expression.blocks.front(); + } + + return expression.blocks.back(); +} + +CodeScope* +InterpretationScope::processOperatorSwitch(const Expression& expression) { + const Expression& exprCondition = process(expression.operands[0]); + + bool flagHasDefault = expression.operands[1].op == Operator::CASE_DEFAULT; + + //TODO check that one and only one case variant is appropriate + for (size_t size = expression.operands.size(), i= flagHasDefault? 2: 1; igetScope(exprCase.blocks.front())->processScope() == exprCondition){ + return exprCase.blocks.back(); + } + } + + if (flagHasDefault){ + const Expression& exprCaseDefault = expression.operands[1]; + return exprCaseDefault.blocks.front(); + } + + assert(false && "Switch has no appropriate variant"); + return nullptr; +} + +llvm::Value* +InterpretationScope::compileHybrid(const InterpretationOperator& op, const Expression& expression, const Context& context){ + switch(op){ + case IF_INTERPRET_CONDITION: { + CodeScope* scopeResult = processOperatorIf(expression); + + llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); + return result; + } + + case SWITCH_INTERPRET_CONDITION:{ + CodeScope* scopeResult = processOperatorSwitch(expression); + + llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); + return result; + } + + case FOLD_INTERPRET_INPUT: { + //initialization + const Expression& exprInput = process(expression.getOperands()[0]); + assert(exprInput.op == Operator::LIST); + + CodeScope* scopeBody = expression.blocks.front(); + + const string& nameEl = expression.bindings[0]; + const Symbol& symbolEl = scopeBody->findSymbol(nameEl); + const std::string& idAccum = expression.bindings[1]; + llvm::Value* rawAccum = context.scope->process(expression.getOperands()[1]); + compilation::CodeScopeUnit* unitBody = context.function->getScopeUnit(scopeBody); + InterpretationScope* intrBody = function->getScope(scopeBody); + const std::vector elementsInput= exprInput.getOperands(); + + for (size_t i=0; ireset(); + + intrBody->bindArg(exprElement, nameEl); + unitBody->overrideDeclaration(symbolEl, move(exprElement)); + unitBody->bindArg(rawAccum, string(idAccum)); + + rawAccum = unitBody->compile(); + } + + return rawAccum; + } + + default: break; + } + + assert(false&& "Unknown hybrid operator"); + return nullptr; +} + +llvm::Value* +InterpretationScope::compile(const Expression& expression, const Context& context){ + const InterpretationData& data = Attachments::get(expression); + + if (data.op != InterpretationOperator::NONE){ + return compileHybrid(data.op, expression, context); + } + + Expression result = process(expression); + return context.scope->processLowlevel(result); +} + +Expression +InterpretationScope::process(const Expression& expression){ + switch (expression.__state){ + case Expression::VARIANT: + case Expression::INVALID: + assert(false); + + case Expression::NUMBER: + case Expression::STRING: + return expression; + + case Expression::IDENT:{ + const std::string &ident = expression.getValueString(); + + Symbol s = scope->findSymbol(ident); + return Parent::processSymbol(s); + } + + case Expression::COMPOUND: + break; + + default: assert(false); + } + + switch (expression.op) { + case Operator::EQU: { + const Expression& left = process(expression.operands[0]); + const Expression& right = process(expression.operands[1]); + + if (left == right) return EXPRESSION_TRUE; + return EXPRESSION_FALSE; + } + + case Operator::NE: { + const Expression& left = process(expression.operands[0]); + const Expression& right = process(expression.operands[1]); + + if (left == right) return EXPRESSION_FALSE; + return EXPRESSION_TRUE; + } + + case Operator::LOGIC_AND: { + assert(expression.operands.size() == 1); + return process (expression.operands[0]); + } + + +// case Operator::LOGIC_OR: + case Operator::CALL: { + const std::string &fnName = expression.getValueString(); + ManagedFnPtr fnAst = this->function->man->ast->findFunction(fnName); + InterpretatonFunction* fnUnit = this->function->man->getFunction(fnAst); + + vector args; + args.reserve(expression.getOperands().size()); + + for(size_t i=0, size = expression.getOperands().size(); iprocess(args); + } + + case Operator::IF:{ + CodeScope* scopeResult = processOperatorIf(expression); + return function->getScope(scopeResult)->processScope(); + } + + case Operator::SWITCH: { + CodeScope* scopeResult = processOperatorSwitch(expression); + return function->getScope(scopeResult)->processScope(); + } + + case Operator::INDEX: { + const Expression& exprKey = process(expression.operands[0]); + const Expression& exprData = processSymbol(scope->findSymbol(expression.getValueString())); + + + if (exprKey.__state == Expression::STRING){ + const string& key = exprKey.getValueString(); + assert(exprData.__indexBindings.count(key)); + + return exprData.operands[exprData.__indexBindings.at(key)]; + } + + if (exprKey.__state == Expression::NUMBER){ + int key = exprKey.getValueDouble(); + return exprData.operands[key]; + } + + assert(false); + } + + case Operator::FOLD: { + const Expression& exprInput = process(expression.getOperands()[0]); + const Expression& exprInit = process(expression.getOperands()[1]); + + const std::string& argEl = expression.bindings[0]; + const std::string& argAccum = expression.bindings[1]; + + InterpretationScope* body = function->getScope(expression.blocks.front()); + + Expression accum = exprInit; + for(size_t size=exprInput.getOperands().size(), i=0; ibindArg(exprInput.getOperands()[i], argEl); + body->bindArg(accum, argAccum); + + accum = body->processScope(); + } + + return accum; + } + +// case Operator::MAP: { +// break; +// } + + default: break; + } + + return expression; +} + +InterpretatonFunction::InterpretatonFunction(const ManagedFnPtr& function, Target* target) + : Function(function, target) +{} + +Expression +InterpretatonFunction::process(const std::vector& args){ + InterpretationScope* body = getScope(__function->__entry); + + for(size_t i=0, size = args.size(); ibindArg(args.at(i), string(body->scope->__bindings.at(i))); + } + + return body->processScope(); +} + +InterpretatonFunction* +TargetInterpretation::getFunction(const PIFSignature& sig){ + return __functions.find(sig); +} + +InterpretationScope* +TargetInterpretation::transformContext(const Context& c){ + return this->getFunction(c.function->function)->getScope(c.scope->scope); +} + +llvm::Value* +TargetInterpretation::transform(const Expression& expression, llvm::Value* raw, const Context& ctx){ + return raw; +} + +Expression +TargetInterpretation::transform(const Expression& expression, const Context& ctx){ + return transformContext(ctx)->process(expression); +} + +llvm::Value* +TargetInterpretation::compile(const Expression& expression, const Context& ctx){ + return transformContext(ctx)->compile(expression, ctx); +} + +bool +TargetInterpretation::isAcceptable(const Expression& expression){ + const InterpretationData& data = Attachments::get(expression, {BOTH, NONE}); + + return (data.resolution == INTR_ONLY || data.op != InterpretationOperator::NONE); +} + +}} + + //Partial function interpretation +llvm::Value* +InterpretationScope::compilePartialFnCall(const Expression& expression, const Context& context){ + const std::string &fnName = expression.getValueString(); + ManagedFnPtr fnAst = this->function->man->ast->findFunction(fnName); + context.pass->getFunctionUnit(fnAst) + + intrBody->bindArg(exprElement, nameEl); + unitBody->overrideDeclaration(symbolEl, move(exprElement)); +} + +class PartialInterpretationScopeDecorator(){ + void compile(){ + + } + + void findFunction(){ + + } +}; + +template +class PartialInterpretationFunctionDecorator: public Parent{ + +protected: + void recognizeArguments(){ + argsReal.reserve(entry->__bindings.size()); + + for(size_t no=0, size=entry->__bindings.size(); no < size; ++no){ + const std::string& argName = entry->__bindings[no]; + const Expression& arg = entry->findDeclaration(entry->findSymbol(argName)); + + InterpretationResolution res = recognizeTags(arg.tags); + if (res != INTR_ONLY){ + argsReal.push_back(arg); + } + } + } + + std::vector prepareArguments(){ + std::vector signature; + + for(size_t no=0, size=argsReal.size(); no < size; ++no){ + signature.push_back(llvm->toLLVMType(ast->expandType(argsReal[no].type))); + } + } + + void prepareBindings(){ + // bindings from argsReal + } + +private: + std::vector argsReal; +}; + +template +class PartialInterpretationCallStatement: public Parent { + PartialInterpretationCallStatement(){ + + } +} \ No newline at end of file diff --git a/cpp/src/compilation/targetinterpretation.h b/cpp/src/compilation/targetinterpretation.h new file mode 100644 index 0000000..94c44d8 --- /dev/null +++ b/cpp/src/compilation/targetinterpretation.h @@ -0,0 +1,100 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +/* + * File: targetstatic.h + * Author: pgess + * + * Created on July 2, 2016, 1:25 PM + */ + +#ifndef TARGETSTATIC_H +#define TARGETSTATIC_H + +#include "ast.h" +#include "compilation/targets.h" +#include "transformations.h" +#include "pass/interpretationpass.h" + +namespace xreate{ namespace compilation { + +class TargetInterpretation; +class InterpretationScope; +class InterpretatonFunction; + + template <> + struct TargetInfo { + typedef Expression Result; + typedef InterpretationScope Scope; + typedef InterpretatonFunction Function; + }; + + template<> + struct TransformerInfo { + static const int id = 1; + }; + +class InterpretationScope: public Scope{ + typedef Scope Parent; + +public: + InterpretationScope(CodeScope* scope, Function* f): Parent(scope, f) {} + Expression process(const Expression& expression) override; + + llvm::Value* compile(const Expression& expression, const Context& context); + +private: + llvm::Value* compileHybrid(const InterpretationOperator& op, const Expression& expression, const Context& context); + llvm::Value* compilePartialFnCall(const Expression& expression, const Context& context); + + CodeScope* processOperatorIf(const Expression& expression); + CodeScope* processOperatorSwitch(const Expression& expression); + +}; + +class InterpretatonFunction: public Function{ + public: + PIFSignature signature; + + InterpretatonFunction(const ManagedFnPtr& function, Target* target); + Expression process(const std::vector& args); +}; + +/* + * Partially interpreted function signature + */ +struct PIFSignature{ + ManagedFnPtr declaration; + std::vector bindings; +}; + +class TargetInterpretation: public Transformer, public Target{ +public: + TargetInterpretation(AST* root): Target(root){} + + //transformer: +public: + virtual llvm::Value* transform(const Expression& expression, llvm::Value* raw, const Context& ctx) override; + virtual Expression transform(const Expression& expression, const Context& ctx) override; + virtual bool isAcceptable(const Expression& expression) override; + + //target: +public: + InterpretatonFunction* getFunction(const ManagedFnPtr& function); +private: + std::set __functions; + + //self: +public: + llvm::Value* compile(const Expression& expression, const Context& ctx); +private: + InterpretationScope* transformContext(const Context& c); +}; + +}} + +#endif /* TARGETSTATIC_H */ + diff --git a/cpp/src/compilation/targets.h b/cpp/src/compilation/targets.h new file mode 100644 index 0000000..fb10bec --- /dev/null +++ b/cpp/src/compilation/targets.h @@ -0,0 +1,146 @@ +/* + * File: targetabstract.h + * Author: pgess + * + * Created on July 2, 2016, 1:25 PM + */ + +#ifndef TARGETABSTRACT_H +#define TARGETABSTRACT_H +#include "ast.h" + +#include +#include + +namespace xreate{ namespace compilation { + +template +struct TargetInfo{ + //typedef Result + //typedef Function + //typedef Scope +}; + +template +class Function; + +template +class Target; + +template +class Scope{ +public: + CodeScope* scope; + + typename TargetInfo::Result + processSymbol(const Symbol& s){ + CodeScope* scope = s.scope; + typename TargetInfo::Scope* self = function->getScope(scope); + + if (self->__bindings.count(s.identifier)) { + return self->__bindings[s.identifier]; + } + + const Expression& declaration = CodeScope::findDeclaration(s); + if (!declaration.isDefined()){ + assert(false); //for bindings there should be result already + } + + return self->__bindings[s.identifier] = self->process(declaration); + } + + typename TargetInfo::Result + processScope() { + if (raw) return *raw; + + raw = process(scope->__body); + return *raw; + } + + virtual typename TargetInfo::Result + process(const Expression& expression)=0; + + Scope(CodeScope* codeScope, Function* f) + : scope(codeScope), function(f) {} + + virtual ~Scope(){} + + void + bindArg(typename TargetInfo::Result arg, const std::string& name){ + assert(scope->__identifiers.count(name)); + + VID id = scope->__identifiers.at(name); + __bindings[id] = arg; + + //reset the result if any: + raw.reset(); + } + +protected: + Function* function; + std::map::Result> __bindings; + typename boost::optional::Result> raw; + + //ResultType findFunction(const std::string& callee); +}; + +template +class Function{ + typedef typename TargetInfo::Result Result; + +public: + Function(const ManagedFnPtr& function, Target* target) + : man(target), __function(function) {} + + typename TargetInfo::Scope* + getScope(CodeScope* scope){ + if (!__scopes.count(scope)){ + typename TargetInfo::Scope* unit = new typename TargetInfo::Scope(scope, this); + __scopes.emplace(scope, std::unique_ptr::Scope>(unit)); + } + + return __scopes.at(scope).get(); + } + + virtual Result + process(const std::vector& args)=0; + + Target* man; + +protected: + ManagedFnPtr __function; + + + std::map::Scope>> __scopes; +}; + +template +class Target { + typedef typename TargetInfo::Function ConcreteFunction; + + public: + Target(AST* root): ast(root){} + + ConcreteFunction* + getFunction(const ManagedFnPtr& function){ + unsigned int id = function.id(); + + if (!__functions.count(id)){ + ConcreteFunction* unit = new ConcreteFunction(function, this); + __functions.emplace(id, std::unique_ptr(unit)); + return unit; + } + + return __functions.at(id).get(); + } + + AST* ast; + + private: + std::map> __functions; +}; + +}} + +#endif /* TARGETABSTRACT_H */ + diff --git a/cpp/src/compilation/transformations.cpp b/cpp/src/compilation/transformations.cpp new file mode 100644 index 0000000..d77ca83 --- /dev/null +++ b/cpp/src/compilation/transformations.cpp @@ -0,0 +1,143 @@ +/* + * File: Transformations.cpp + * Author: pgess + * + * Created on June 18, 2016, 6:23 PM + */ + +#include "compilation/transformations.h" +#include "pass/compilepass.h" +#include "llvmlayer.h" +#include + +using namespace llvm; + +namespace xreate { namespace compilation { + +Transformations::Transformations(CompilePass* passCompilation): pass(passCompilation) { +} + +void +Transformations::subscribe(const std::string& annotation, int handler){ + __subscriptions.emplace(annotation, handler); +} + +bool +Transformations::isAcceptable(const Expression& expression){ + //check subscription based on expression attachments + if (Attachments::get(expression, {false, 0}).flagSubscribed){ + return true; + } + + //subscription based on expression annotations; + if (expression.tags.size() == 0) return false; + + for (auto tag: expression.tags) { + if (__subscriptions.count(tag.first)){ + return true; + } + } + + return false; +} + +Expression +Transformations::transform(const Expression& expression, const Context& ctx){ + Expression result = expression; + + for (auto handler: getAppropriateTransformers(expression)){ + result = handler->transform(result, ctx); + } + + return result; +} + +llvm::Value* +Transformations::transform(const Expression& expression, llvm::Value* raw, const Context& ctx){ + for (auto handler: getAppropriateTransformers(expression)){ + raw = handler->transform(expression, raw, ctx); + } + + return raw; +} + +std::list +Transformations::getAppropriateTransformers(const Expression& expression){ + + std::list result; + + for (auto tag: expression.tags) { + if (__subscriptions.count(tag.first)){ + auto handlers = __subscriptions.equal_range(tag.first); + + for (auto handlerIt=handlers.first; handlerIt!= handlers.second; ++handlerIt){ + Transformer* handler = __transformers[handlerIt->second]; + + if (handler->isAcceptable(expression)){ + result.push_back(handler); + } + } + } + } + + auto subscriberInternal = Attachments::get(expression, {false, 0}); + if (subscriberInternal.flagSubscribed){ + result.push_back(__transformers[subscriberInternal.subscriberId]); + } + + return result; +} + +TransformerSaturation::TransformerSaturation(Transformations* man) + : __man(man) { + + man->subscribe("break", TransformerInfo::id); +} + +bool +TransformerSaturation::isAcceptable(const Expression& expression){ + return true; +} + +bool +TransformerSaturation::exists() const{ + return __block != nullptr; +} + +llvm::Value* +TransformerSaturation::transform(const Expression& expression, llvm::Value* raw, const Context& ctx){ + __block = __man->pass->man->llvm->builder.GetInsertBlock(); + + return raw; +} + +llvm::BasicBlock* +TransformerSaturation::getBlock() const{ + return __block; +} + +void +TransformerSaturation::inject(llvm::BasicBlock* blockAllocation, llvm::BasicBlock* blockExit, compilation::Context context){ + llvm::Type* tyInt1 = llvm::Type::getInt1Ty(llvm::getGlobalContext()); + llvm::Value* valueConstOne = llvm::ConstantInt::get(tyInt1, 1); + llvm::Value* valueConstFalse = llvm::ConstantInt::get(tyInt1, 0); + + //allocation of saturation flag + IRBuilder<> builderAlloca(blockAllocation, blockAllocation->getFirstInsertionPt()); + llvm::Value* flagSaturation = builderAlloca.CreateAlloca(tyInt1, valueConstOne, "flagSaturation"); + builderAlloca.CreateStore(valueConstFalse, flagSaturation, true); + + //set up saturation flag + llvm::BasicBlock* blockSaturation = __block; + IRBuilder<> builderSaturation(blockSaturation, blockSaturation->getFirstInsertionPt()); + builderSaturation.CreateStore(valueConstOne, flagSaturation, true); + + //check saturation flag: + //TODO remove blockContinue, receive from caller block to continue. + llvm::BasicBlock *blockContinue = llvm::BasicBlock::Create(llvm::getGlobalContext(), "continue", context.function->raw); + context.pass->man->llvm->builder.CreateCondBr(context.pass->man->llvm->builder.CreateLoad(flagSaturation), blockExit, blockContinue); + + context.pass->man->llvm->builder.SetInsertPoint(blockContinue); +} + +}} \ No newline at end of file diff --git a/cpp/src/compilation/transformations.h b/cpp/src/compilation/transformations.h new file mode 100644 index 0000000..daec0bf --- /dev/null +++ b/cpp/src/compilation/transformations.h @@ -0,0 +1,119 @@ +/* + * File: Transformations.h + * Author: pgess + * + * Created on June 18, 2016, 6:23 PM + */ + +#ifndef TRANSFORMATIONS_H +#define TRANSFORMATIONS_H + +#include "ast.h" +#include "pass/compilepass.h" +#include "attachments.h" + +namespace llvm { + class BasicBlock; +} + +namespace xreate { namespace compilation { + + class Transformer{ + public: + virtual llvm::Value* transform(const Expression& expression, llvm::Value* raw, const Context& ctx)=0; + virtual Expression transform(const Expression& expression, const Context& ctx){return expression;} + virtual bool isAcceptable(const Expression& expression)=0; + + virtual ~Transformer(){}; + }; + + class TransformerSaturation: public Transformer{ + public: + llvm::Value* transform(const Expression& expression, llvm::Value* raw, const Context& ctx); + bool isAcceptable(const Expression& expression); + + TransformerSaturation(Transformations*); + llvm::BasicBlock* getBlock() const; + bool exists() const; + void inject(llvm::BasicBlock* blockAllocation, llvm::BasicBlock* blockExit, compilation::Context context); + + private: + llvm::BasicBlock* __block = nullptr; + Transformations* __man; + }; + + template + struct TransformerInfo { + //static const int id = 1; (next vacant id) + }; + + template <> + struct TransformerInfo { + static const int id = 0; + }; + + class Transformations; + + struct SubscriberInfo{ + bool flagSubscribed; + int subscriberId; + }; + + class Transformations: public Transformer { + public: + xreate::CompilePass* pass; + + bool isAcceptable(const Expression& expression); + llvm::Value* transform(const Expression& expression, llvm::Value* raw, const Context& ctx) override; + Expression transform(const Expression& expression, const Context& ctx) override; + + Transformations(CompilePass*); + void subscribe(const std::string& annotation, int handler); + + template + void registerTransformer(TransformerType* t){ + const int id = TransformerInfo::id; + + __transformers[id] = t; + } + + template + static void subscribe(const Holder& holder){ + //assert(! Attachments::exists()); + + const int id = TransformerInfo::id; + + if (Attachments::exists(holder)){ + const int idOld = Attachments::get(holder).subscriberId; + assert(idOld == id); + return; + } + + Attachments::put(holder, {true, id}); + } + + template + TransformerType* get(){ + const int id = TransformerInfo::id; + return static_cast(__transformers.at(id)); + } + + private: + std::map __transformers; + std::multimap __subscriptions; + + std::list getAppropriateTransformers(const Expression& expression); + }; +}} + +namespace xreate { + template<> + struct AttachmentsDict + { + typedef xreate::compilation::SubscriberInfo Data; + static const unsigned int key = 4; + }; +} + +#endif /* TRANSFORMATIONS_H */ + diff --git a/cpp/src/contextrule.cpp b/cpp/src/contextrule.cpp index 6ae4fc4..af3c84e 100644 --- a/cpp/src/contextrule.cpp +++ b/cpp/src/contextrule.cpp @@ -1,52 +1,53 @@ /* * contextrule.cpp * * Created on: Jan 2, 2016 * Author: pgess */ #include "contextrule.h" #include "clasplayer.h" +#include "analysis/aux.h" #include using namespace xreate; using namespace std; ContextRule::ContextRule(const Expression& rule) { assert(rule.op == Operator::CONTEXT_RULE); assert(rule.operands.size() == 3); head = rule.operands.at(0); guards = rule.operands.at(1); body = rule.operands.at(2); } std::string ContextRule::compile(const ScopePacked& scopeId) const{ const string prolog = " %context rule visibility implemenetation\n" "context_rule_visibility(X, Y) :- X=Y, scope(X), scope(Y).\n" "context_rule_visibility(X, Y) :- cfa_parent(X, scope(Y)), scope(X), scope(Y).\n"; - listrepHead_ = ClaspLayer::compile(head); + listrepHead_ = xreate::analysis::compile(head); assert(repHead_.size() == 1); - listrepGuards_ = ClaspLayer::compile(guards); + listrepGuards_ = xreate::analysis::compile(guards); assert(repGuards_.size() == 1); - listrepBody_ = ClaspLayer::compile(body); + listrepBody_ = xreate::analysis::compile(body); assert(repBody_.size() == 1); const std::string& atomBindingScope = Config::get("clasp.bindings.scope"); boost::format formatContextVisibility("context_rule_visibility(ScopeX, %1%)"); - boost::format formatScopeBind(atomBindingScope + "(ScopeX, %1%)"); + boost::format formatScopeBind(atomBindingScope + "(ScopeX, %1%, Linkage)"); const string& repHead = str(formatScopeBind % repHead_.front()); const string& repGuards = str(formatScopeBind % repGuards_.front()); const string& repVisibility = str(formatContextVisibility % scopeId); boost::format formatRule("%1%:- %2%, %3%, %4%."); return prolog + str(formatRule % repHead % repGuards % repBody_.front() % repVisibility); } diff --git a/cpp/src/pass/abstractpass.cpp b/cpp/src/pass/abstractpass.cpp index 7eac8f0..ec136fd 100644 --- a/cpp/src/pass/abstractpass.cpp +++ b/cpp/src/pass/abstractpass.cpp @@ -1,36 +1,35 @@ #include "abstractpass.h" #include "attachments.h" #include "passmanager.h" using namespace std; namespace xreate { template<> - void defaultValue(){}; + void defaultValue(){} - void AbstractPassBase::finish() - {} + void AbstractPassBase::finish(){} AbstractPassBase::AbstractPassBase(PassManager *manager) : man(manager) { } template<> void AbstractPass::processSymbol(const std::string& ident, PassContext context) { const Symbol& symbol = context.scope->findSymbol(ident); if (__visitedSymbols.isCached(symbol)) return; - if (CodeScope::hasDeclaration(symbol)) { - __visitedSymbols.setCachedValue(symbol); + __visitedSymbols.setCachedValue(symbol); + const Expression& declaration = CodeScope::findDeclaration(symbol); - PassContext context2 = context; - context2.scope = symbol.scope; - process(CodeScope::findDeclaration(symbol), context2, ident); + if (declaration.isDefined()){ + PassContext context2 = context.updateScope(symbol.scope); + process(declaration, context2, ident); } } } diff --git a/cpp/src/pass/abstractpass.h b/cpp/src/pass/abstractpass.h index 8e4aef4..5595004 100644 --- a/cpp/src/pass/abstractpass.h +++ b/cpp/src/pass/abstractpass.h @@ -1,176 +1,194 @@ #ifndef ABSTRACTPASS_H #define ABSTRACTPASS_H #include "ast.h" #include "passmanager.h" #include -using namespace std; namespace xreate { struct PassContext { CodeScope* scope = 0; ManagedFnPtr function; ManagedRulePtr rule; std::string varDecl; PassContext() {} PassContext&& updateScope(CodeScope* scopeNew) { PassContext context2{*this}; context2.scope = scopeNew; return std::move(context2); } ~PassContext(){} }; class AbstractPassBase { public: AbstractPassBase(PassManager* manager); virtual void run()=0; virtual void finish(); PassManager* man; }; template Output defaultValue(); + + template<> + void defaultValue(); template class SymbolCache: private std::map{ public: bool isCached(const Symbol& symbol){ return this->count(symbol); } Output setCachedValue(const Symbol& symbol, Output&& value){ this->emplace(symbol, value); return value; } Output getCachedValue(const Symbol& symbol){ assert(this->count(symbol)); return this->at(symbol); } }; template<> class SymbolCache: private std::set{ public: bool isCached(const Symbol& symbol){ bool result = this->count(symbol) > 0; return result; } void setCachedValue(const Symbol& symbol){ this->insert(symbol); } void getCachedValue(const Symbol& symbol){ } }; template class AbstractPass: public AbstractPassBase { - private: + SymbolCache __visitedSymbols; + protected: Output processSymbol(const std::string& ident, PassContext context){ const Symbol& symbol = context.scope->findSymbol(ident); if (__visitedSymbols.isCached(symbol)) return __visitedSymbols.getCachedValue(symbol); - if (CodeScope::hasDeclaration(symbol)) { - PassContext context2 = context; - context2.scope = symbol.scope; - Output&& result = process(CodeScope::findDeclaration(symbol), context2, ident); + + const Expression& declaration = CodeScope::findDeclaration(symbol); + if (declaration.isDefined()){ + PassContext context2 = context.updateScope(symbol.scope); + + Output&& result = process(declaration, context2, ident); return __visitedSymbols.setCachedValue(symbol, std::move(result)); } - + return defaultValue(); } + + SymbolCache& getSymbolCache(){ + return __visitedSymbols; + } + + public: AbstractPass(PassManager* manager) : AbstractPassBase(manager){} - + //NOTE implement processFnCall virtual void processFnCall(ManagedFnPtr function, PassContext context) {} virtual void processFnCallUncertain(ManagedFnPtr function, PassContext context) {} virtual void process(ManagedRulePtr rule) {} virtual Output process(ManagedFnPtr function){ + const Symbol& symbolFunction{0, function->getEntryScope()}; + + if (__visitedSymbols.isCached(symbolFunction)) + return __visitedSymbols.getCachedValue(symbolFunction); + PassContext context; context.function = function; - + return process(function->getEntryScope(), context); } virtual Output process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl=""){ context.scope = scope; return process(scope->__body, context); } virtual Output process(const Expression& expression, PassContext context, const std::string& varDecl=""){ switch (expression.__state) { case Expression::COMPOUND: assert(expression.op != Operator::MAP || (expression.op == Operator::MAP && expression.blocks.size())); + //TODO there are discrepancies for SWITCH CASE scopes.case body parent scope differs from context.scope. for (const Expression &op: expression.getOperands()) { process(op, context); } + // for (CodeScope* scope: expression.blocks) { process(scope, context); } if (expression.op == Operator::CALL) { const std::string &calleeName = expression.getValueString(); - list callees = man->root->getFunctionVariants(calleeName); + std::list callees = man->root->getFunctionVariants(calleeName); if (callees.size() == 1 && callees.front()){ processFnCall(callees.front(), context); } else { for (const ManagedFnPtr& callee: callees){ processFnCallUncertain(callee, context); } } } break; case Expression::IDENT: assert(context.scope); return processSymbol(expression.getValueString(), context); default: break; } return defaultValue(); } void run() { ManagedRulePtr rule = man->root->begin(); while (rule.isValid()) { process(rule); ++rule; } ManagedFnPtr f = man->root->begin(); while (f.isValid()) { process(f); ++f; } } }; template<> void AbstractPass::processSymbol(const std::string& ident, PassContext context); } #endif diff --git a/cpp/src/pass/adhocpass.cpp b/cpp/src/pass/adhocpass.cpp index 8473a79..ef9d1eb 100644 --- a/cpp/src/pass/adhocpass.cpp +++ b/cpp/src/pass/adhocpass.cpp @@ -1,81 +1,81 @@ /* * adhoc.cpp * * Created on: Nov 28, 2015 * Author: pgess */ #include "pass/adhocpass.h" #include "query/context.h" namespace xreate { AdhocScheme* AdhocPass::determineForScope(CodeScope* entry){ const ScopePacked scopeId = man->clasp->pack(entry); - const ContextDomain& domain = queryContext->getContext(scopeId); + const Domain& domain = queryContext->getContext(scopeId); AdhocScheme* scheme = nullptr; for (const Expression& context: domain){ if (context.__state != Expression::IDENT) continue; if (__schemes.count(context.getValueString())){ assert(!scheme && "ambiguous context"); scheme = __schemes.at(context.getValueString()); } } assert(scheme && "Appropriate context not found"); return scheme; } const TypeAnnotation& AdhocScheme::getResultType(){ return __resultType; } CodeScope* AdhocScheme::getImplementationForCommand(const std::string& comm) { assert(__commands.count(comm) && "Adhoc not defined"); return __commands.at(comm); } AdhocScheme::AdhocScheme(const Expression& scheme): __resultType(scheme.type), __context(scheme.getValueString()) { Expression cases = scheme.getOperands()[0]; for (const Expression& exprCase: cases.getOperands()){ CodeScope* blockComm = exprCase.blocks.front(); std::string nameCase = blockComm->__body.operands[0].getValueString(); CodeScope* blockImpl = *(++exprCase.blocks.begin()); __commands.emplace(nameCase, blockImpl); } } const std::string& AdhocScheme::getContext(){ return __context; } /* void AdhocPass::process(const Expression& expression, PassContext context, const std::string& varDecl=""){ if (expression == Exp) } */ void AdhocPass::run(){ queryContext = reinterpret_cast(man->clasp->registerQuery(new ContextQuery(), QueryId::ContextQuery)); auto range = man->root->__interfacesData.equal_range(ASTInterface::Adhoc); for (auto i=range.first; i!= range.second; ++i){ AdhocScheme* scheme = new AdhocScheme(i->second); __schemes.emplace(scheme->getContext(), scheme); } } } diff --git a/cpp/src/pass/cfgpass.cpp b/cpp/src/pass/cfapass.cpp similarity index 53% rename from cpp/src/pass/cfgpass.cpp rename to cpp/src/pass/cfapass.cpp index 120b80d..c4afd00 100644 --- a/cpp/src/pass/cfgpass.cpp +++ b/cpp/src/pass/cfapass.cpp @@ -1,98 +1,100 @@ -#include "cfgpass.h" +#include "cfapass.h" +#include "analysis/cfagraph.h" + #include + using namespace std; using namespace xreate; - - void -CFGPass::initSignatures(){ +CFAPass::initSignatures(){ auto range = man->root->__interfacesData.equal_range(CFA); for (auto i = range.first; i!= range.second; ++i){ __signatures.emplace(i->second.op, i->second); } } -void CFGPass::run(){ +void CFAPass::run(){ initSignatures(); return AbstractPass::run(); } void -CFGPass::finish() +CFAPass::finish() { man->clasp->setCFAData(move(__context.graph)); return AbstractPass::finish(); } void -CFGPass::processFnCall(ManagedFnPtr function, PassContext context) +CFAPass::processFnCall(ManagedFnPtr function, PassContext context) { ClaspLayer* clasp = man->clasp; - __context.graph.addCallConnection(clasp->pack(context.scope), function->getName()); + __context.graph->addCallConnection(clasp->pack(context.scope), function->getName()); return AbstractPass::processFnCall(function, context); } void -CFGPass::processFnCallUncertain(ManagedFnPtr function, PassContext context){ +CFAPass::processFnCallUncertain(ManagedFnPtr function, PassContext context){ ClaspLayer* clasp = man->clasp; - __context.graph.addCallConnection(clasp->pack(context.scope), function->getName()); + __context.graph->addCallConnection(clasp->pack(context.scope), function->getName()); return AbstractPass::processFnCallUncertain(function, context); } void -CFGPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl){ +CFAPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl){ ClaspLayer* clasp = man->clasp; CodeScope* scopeParent = context.scope; ScopePacked scopeId = clasp->pack(scope); if (scopeParent){ - __context.graph.addParentConnection(scopeId, clasp->pack(scopeParent)); + __context.graph->addParentConnection(scopeId, clasp->pack(scopeParent)); } else { - __context.graph.addParentConnection(scopeId, context.function->getName()); + __context.graph->addParentConnection(scopeId, context.function->getName()); } - //TEST scope annotations + //TOTEST scope annotations //SECTIONTAG context gather scope annotations - __context.graph.addScopeAnnotations(scopeId, scope->tags); + __context.graph->addScopeAnnotations(scopeId, scope->tags); - __context.graph.addContextRules(scopeId, scope->contextRules); + __context.graph->addContextRules(scopeId, scope->contextRules); return AbstractPass::process(scope, context, hintBlockDecl); } -//TEST scope annotations via scheme +//TOTEST scope annotations via scheme void -CFGPass::process(const Expression& expression, PassContext context, const std::string& varDecl){ +CFAPass::process(const Expression& expression, PassContext context, const std::string& varDecl){ ClaspLayer* clasp = man->clasp; if (expression.__state == Expression::COMPOUND){ Operator op= expression.op; if (__signatures.count(op)) { assert(expression.blocks.size()); for (const auto& scheme: boost::make_iterator_range(__signatures.equal_range(expression.op))) { - __context.graph.addScopeAnnotations(clasp->pack(expression.blocks.front()), scheme.second.getOperands()); + __context.graph->addScopeAnnotations(clasp->pack(expression.blocks.front()), scheme.second.getOperands()); } } } return AbstractPass::process(expression, context, varDecl); } void -CFGPass::process(ManagedFnPtr function) +CFAPass::process(ManagedFnPtr function) { - __context.graph.addFunctionAnnotations(function->getName(), function->getAnnotations()); + __context.graph->addFunctionAnnotations(function->getName(), function->getTags()); return AbstractPass::process(function); } -CFGPass::CFGPass(PassManager* manager) +CFAPass::CFAPass(PassManager* manager) : AbstractPass(manager) + , __context{new xreate::analysis::CFAGraph(manager->clasp)} {} diff --git a/cpp/src/pass/cfgpass.h b/cpp/src/pass/cfapass.h similarity index 77% rename from cpp/src/pass/cfgpass.h rename to cpp/src/pass/cfapass.h index 8640f20..a064c6d 100644 --- a/cpp/src/pass/cfgpass.h +++ b/cpp/src/pass/cfapass.h @@ -1,34 +1,38 @@ // Control Flow Graph determination pass #ifndef CFGPASS_H #define CFGPASS_H #include "passmanager.h" #include "clasplayer.h" #include "abstractpass.h" +namespace xreate{namespace analysis { + class CFAGraph; +}} + namespace xreate { -class CFGPass : public AbstractPass +class CFAPass : public AbstractPass { public: - void process(ManagedFnPtr function) override; + void process(ManagedFnPtr function) override; void processFnCall(ManagedFnPtr function, PassContext context) override; void processFnCallUncertain(ManagedFnPtr function, PassContext context) override; void process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl="") override; void process(const Expression& expression, PassContext context, const std::string& varDecl="") override; - CFGPass(PassManager* manager); + CFAPass(PassManager* manager); void finish() override; void run() override; private: struct { - CFAGraph graph; + xreate::analysis::CFAGraph* graph; } __context; std::multimap __signatures; //CFA data for particular operators void initSignatures(); }; } #endif // CFGPASS_H diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp index 84e1cb5..6c52cee 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,654 +1,812 @@ #include "compilepass.h" #include "clasplayer.h" #include "llvmlayer.h" #include #include "query/containers.h" #include "query/context.h" -#include "compilation/instr-containers.h" +#include "compilation/containers.h" +#include "compilation/transformations.h" #include "ExternLayer.h" #include "pass/adhocpass.h" +//#include "compilation/targetinterpretation.h" #include #include #include using namespace std; using namespace xreate; using namespace xreate::compilation; using namespace llvm; +//TODO use Scope + //SECTIONTAG types/convert implementation +//TODO type conversion: +//a) automatically expand types int -> bigger int; int -> floating +//b) detect exact type of `num` based on max used numeral / function type +//c) warning if need to truncate (allow/dissalow based on annotations) + +namespace xreate { + llvm::Value* -doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, LLVMLayer* llvm){ - if (tyTarget->isIntegerTy() && source->getType()->isIntegerTy()) - { - llvm::IntegerType* tyTargetInt = llvm::dyn_cast(tyTarget); - llvm::IntegerType* tySourceInt = llvm::dyn_cast(source->getType()); - - if (tyTargetInt->getBitWidth() < tySourceInt->getBitWidth()){ - return llvm->builder.CreateCast(llvm::Instruction::Trunc, source, tyTarget); - } - - if (tyTargetInt->getBitWidth() > tySourceInt->getBitWidth()){ - return llvm->builder.CreateCast(llvm::Instruction::SExt, source, tyTarget); - } - } +doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, llvm::IRBuilder<>& builder){ + if (tyTarget->isIntegerTy() && source->getType()->isIntegerTy()) + { + llvm::IntegerType* tyTargetInt = llvm::dyn_cast(tyTarget); + llvm::IntegerType* tySourceInt = llvm::dyn_cast(source->getType()); + + if (tyTargetInt->getBitWidth() < tySourceInt->getBitWidth()){ + return builder.CreateCast(llvm::Instruction::Trunc, source, tyTarget); + } + + if (tyTargetInt->getBitWidth() > tySourceInt->getBitWidth()){ + return builder.CreateCast(llvm::Instruction::SExt, source, tyTarget); + } + } - return source; + if (source->getType()->isIntegerTy() && tyTarget->isFloatingPointTy()){ + return builder.CreateCast(llvm::Instruction::SIToFP, source, tyTarget); + } + + return source; } CodeScopeUnit::CodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass) : scope(codeScope), pass(compilePass), function(f) {} -namespace xreate { class CallStatement { public: virtual llvm::Value* operator() (std::vector&& args, const std::string& hintDecl, llvm::IRBuilder<>&) = 0; }; class CallStatementRaw: public CallStatement{ public: - CallStatementRaw(llvm::Value* callee): __callee(callee) {} + CallStatementRaw(llvm::Function* callee): __callee(callee) {} llvm::Value* operator() (std::vector&& args, const std::string& hintDecl, llvm::IRBuilder<>& builder) { + auto argsFormal = __callee->args(); + + int pos=0; + //SECTIONTAG types/convert function ret value + for (auto argFormal = argsFormal.begin(); argFormal!=argsFormal.end(); ++argFormal, ++pos){ + args[pos] = doAutomaticTypeConversion(args[pos], argFormal->getType(), builder); + } + return builder.CreateCall(__callee, args, hintDecl); } private: - llvm::Value* __callee; + llvm::Function* __callee; }; +//TASK implement inlining class CallStatementInline: public CallStatement{ public: CallStatementInline(FunctionUnit* caller, FunctionUnit* callee) : __caller(caller), __callee(callee) {} llvm::Value* operator() (std::vector&& args, const std::string& hintDecl, llvm::IRBuilder<>& builder) { - //TEST inlining - return __callee->compileInline(move(args), __caller); + //TOTEST inlining +// CodeScopeUnit* entryCompilation = outer->getScopeUnit(function->__entry); +// for(int i=0, size = args.size(); ibindArg(args.at(i), string(entryCompilation->scope->__bindings.at(i))); +// } +// +// +// return entryCompilation->compile(); } private: FunctionUnit* __caller; FunctionUnit* __callee; + + bool isInline(){ + // Symbol ret = Symbol{0, function->__entry}; + // bool flagOnTheFly = SymbolAttachments::get(ret, false); + //TODO consider inlining + return false; + } +}; + +template +class CallStatementLateContext: public CallStatement{ + { + if (specializations.size()< 2){ + return Parent... + } + + + + + + + + } + }; } +void +CodeScopeUnit::overrideDeclaration(const Symbol binding, Expression&& declaration){ + function->getScopeUnit(binding.scope)->__declarationsOverriden.emplace(binding.identifier, move(declaration)); +} + +class ScopeDecorator{ + +}; + //SECTIONTAG late-context find callee function -//TEST static late context decisions -//TEST dynamic late context decisions +//TOTEST static late context decisions +//TOTEST dynamic late context decisions + CallStatement* CodeScopeUnit::findFunction(const std::string& calleeName){ - LLVMLayer* llvm = pass->man->llvm; - ClaspLayer* clasp = pass->man->clasp; + LLVMLayer* llvm = pass->man->llvm; + ClaspLayer* clasp = pass->man->clasp; - ContextQuery* queryContext = pass->queryContext; + ContextQuery* queryContext = pass->queryContext; - const std::list& specializations = pass->man->root->getFunctionVariants(calleeName); + const std::list& specializations = pass->man->root->getFunctionVariants(calleeName); - //check external function - if (!specializations.size()){ - llvm::Function* external = pass->man->llvm->layerExtern->lookupFunction(calleeName); + //if no specializations registered - check external function + if (specializations.size()==0){ + llvm::Function* external = llvm->layerExtern->lookupFunction(calleeName); - return new CallStatementRaw(external); - } + return new CallStatementRaw(external); + } - //no decisions required - if (specializations.size()==1){ - if (!specializations.front()->guardContext.isValid()) { - return new CallStatementRaw( pass->getFunctionUnit(specializations.front())->compile()); - } - } + //no decisions required + if (specializations.size()==1){ + if (!specializations.front()->guardContext.isValid()) { + return new CallStatementRaw( pass->getFunctionUnit(specializations.front())->compile()); + } + } - //prepare specializations dictionary - typedef ExpressionSerialization<>::Serializer Serializer; - typedef ExpressionSerialization<>::Code Code; + //TODO move dictSpecialization over to a separate function in order to perform cache, etc. + //prepare specializations dictionary + std::map dictSpecializations; - auto adapter = [](const ManagedFnPtr& p){ return p->guardContext; }; - Serializer serializer(specializations, adapter); + boost::optional variantDefault; + boost::optional variant; - std::map dictSpecializations; - boost::optional variantDefault; - boost::optional variant; + for(const ManagedFnPtr& f: specializations){ + const Expression& guard = f->guardContext; - for(const ManagedFnPtr& f: specializations){ - const Expression& guard = f->guardContext; + //default case: + if (!guard.isValid()){ + variantDefault = f; + continue; + } - //default case: - if (!guard.isValid()){ - variantDefault = f; - continue; - } + assert(dictSpecializations.emplace(guard, f).second && "Found several identical specializations"); + } - assert(dictSpecializations.emplace(serializer.getId(guard), f).second && "Found several appropriate specializations"); - } + //check static context + ScopePacked scopeCaller = clasp->pack(this->scope); + const string atomSpecialization = "specialization"; + const Expression topicSpecialization(Operator::CALL, {(Atom(string(atomSpecialization))), (Atom(string(calleeName))), (Atom(scopeCaller))}); - //check static context - const ScopeContextDecisions& decisions = queryContext->getStaticDecisions(clasp->pack(this->scope)); - if (decisions.count(calleeName)){ - variant = dictSpecializations.at(serializer.getId(decisions.at(calleeName))); - } + const Decisions& decisions = queryContext->getFinalDecisions(scopeCaller); + if (decisions.count(topicSpecialization)){ + variant = dictSpecializations.at(decisions.at(topicSpecialization)); + } - size_t sizeDemand = this->function->contextCompiler.getFunctionDemandSize(); + //TODO check only demand for this particular topic. + size_t sizeDemand = this->function->contextCompiler.getFunctionDemandSize(); - //decision made if static context found or no late context exists(and there is default variant) - bool flagHasStaticDecision = variant || (variantDefault && !sizeDemand); + //decision made if static context found or no late context exists(and there is default variant) + bool flagHasStaticDecision = variant || (variantDefault && !sizeDemand); - //if no late context exists - if (flagHasStaticDecision) { - FunctionUnit* calleeUnit = pass->getFunctionUnit(variant? *variant: *variantDefault); + //if no late context exists + if (flagHasStaticDecision) { + FunctionUnit* calleeUnit = pass->getFunctionUnit(variant? *variant: *variantDefault); - //inlining possible based on static decision only - if (calleeUnit->isInline()) { - return new CallStatementInline(function, calleeUnit); - } + //inlining possible based on static decision only + if (calleeUnit->isInline()) { + return new CallStatementInline(function, calleeUnit); + } - return new CallStatementRaw(calleeUnit->compile()); - } + return new CallStatementRaw(calleeUnit->compile()); + } - //require default variant if no static decision made - assert(variantDefault); + //require default variant if no static decision made + assert(variantDefault); - llvm::Function* functionVariantDefault = this->pass->getFunctionUnit(*variantDefault)->compile(); - return new CallStatementRaw(this->function->contextCompiler.findFunction(calleeName, functionVariantDefault)); + llvm::Function* functionVariantDefault = this->pass->getFunctionUnit(*variantDefault)->compile(); + return new CallStatementRaw(this->function->contextCompiler.findFunction(calleeName, functionVariantDefault, scopeCaller)); } void -CodeScopeUnit::bindArg(llvm::Value* var, std::string&& name) +CodeScopeUnit::bindArg(llvm::Value* value, std::string&& alias) { - assert(scope->__vartable.count(name)); - VID id = scope->__vartable.at(name); - __rawVars[id] = var; + //reset cached compiled value if any + raw = nullptr; + + //ensure existing of an alias + assert(scope->__identifiers.count(alias)); + + //memorize new value for an alias + VID id = scope->__identifiers.at(alias); + __rawVars[id] = value; } llvm::Value* CodeScopeUnit::process(const Expression& expr, const std::string& hintVarDecl){ + + Context ctx{this, this->function, this->pass}; + +// if (pass->targetInterpretation->isAcceptable(expr)){ +// return pass->targetInterpretation->compile(expr, ctx); +// } + + llvm::Value* result = processLowlevel(expr, hintVarDecl); + + if (pass->transformations->isAcceptable(expr)){ + return pass->transformations->transform(expr, result, ctx); + } + + return result; +} + +llvm::Value* +CodeScopeUnit::processLowlevel(const Expression& expr, const std::string& hintVarDecl){ #define DEFAULT(x) (hintVarDecl.empty()? x: hintVarDecl) llvm::Value *left; llvm::Value *right; LLVMLayer& l = *pass->man->llvm; - containers::Instructions instructions = containers::Instructions({function, this, pass}); + xreate::compilation::Advanced instructions = xreate::compilation::Advanced({this, function, pass}); switch (expr.op) { - case Operator::ADD: - case Operator::SUB: - case Operator::MUL: - case Operator::DIV: - case Operator::EQU: - case Operator::LSS: - case Operator::GTR: + case Operator::ADD: case Operator::SUB: case Operator::MUL: + case Operator::DIV: case Operator::EQU: case Operator::LSS: + case Operator::GTR: case Operator::NE: case Operator::LSE: + case Operator::GTE: + assert(expr.__state == Expression::COMPOUND); assert(expr.operands.size() == 2); left = process(expr.operands[0]); right = process(expr.operands[1]); //SECTIONTAG types/convert binary operation - right = doAutomaticTypeConversion(right, left->getType(), &l); + right = doAutomaticTypeConversion(right, left->getType(), l.builder); break; default:; } switch (expr.op) { case Operator::ADD: return l.builder.CreateAdd(left, right, DEFAULT("tmp_add")); break; case Operator::SUB: return l.builder.CreateSub(left, right, DEFAULT("tmp_sub")); break; case Operator::MUL: return l.builder.CreateMul(left, right, DEFAULT("tmp_mul")); break; case Operator::DIV: return l.builder.CreateSDiv(left, right, DEFAULT("tmp_div")); break; case Operator::EQU: - left->dump(); - right->dump(); - return l.builder.CreateICmpEQ(left, right, DEFAULT("tmp_equ")); + if (left->getType()->isIntegerTy()) return l.builder.CreateICmpEQ(left, right, DEFAULT("tmp_equ")); + if (left->getType()->isFloatingPointTy()) return l.builder.CreateFCmpOEQ(left, right, DEFAULT("tmp_equ")); + break; + + case Operator::NE: + return l.builder.CreateICmpNE(left, right, DEFAULT("tmp_ne")); break; case Operator::LSS: return l.builder.CreateICmpSLT(left, right, DEFAULT("tmp_lss")); break; + case Operator::LSE: + return l.builder.CreateICmpSLE(left, right, DEFAULT("tmp_lse")); + break; + case Operator::GTR: return l.builder.CreateICmpSGT(left, right, DEFAULT("tmp_gtr")); break; + case Operator::GTE: + return l.builder.CreateICmpSGE(left, right, DEFAULT("tmp_gte")); + break; + case Operator::NEG: left = process(expr.operands[0]); return l.builder.CreateNeg(left, DEFAULT("tmp_neg")); break; case Operator::CALL: { assert(expr.__state == Expression::COMPOUND); std::string nameCallee = expr.getValueString(); unique_ptr callee(findFunction(nameCallee)); //prepare arguments std::vector args; args.reserve(expr.operands.size()); std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()), [this](const Expression &operand) { return process(operand); } ); ScopePacked outerScopeId = pass->man->clasp->pack(this->scope); //SECTIONTAG late-context propagation arg size_t calleeDemandSize = pass->queryContext->getFunctionDemand(nameCallee).size(); if (calleeDemandSize){ - llvm::Value* argLateContext = function->contextCompiler.compileArgument(nameCallee, outerScopeId); + llvm::Value* argLateContext = function->contextCompiler.compileContextArgument(nameCallee, outerScopeId); args.push_back(argLateContext); } return (*callee)(move(args), DEFAULT("res_"+nameCallee), l.builder); } case Operator::IF: { return instructions.compileIf(expr, DEFAULT("tmp_if")); } case Operator::SWITCH: { return instructions.compileSwitch(expr, DEFAULT("tmp_switch")); } case Operator::LOOP_CONTEXT: { return instructions.compileLoopContext(expr, DEFAULT("tmp_loop")); } case Operator::LOGIC_AND: { assert(expr.operands.size() == 1); return process (expr.operands[0]); } case Operator::LIST: { return instructions.compileConstantArray(expr, DEFAULT("tmp_list")); }; case Operator::LIST_RANGE: { assert(false); //no compilation phase for a range list // return InstructionList(this).compileConstantArray(expr, l, hintRetVar); }; case Operator::LIST_NAMED: { typedef Expanded ExpandedType; ExpandedType tyRaw = l.ast->expandType(expr.type); const std::vector fields = (tyRaw.get().__operator == TypeOperator::CUSTOM)? l.layerExtern->getStructFields(l.layerExtern->lookupType(tyRaw.get().__valueCustom)) : tyRaw.get().fields; std::map indexFields; for(size_t i=0, size = fields.size(); i(l.toLLVMType(tyRaw)); llvm::Value* record = llvm::UndefValue::get(tyRecord); for (size_t i=0; igetElementType(fieldId); // result = llvm::UndefValue::get(tyNullField); // // } else { result = process(operand); // } assert (result); record = l.builder.CreateInsertValue(record, result, llvm::ArrayRef({fieldId})); } return record; }; case Operator::MAP: { assert(expr.blocks.size()); return instructions.compileMapSolid(expr, DEFAULT("map")); }; case Operator::FOLD: { return instructions.compileFold(expr, DEFAULT("fold")); }; + case Operator::FOLD_INF: + { + return instructions.compileFoldInf(expr, DEFAULT("fold")); + }; + case Operator::INDEX: { //TODO allow multiindex assert(expr.operands.size()==1); const std::string &ident = expr.getValueString(); Symbol s = scope->findSymbol(ident); - const TypeAnnotation& t = s.scope->findDefinition(s); + const TypeAnnotation& t = CodeScope::findDeclaration(s).type; const ExpandedType& t2 = pass->man->root->expandType(t); switch (t2.get().__operator) { case TypeOperator::STRUCT: case TypeOperator::CUSTOM: { Expression idx = expr.operands.at(0); assert(idx.__state == Expression::STRING); std::string idxField = idx.getValueString(); llvm::Value* aggr = compileSymbol(s, ident); return instructions.compileStructIndex(aggr, t2, idxField); }; case TypeOperator::ARRAY: { std::vector indexes; std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()), [this] (const Expression& op){return process(op);} ); return instructions.compileArrayIndex(s, indexes, DEFAULT(string("el_") + ident)); }; default: assert(false); } }; //SECTIONTAG adhoc actual compilation case Operator::ADHOC: { assert(function->adhocImplementation && "Adhoc implementation not found"); string comm = expr.operands[0].getValueString(); CodeScope* scope = function->adhocImplementation->getImplementationForCommand(comm); CodeScopeUnit* unitScope = function->getScopeUnit(scope); return unitScope->compile(); }; case Operator::SEQUENCE: { assert (expr.getOperands().size()); llvm::Value* result; for(const Expression &op: expr.getOperands()){ result = process(op, ""); } return result; } case Operator::NONE: assert(expr.__state != Expression::COMPOUND); switch (expr.__state) { case Expression::IDENT: { const std::string &ident = expr.getValueString(); Symbol s = scope->findSymbol(ident); return compileSymbol(s, ident); } case Expression::NUMBER: { int literal = expr.getValueDouble(); return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), literal); } case Expression::STRING: { return instructions.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str")); }; case Expression::VARIANT: { const ExpandedType& typVariant = pass->man->root->expandType(expr.type); llvm::Type* typRaw = l.toLLVMType(typVariant); int value = expr.getValueDouble(); return llvm::ConstantInt::get(typRaw, value); } default: { break; } }; break; default: break; } assert(false); return 0; } llvm::Value* CodeScopeUnit::compile(const std::string& hintBlockDecl){ if (raw != nullptr) return raw; if (!hintBlockDecl.empty()) { llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm::getGlobalContext(), hintBlockDecl, function->raw); pass->man->llvm->builder.SetInsertPoint(block); } raw = process(scope->__body); return raw; } llvm::Value* CodeScopeUnit::compileSymbol(const Symbol& s, std::string hintRetVar) { CodeScope* scope = s.scope; CodeScopeUnit* self = function->getScopeUnit(scope); if (self->__rawVars.count(s.identifier)) { return self->__rawVars[s.identifier]; } - return self->__rawVars[s.identifier] = self->process(scope->findDeclaration(s), hintRetVar); -} + //compilation transformations could override symbol declarations. + Expression declaration = CodeScope::findDeclaration(s); + if (!declaration.isDefined()){ + if (self->__declarationsOverriden.count(s.identifier)){ + declaration = self->__declarationsOverriden[s.identifier]; -bool -FunctionUnit::isInline(){ - Symbol ret = Symbol{0, function->__entry}; - bool flagOnTheFly = SymbolAttachments::get(ret, false); + } else { + assert(false); //in case of bindings there should be raws already. + } + } - return flagOnTheFly; + return self->__rawVars[s.identifier] = self->process(declaration, hintRetVar); } +//SECTIONTAG late-context FunctionDecorator +template +class LateContextFunctionDecorator: public Parent{ + + LateContextFunctionDecorator(ManagedFnPtr f, CompilePass* p) + : Parent(f, p), contextCompiler(this, p) + {} + + std::vector prepareArguments(){ + std::vector&& arguments = Parent::prepareArguments(); + + size_t sizeLateContextDemand = contextCompiler.getFunctionDemandSize(); + if (sizeLateContextDemand) { + llvm::Type* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); + llvm::Type* tyDemand = llvm::ArrayType::get(ty32, sizeLateContextDemand); + + arguments.push_back(tyDemand); + } + return arguments; + } + + void prepareBindings(){ + if (sizeLateContextDemand){ + fargsI->setName("latecontext"); + contextCompiler.rawContextArgument = &*fargsI; + } + } + +protected: + LateContextCompiler2 contextCompiler; +}; + +//SECTIONTAG adhoc FunctionDecorator +template +class AdhocFunctionDecorator: public Parent{ +protected: + llvm::Type* prepareResult(){ + if (! function->isPrefunction){ + return Parent::prepareResult(); + } + + AdhocPass* adhocpass = reinterpret_cast(pass->man->getPassById(PassId::AdhocPass)); + adhocImplementation = adhocpass->determineForScope(entry); + + return llvm->toLLVMType(ast->expandType(adhocImplementation->getResultType())); + } + +private: + AdhocScheme* adhocImplementation=nullptr; //SECTIONTAG adhoc prefunc scheme declaration +}; + +template +class BasicFunctionDecorator: public Decorator{ +protected: + std::string prepareName(){ + string name = ast->getFunctionVariants(function->__name).size() > 1? + function->__name + std::to_string(function.id()) : + function->__name; + + return name; + } + + virtual std::vector prepareArguments(){ + std::vector signature; + std::transform(entry->__bindings.begin(), entry->__bindings.end(), std::inserter(signature, signature.end()), + [this, llvm, ast, entry](const std::string &arg)->llvm::Type* { + assert(entry->__identifiers.count(arg)); + VID argid = entry->__identifiers.at(arg); + return llvm->toLLVMType(ast->expandType(entry->__declarations.at(argid).type)); + }); + return signature; + } + + virtual llvm::Type* prepareResult(){ + return llvm->toLLVMType(ast->expandType(entry->__declarations[0].type)); + } + + virtual void prepareBindings(){ + CodeScope* entry = function->__entry; + + CodeScopeUnit* entryCompilation = getScopeUnit(entry); + llvm::Function::arg_iterator fargsI = raw->arg_begin(); + for (std::string &arg : entry->__bindings) { + VID argid = entry->__identifiers[arg]; + + entryCompilation->__rawVars[argid] = &*fargsI; + fargsI->setName(arg); + ++fargsI; + } + } +}; + +typedef LateContextFunctionDecorator< + AdhocFunctionDecorator< + BasicFunctionDecorator>> DefaultFunctionUnit; + llvm::Function* FunctionUnit::compile(){ if (raw != nullptr) return raw; - std::vector types; + LLVMLayer* llvm = pass->man->llvm; llvm::IRBuilder<>& builder = llvm->builder; - CodeScope* entry = function->__entry; + AST* ast = pass->man->root; - const string& functionName = ast->getFunctionVariants(function->__name).size() > 1? function->__name + std::to_string(function.id()) : function->__name; - - std::transform(entry->__args.begin(), entry->__args.end(), std::inserter(types, types.end()), - [this, llvm, ast, entry](const std::string &arg)->llvm::Type* { - assert(entry->__vartable.count(arg)); - VID argid = entry->__vartable.at(arg); - assert(entry->__definitions.count(argid)); - return llvm->toLLVMType(ast->expandType(entry->__definitions.at(argid))); - }); - - //SECTIONTAG late-context signature type - size_t sizeLateContextDemand = contextCompiler.getFunctionDemandSize(); - if (sizeLateContextDemand) { - llvm::Type* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); - llvm::Type* tyDemand = llvm::ArrayType::get(ty32, sizeLateContextDemand); - types.push_back(tyDemand); - } - //SECTIONTAG adhoc func signature determination - llvm::Type* expectedResultType; - if (function->isPrefunction){ - AdhocPass* adhocpass = reinterpret_cast(pass->man->getPassById(PassId::AdhocPass)); - adhocImplementation = adhocpass->determineForScope(entry); - expectedResultType = llvm->toLLVMType(ast->expandType(adhocImplementation->getResultType())); - } else { - expectedResultType = llvm->toLLVMType(ast->expandType(entry->__definitions[0])); - } + string&& functionName = prepareName(); + std::vector&& types = prepareArguments(); + llvm::Type* expectedResultType = prepareResult(); llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false); - raw = llvm::cast(llvm->module->getOrInsertFunction(functionName, ft)); + prepareBindings(); - CodeScopeUnit* entryCompilation = getScopeUnit(entry); - llvm::Function::arg_iterator fargsI = raw->arg_begin(); - for (std::string &arg : entry->__args) { - VID argid = entry->__vartable[arg]; - - entryCompilation->__rawVars[argid] = fargsI; - fargsI->setName(arg); - ++fargsI; - } - - if (sizeLateContextDemand){ - fargsI->setName("latecontext"); - contextCompiler.raw = fargsI; - } const std::string&blockName = "entry"; llvm::BasicBlock* blockCurrent = builder.GetInsertBlock(); llvm::Value* result = entryCompilation->compile(blockName); assert(result); //SECTIONTAG types/convert function ret value - builder.CreateRet(doAutomaticTypeConversion(result, expectedResultType, llvm)); + builder.CreateRet(doAutomaticTypeConversion(result, expectedResultType, llvm->builder)); if (blockCurrent){ builder.SetInsertPoint(blockCurrent); } llvm->moveToGarbage(ft); return raw; } -llvm::Value* -FunctionUnit::compileInline(std::vector &&args, FunctionUnit* outer){ - CodeScopeUnit* entryCompilation = outer->getScopeUnit(function->__entry); - for(int i=0, size = args.size(); ibindArg(args.at(i), string(entryCompilation->scope->__args.at(i))); - } - - - return entryCompilation->compile(); -} - CodeScopeUnit* FunctionUnit::getScopeUnit(CodeScope* scope){ if (!scopes.count(scope)){ CodeScopeUnit* unit = new CodeScopeUnit(scope, this, pass); scopes.emplace(scope, std::unique_ptr(unit)); } return scopes.at(scope).get(); } CodeScopeUnit* FunctionUnit::getEntry(){ return getScopeUnit(function->getEntryScope()); } CodeScopeUnit* FunctionUnit::getScopeUnit(ManagedScpPtr scope){ return getScopeUnit(&*scope); } FunctionUnit* CompilePass::getFunctionUnit(const ManagedFnPtr& function){ unsigned int id = function.id(); if (!functions.count(id)){ - FunctionUnit* unit = new FunctionUnit(function, this); - functions.emplace(id, std::unique_ptr(unit)); + FunctionUnit* unit = new DefaultFunctionUnit(function, this); + functions.emplace(id, unit); return unit; } return functions.at(id).get(); } void CompilePass::run(){ - queryContext = reinterpret_cast (man->clasp->getQuery(QueryId::ContextQuery)); + transformations = new Transformations(this); + transformations->registerTransformer(new TransformerSaturation(transformations)); + + //targetInterpretation = new TargetInterpretation(this->man->root); + + queryContext = reinterpret_cast (man->clasp->getQuery(QueryId::ContextQuery)); //Find out main function; ClaspLayer::ModelFragment model = man->clasp->query(Config::get("function-entry")); assert(model && "Error: No entry function found"); assert(model->first != model->second && "Error: Ambiguous entry function"); string nameMain = std::get<0>(ClaspLayer::parse(model->first->second)); FunctionUnit* unitMain = getFunctionUnit(man->root->findFunction(nameMain)); entry = unitMain->compile(); } llvm::Function* CompilePass::getEntryFunction(){ assert(entry); return entry; } void CompilePass::prepareQueries(ClaspLayer* clasp){ clasp->registerQuery(new containers::Query(), QueryId::ContainersQuery); clasp->registerQuery(new ContextQuery(), QueryId::ContextQuery); } //CODESCOPE COMPILATION PHASE //FIND SYMBOL(compilation phase): //if (!forceCompile) //{ // return result; //} // //search in already compiled vars //if (__rawVars.count(vId)) //{ // return result; //} //if (!__declarations.count(vId)) { // //error: symbol is uncompiled scope arg // assert(false); //} //const Expression& e = __declarations.at(vId); //__rawVars[vId] = process(e, l, name); //FIND FUNCTION //llvm::Function* //CompilePass::findFunction(const std::string& name){ // ManagedFnPtr calleeFunc = man->root->findFunction(name); // assert(calleeFunc.isValid()); // return nullptr; //} diff --git a/cpp/src/pass/compilepass.h b/cpp/src/pass/compilepass.h index 17b4bdf..54fb72d 100644 --- a/cpp/src/pass/compilepass.h +++ b/cpp/src/pass/compilepass.h @@ -1,101 +1,120 @@ #ifndef COMPILEPASS_H #define COMPILEPASS_H #include #include "abstractpass.h" #include "llvm/IR/Function.h" namespace xreate { class AdhocScheme; class ClaspLayer; class ContextQuery; class CallStatement; } namespace xreate { class CompilePass; namespace compilation { class CodeScopeUnit; class FunctionUnit; +class TargetInterpretation; + struct Context{ - FunctionUnit* function; CodeScopeUnit* scope; + FunctionUnit* function; CompilePass* pass; }; class CodeScopeUnit { public: CodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass); - void bindArg(llvm::Value* var, std::string&& name); + void bindArg(llvm::Value* value, std::string&& alias); + void overrideDeclaration(const Symbol binding, Expression&& declaration); std::map __rawVars; void reset(){raw = nullptr;} llvm::Value* compile(const std::string& hintBlockDecl=""); llvm::Value* compileSymbol(const Symbol& s, std::string hintRetVar=""); llvm::Value* process(const Expression& expr, const std::string& hintVarDecl=""); + llvm::Value* processLowlevel(const Expression& expr, const std::string& hintVarDecl=""); + CodeScope* scope; private: CompilePass* pass; llvm::Value* raw = nullptr; FunctionUnit* function; + std::unordered_map __declarationsOverriden; + CallStatement* findFunction(const std::string& callee); }; -class FunctionUnit{ +class IFunctionDecorator { +protected: + virtual std::string prepareName() = 0; + virtual std::vector prepareArguments() = 0; + virtual llvm::Type* prepareResult() = 0; + virtual void prepareBindings() = 0; + virtual ~IFunctionDecorator(){} +}; + +class FunctionUnit: public IFunctionDecorator{ public: FunctionUnit(ManagedFnPtr f, CompilePass* p) - : function(f), pass(p), contextCompiler(this, p) {} - - llvm::Value* compileInline(std::vector&& args, FunctionUnit* outer); - bool isInline(); - llvm::Function* compile(); - - CodeScopeUnit* getEntry(); - CodeScopeUnit* getScopeUnit(CodeScope* scope); - CodeScopeUnit* getScopeUnit(ManagedScpPtr scope); - - ManagedFnPtr function; - llvm::Function* raw = nullptr; - AdhocScheme* adhocImplementation=nullptr; //SECTIONTAG adhoc prefunc scheme declaration - + : function(f), pass(p) {} + + llvm::Function* compile(); + + CodeScopeUnit* getEntry(); + CodeScopeUnit* getScopeUnit(CodeScope* scope); + CodeScopeUnit* getScopeUnit(ManagedScpPtr scope); + + ManagedFnPtr function; + llvm::Function* raw = nullptr; + +protected: + std::string prepareName(); + std::vector prepareArguments(); + llvm::Type* prepareResult(); + private: - CompilePass* pass; - std::map> scopes; - -public: - LateContextCompiler2 contextCompiler; + CompilePass* pass; + std::map> scopes; }; + class Transformations; } // end of namespace `xreate::compilation` class CompilePass : public AbstractPass { friend class LateContextCompiler; friend class LateContextCompiler2; friend class compilation::CodeScopeUnit; friend class compilation::FunctionUnit; public: + compilation::Transformations* transformations; + CompilePass(PassManager* manager): AbstractPass(manager) {} compilation::FunctionUnit* getFunctionUnit(const ManagedFnPtr& function); void run() override; llvm::Function* getEntryFunction(); static void prepareQueries(ClaspLayer* clasp); - private: - std::map> functions; + std::map functions; llvm::Function* entry = 0; ContextQuery* queryContext; + compilation::TargetInterpretation* targetInterpretation; + }; } #endif // COMPILEPASS_H diff --git a/cpp/src/pass/dfapass.cpp b/cpp/src/pass/dfapass.cpp new file mode 100644 index 0000000..2939d08 --- /dev/null +++ b/cpp/src/pass/dfapass.cpp @@ -0,0 +1,256 @@ +#include "pass/dfapass.h" +#include "analysis/dfagraph.h" + +#include "passmanager.h" +#include "clasplayer.h" + +#include + +using namespace std; +using namespace xreate::analysis; + +namespace xreate{ + +DFAPass::DFAPass(PassManager* manager) + : AbstractPass(manager) + , __context{new xreate::analysis::DFAGraph(manager->clasp)} + , clasp(manager->clasp) +{} + +SymbolNode +DFAPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl){ + const SymbolNode& retActual = AbstractPass::process(scope, context, hintBlockDecl); + const SymbolPacked& retFormal{0, clasp->pack(scope)}; + __context.graph->addConnection(retFormal, retActual, DFGConnection::STRONG); + + return retFormal; +} + +SymbolNode +DFAPass::process(const Expression& expression, PassContext context, const std::string& decl) +{ + ExpressionCache cache; + + if (!decl.empty()){ + cache.result = clasp->pack(context.scope->findSymbol(decl), context.function->getName() + ":" + decl); + + } else if (!expression.tags.empty()) { + cache.result = __context.graph->createAnonymousSymbol(clasp->pack(context.scope)); + + } else { + cache.result = SymbolTransient{{}, clasp->pack(context.scope)}; + } + + cache.operands.reserve(expression.getOperands().size()); + for (const Expression &op: expression.getOperands()) { + cache.operands.push_back(process(op, context)); + } + + cache.blocks.reserve(expression.blocks.size()); + for (CodeScope* scope: expression.blocks) { + cache.blocks.push_back(process(scope, context)); + } + + if (expression.__state != Expression::COMPOUND) { + processElementaryOp(expression, context, cache, decl); + + } else { + processCompoundOp(expression, context, cache, decl); + } + + applyDependencies(expression, context, cache, decl); + applyStaticAnnotations(expression, context, cache, decl); + applySignatureAnnotations(expression, context, cache, decl); + applyInPlaceAnnotations(expression, context, cache, decl); + +//TODO Null ad hoc DFG implementation +// if (expression.isNone()){ +// return SymbolTransient{{Atom(Config::get("clasp.nonevalue"))}}; +// } + + //non initialized(SymbolInvalid) value + + return cache.result; +} + + +void +DFAPass::processElementaryOp(const Expression& expression, PassContext context, DFAPass::ExpressionCache& cache, const std::string& varDecl){ + switch(expression.__state) { + case Expression::IDENT: { + std::string identifier = expression.getValueString(); + + SymbolNode nodeFrom = AbstractPass::process(expression, context, identifier); + if (SymbolPacked* nodeTo = boost::get(&cache.result)){ + __context.graph->addConnection(*nodeTo, nodeFrom, DFGConnection::STRONG); + } + + break; + } + + default: break; + } +} + +void +DFAPass::processCompoundOp(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& varDecl){ + + switch(expression.op) { + //apply calling relation + case Operator::CALL: { + const string &nameCalleeFunction = expression.getValueString(); + + //TODO implement processFnCall/Uncertain + list variantsCalleeFunction = man->root->getFunctionVariants(nameCalleeFunction); + if (variantsCalleeFunction.size()!=1) return; + ManagedFnPtr function= variantsCalleeFunction.front(); + + // set calling relations: + CodeScope *scopeRemote = function->getEntryScope(); + std::vector::iterator nodeActual = cache.operands.begin(); + for (const std::string &identFormal: scopeRemote->__bindings) { + const Symbol &symbolFormal = scopeRemote->findSymbol(identFormal); + __context.graph->addConnection(clasp->pack(symbolFormal, nameCalleeFunction + ":" + identFormal), *nodeActual, DFGConnection::WEAK); + ++nodeActual; + } + + //TODO represent RET connection + break; + } + + //apply PROTOTYPE relation + case Operator::MAP: { + SymbolNode nodeFrom= cache.operands.front(); + + SymbolPacked* nodeFromPacked = boost::get(&nodeFrom); + assert(nodeFromPacked); + + SymbolPacked* nodeTo = boost::get(&cache.result); + assert(nodeTo); + + __context.graph->addConnection(*nodeTo, *nodeFromPacked, DFGConnection::PROTOTYPE); + break; + } + + default: break; + } +} + +void +DFAPass::applyDependencies(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl){ + for (SymbolNode &op: cache.operands) { + __context.graph->addDependencyConnection(cache.result, op); + } + + for (SymbolNode &block: cache.blocks) { + __context.graph->addDependencyConnection(cache.result, block); + } + + switch(expression.__state) { + case Expression::IDENT: { + const string& identName = expression.getValueString(); + + SymbolNode identSymbol = clasp->pack(context.scope->findSymbol(identName), context.function->getName() + ":" + identName); + __context.graph->addDependencyConnection(cache.result, identSymbol); + } + + default: break; + } +} + +void +DFAPass::applyStaticAnnotations(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl){ + + switch(expression.__state) { + case Expression::NUMBER: + case Expression::STRING: + __context.graph->addAnnotation(cache.result, Expression(Atom("static"))); + break; + + default: break; + } +} + +void +DFAPass::applySignatureAnnotations(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl){ + if (__signatures.count(expression.op)) { + const Expression &scheme = __signatures.at(expression.op); + + //TODO add possibility to specifi signature for a particular function +// if (expression.op == Operator::CALL || expression.op == Operator::INDEX){ +// string caption = expression.getValueString(); +// operands.push_back(process(Expression(move(caption)), context, "")); +// } + + std::vector::iterator arg = cache.operands.begin(); + std::vector::const_iterator tag = ++scheme.getOperands().begin(); + + while (tag != scheme.getOperands().end()) { + if (tag->__state != Expression::INVALID) { + __context.graph->addAnnotation(*arg, Expression(*tag)); + } + + ++arg; ++tag; + } + + //TODO represent RET connection +// Expression retTag = *scheme.getOperands().begin(); +// if (retTag.__state != Expression::INVALID) { +// __context.graph->addAnnotation(node, move(retTag)); +// } + } +} + +void +DFAPass::applyInPlaceAnnotations(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl){ + // write down in-place expression tags: + for (pair tag: expression.tags) { + __context.graph->addAnnotation(cache.result, Expression(tag.second)); + } +} + +void +DFAPass::run() +{ + init(); + return AbstractPass::run(); +} + +void +DFAPass::init() +{ + for (const Expression& scheme: man->root->__dfadata) + { + __signatures.emplace(scheme.op, scheme); + } +} + +void DFAPass::finish() +{ + man->clasp->setDFAData(move(__context.graph)); +} + +template<> +SymbolNode defaultValue(){return SymbolInvalid();}; + +} + + + + + +/* +if (SymbolTransient* symbT = boost::get(&symbolRet)){ + std::vector tags; + tags.reserve(symbT->tags.size()); + + const std::string stmntRetTag = Config::get("clasp.ret.tag"); + std::transform(symbT->tags.begin(), symbT->tags.end(), std::inserter(tags, tags.begin()), + [&stmntRetTag](const Expression& e) { + Expression tag(Operator::CALL, {Atom(string(stmntRetTag)), e}); + return Tag{e, TagModifier::NONE}; + }); + + clasp->cfagraph->addFunctionAnnotations(function->getName(), tags); +} +*/ \ No newline at end of file diff --git a/cpp/src/pass/dfapass.h b/cpp/src/pass/dfapass.h new file mode 100644 index 0000000..cc26e8c --- /dev/null +++ b/cpp/src/pass/dfapass.h @@ -0,0 +1,49 @@ +// Data Flow Graph determination pass + +#ifndef DFGPASS_H +#define DFGPASS_H + +#include "abstractpass.h" +#include "analysis/dfagraph.h" + +namespace xreate { + +class ClaspLayer; + +class DFAPass : public AbstractPass { +public: + xreate::analysis::SymbolNode process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl="") override; + xreate::analysis::SymbolNode process(const Expression& expression, PassContext context, const std::string& varDecl="") override; + + DFAPass(PassManager* manager); + + void init(); + void run(); + void finish(); + +private: + struct + { + xreate::analysis::DFAGraph* graph; + } __context; + + struct ExpressionCache{ + std::vector operands; + std::vector blocks; + xreate::analysis::SymbolNode result; + }; + + std::map __signatures; //DFA data for particular operators + ClaspLayer* clasp; + + void processCompoundOp(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& varDecl=""); + void processElementaryOp(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& varDecl=""); + + void applyDependencies(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl); + void applyInPlaceAnnotations(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl); + void applySignatureAnnotations(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl); + void applyStaticAnnotations(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl); +}; +}; + +#endif diff --git a/cpp/src/pass/dfgpass.cpp b/cpp/src/pass/dfgpass.cpp deleted file mode 100644 index da501ad..0000000 --- a/cpp/src/pass/dfgpass.cpp +++ /dev/null @@ -1,182 +0,0 @@ -#include "dfgpass.h" -#include "passmanager.h" -#include "clasplayer.h" -#include -using namespace std; - -namespace xreate{ -DFGPass::DFGPass(PassManager* manager) - : AbstractPass(manager), clasp(man->clasp) -{} - -SymbolNode -DFGPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl){ - /* - if (SymbolTransient* symbT = boost::get(&symbolRet)){ - std::vector tags; - tags.reserve(symbT->tags.size()); - - const std::string stmntRetTag = Config::get("clasp.ret.tag"); - std::transform(symbT->tags.begin(), symbT->tags.end(), std::inserter(tags, tags.begin()), - [&stmntRetTag](const Expression& e) { - Expression tag(Operator::CALL, {Atom(string(stmntRetTag)), e}); - return Tag{e, TagModifier::NONE}; - }); - - clasp->cfagraph.addFunctionAnnotations(function->getName(), tags); - } - */ - - const SymbolNode& retActual = AbstractPass::process(scope, context, hintBlockDecl); - const SymbolPacked& retFormal{0, clasp->pack(scope)}; - __context.graph.addConnection(retFormal, retActual, DFGConnection::ALIAS); - - return retFormal; -} - -SymbolNode -DFGPass::process(const Expression& expression, PassContext context, const std::string& decl) -{ - // write down adhoc expression tags: - if (expression.tags.size() && decl.length()) { - for (pair tag: expression.tags) { - SymbolNode nodeThis = clasp->pack(context.scope->findSymbol(decl), context.function->getName() + ":" + decl); - __context.graph.addAnnotation(nodeThis, Expression(tag.second)); - } - } - - switch(expression.__state) { - case Expression::IDENT: { - const string& ident = expression.getValueString(); - SymbolNode nodeFrom = AbstractPass::process(expression, context, decl); - SymbolPacked nodeTo = clasp->pack(context.scope->findSymbol(ident), context.function->getName() + ":" + ident); - - __context.graph.addConnection(nodeTo, nodeFrom, DFGConnection::ALIAS); - return nodeTo; - } - - default: break; - } - -//TODO Null ad hoc DFG implementation -// if (expression.isNone()){ -// return SymbolTransient{{Atom(Config::get("clasp.nonevalue"))}}; -// } - - switch(expression.op) { - case Operator::CALL: { - const string &name = expression.getValueString(); - - std::vector operands; - operands.reserve(expression.getOperands().size()); - - for (const Expression &op: expression.getOperands()) { - operands.push_back(process(op, context)); - } - - //TODO implement processFnCall/Uncertain - list functions = man->root->getFunctionVariants(name); - if (functions.size()!=1) return SymbolInvalid(); - ManagedFnPtr function= functions.front(); - - // set calling relations: - CodeScope *scopeRemote = function->getEntryScope(); - std::vector::iterator nodeActual = operands.begin(); - for (const std::string &identFormal: scopeRemote->__args) { - const Symbol &symbolFormal = scopeRemote->findSymbol(identFormal); - __context.graph.addConnection(clasp->pack(symbolFormal, name + ":" + identFormal), *nodeActual, DFGConnection::OPT); - ++nodeActual; - } - - //TODO need SymbolTransient::connection mark in order to represent OPT connection - return clasp->pack(Symbol{0, scopeRemote}, name + ": *retv"); - } - - default: break; - } - - - - SymbolNode result = AbstractPass::process(expression, context, decl); - - if (expression.__state != Expression::COMPOUND){ - return result; - } - - std::vector operands; - if (__signatures.count(expression.op)) { - const Expression &scheme = __signatures.at(expression.op); - - operands.reserve(expression.getOperands().size()); - - if (expression.op == Operator::CALL || expression.op == Operator::INDEX){ - string caption = expression.getValueString(); - operands.push_back(process(Expression(move(caption)), context, "")); - } - - for (const Expression &op: expression.getOperands()) { - operands.push_back(process(op, context)); - } - - std::vector::iterator arg = operands.begin(); - std::vector::const_iterator tag = ++scheme.getOperands().begin(); - - while (tag != scheme.getOperands().end()) { - if (tag->__state != Expression::INVALID) { - __context.graph.addAnnotation(*arg, Expression(*tag)); - } - - ++arg; ++tag; - } - - Expression retTag = *scheme.getOperands().begin(); - if (retTag.__state != Expression::INVALID) { - __context.graph.addAnnotation(result, move(retTag)); - } - } - - // adhoc for MAP case, TODO reorganize code in more clear manner - if (expression.op == Operator::MAP) { - SymbolNode nodeFrom; - - if (operands.size()) { - nodeFrom = operands.at(0); - } else { - nodeFrom = process(expression.getOperands().at(0), context); - } - - assert(!decl.empty()); - SymbolPacked nodeTo = clasp->pack(context.scope->findSymbol(decl), context.function->getName() + ":" + decl); - SymbolPacked* nodeFromPacked = boost::get(&nodeFrom); - assert(nodeFromPacked); - __context.graph.addConnection(move(nodeTo), *nodeFromPacked, DFGConnection::PROTO); - } - - return result; -} - -void -DFGPass::run() -{ - init(); - return AbstractPass::run(); -} - -void -DFGPass::init() -{ - for (const Expression& scheme: man->root->__dfadata) - { - __signatures.emplace(scheme.op, scheme); - } -} - -void DFGPass::finish() -{ - man->clasp->addDFAData(move(__context.graph)); -} - -template<> -SymbolNode defaultValue(){return SymbolInvalid();}; - -} diff --git a/cpp/src/pass/dfgpass.h b/cpp/src/pass/dfgpass.h deleted file mode 100644 index d29ecf3..0000000 --- a/cpp/src/pass/dfgpass.h +++ /dev/null @@ -1,34 +0,0 @@ -// Data Flow Graph determination pass - -#ifndef DFGPASS_H -#define DFGPASS_H - -#include "abstractpass.h" -#include "clasplayer.h" - -namespace xreate { - -class ClaspLayer; - -class DFGPass : public AbstractPass { -public: - SymbolNode process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl=""); - SymbolNode process(const Expression& expression, PassContext context, const std::string& varDecl="") override; - - DFGPass(PassManager* manager); - - void init(); - void run(); - void finish(); -private: - struct - { - DFAGraph graph; - } __context; - - std::map __signatures; //DFA data for particular operators - ClaspLayer* clasp; -}; -}; - -#endif diff --git a/cpp/src/pass/interpretationpass.cpp b/cpp/src/pass/interpretationpass.cpp new file mode 100644 index 0000000..968efa4 --- /dev/null +++ b/cpp/src/pass/interpretationpass.cpp @@ -0,0 +1,334 @@ +/* + * File: interpretationpass.cpp + * Author: pgess + * + * Created on July 5, 2016, 5:21 PM + */ + +#include "pass/interpretationpass.h" +#include "compilation/transformations.h" +#include +#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(){ + return CMPL_ONLY; +} + +InterpretationResolution +unify(InterpretationResolution flag) { + return flag; +} + +template +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 + bool checkConstraints(InterpretationResolution flag) { + return ( (flag==INTR_ONLY && FLAG_REQUIRED == QUERY_INTR_ONLY) + || (flag==CMPL_ONLY && FLAG_REQUIRED == QUERY_CMPL_ONLY)); + } +} + +template +bool checkConstraints(std::vector&& flags) { + assert(flags.size()); + + InterpretationResolution flag = flags.front(); + return detail::checkConstraints(flag); +} + +template +bool checkConstraints(std::vector&& flags) { + assert(flags.size()); + + InterpretationResolution flag = flags.front(); + flags.pop_back(); + + if (detail::checkConstraints(flag)){ + return checkConstraints(move(flags)); + } + + return false; +} + +void +setSpecializedOperator(const Expression& expression, const InterpretationOperator& op){ + if (Attachments::exists(expression)){ + InterpretationData& data = Attachments::get(expression); + data.op = op; + + } else { + Attachments::put(expression, {BOTH, op}); + } + + compilation::Transformations::subscribe(expression); +} + +InterpretationResolution +recognizeTags(const map& 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(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 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({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({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({flagHeaders})){ + setSpecializedOperator(expression, SWITCH_INTERPRET_CONDITION); + flagHeaders = BOTH; + } + + //determine body resolutions + resolution = flagHeaders; + for (size_t size = expression.operands.size(), i= 1; i(expression, {BOTH, NONE}) + .resolution; + + resolution = unify(resolution, resolutionExpected); + if (resolution == INTR_ONLY){ + Attachments::put(expression, {INTR_ONLY, NONE}); + compilation::Transformations::subscribe(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 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); + } +} +- \ No newline at end of file diff --git a/cpp/src/pass/interpretationpass.h b/cpp/src/pass/interpretationpass.h new file mode 100644 index 0000000..0992d6e --- /dev/null +++ b/cpp/src/pass/interpretationpass.h @@ -0,0 +1,47 @@ +/* + * File: interpretationpass.h + * Author: pgess + * + * Created on July 5, 2016, 5:21 PM + */ + +#ifndef INTERPRETATIONPASS_H +#define INTERPRETATIONPASS_H + +#include "abstractpass.h" + +namespace xreate { + + enum InterpretationResolution{BOTH, INTR_ONLY, CMPL_ONLY, POSTPONED}; + enum InterpretationOperator{NONE, IF_INTERPRET_CONDITION, FOLD_INTERPRET_INPUT, SWITCH_INTERPRET_CONDITION}; + + struct InterpretationData{ + InterpretationResolution resolution; + InterpretationOperator op; + }; + + template<> + InterpretationResolution + defaultValue(); + + template<> + struct AttachmentsDict + { + typedef InterpretationData Data; + static const unsigned int key = 3; + }; + + class InterpretationPass: public AbstractPass { + typedef AbstractPass Parent; + + public: + InterpretationResolution process(const Expression& expression, PassContext context, const std::string& varDecl="") override; + InterpretationResolution process(ManagedFnPtr function); + + InterpretationPass(PassManager* manager); + }; +} + + +#endif /* INTERPRETATIONPASS_H */ + diff --git a/cpp/src/pass/loggerpass.cpp b/cpp/src/pass/loggerpass.cpp index ce8e552..f4471c8 100644 --- a/cpp/src/pass/loggerpass.cpp +++ b/cpp/src/pass/loggerpass.cpp @@ -1,106 +1,108 @@ /* * logging.cpp * * Created on: Jun 23, 2015 * Author: pgess */ #include -#include "compilation/instr-containers.h" +#include "compilation/containers.h" #include "utils.h" using namespace std; using namespace llvm; namespace xreate { void LoggerPass::init(ClaspLayer* clasp){ auto model = clasp->query(Config::get("logging.id")); if(!model) return; for (ClaspLayer::ModelIterator rec = model->first; rec!=model->second; ++rec){ std::tuple _v =ClaspLayer::parse(rec->second); Symbol v = clasp->unpack(get<0>(_v)); - SymbolAttachments::put(v, true); + Attachments::put(v, true); } } void LoggerPass::process(const Expression& expression, PassContext context, const std::string& varDecl){ if (varDecl.size()){ Symbol v = context.scope->findSymbol(varDecl); - if (SymbolAttachments::get(v, false)){ + if (Attachments::get(v, false)){ compilation::FunctionUnit* func = compiler->getFunctionUnit(context.function); compilation::CodeScopeUnit* scope = func->getScopeUnit(context.scope); - compilation::Context compilationContext{func, scope, compiler}; + compilation::Context compilationContext{scope, func, compiler}; inject(v, compilationContext); } } return AbstractPass::process(expression, context, varDecl); } void LoggerPass::inject(const Symbol& symbol, const compilation::Context& context){ - llvm::Value* source = context.scope->compileSymbol(symbol); - ExpandedType typSource = man->root->expandType(CodeScope::findDefinition(symbol)); - string format = ""; - switch (typSource->__value) { - case TypePrimitive::Int : case TypePrimitive::Num : case TypePrimitive::I32: case TypePrimitive::I8: - format = "%d\n"; - break; - - case TypePrimitive::String: - format = "%s\n"; - break; - - default: - assert(false && "No appropriate type for logging"); - } - - containers::Instructions compiler(context); - - LLVMLayer* llvm = context.pass->man->llvm; - llvm->builder.SetInsertPoint(*source->use_begin()); - llvm::Value* formatRaw = compiler.compileConstantStringAsPChar(format, "logformat"); - - llvm->builder.CreateCall2(refPrintf, formatRaw, source); + //TODO fix log injection + +// llvm::Value* source = context.scope->compileSymbol(symbol); +// ExpandedType typSource = man->root->expandType(CodeScope::findDefinition(symbol).type); +// string format = ""; +// switch (typSource->__value) { +// case TypePrimitive::Int : case TypePrimitive::Num : case TypePrimitive::I32: case TypePrimitive::I8: +// format = "%d\n"; +// break; +// +// case TypePrimitive::String: +// format = "%s\n"; +// break; +// +// default: +// assert(false && "No appropriate type for logging"); +// } +// +// xreate::compilation::Advanced instructions(context); +// +// LLVMLayer* llvm = context.pass->man->llvm; +// llvm->builder.SetInsertPoint(llvm->builder.GetInsertBlock(), *source->use_begin()); +// llvm::Value* formatRaw = instructions.compileConstantStringAsPChar(format, "logformat"); +// +// llvm->builder.CreateCall2(refPrintf, formatRaw, source); } void LoggerPass::initOutput(){ LLVMLayer* llvm = man->llvm; refPrintf = llvm->module->getFunction("printf"); if (!refPrintf) { PointerType* typPtrI8 = PointerType::get(IntegerType::get(llvm->module->getContext(), 8), 0); std::vectorargsPrintf{typPtrI8}; FunctionType* signaturePrintf = FunctionType::get( /*Result=*/IntegerType::get(llvm->module->getContext(), 32), /*Params=*/argsPrintf, /*isVarArg=*/true); refPrintf = llvm::Function::Create( /*Type=*/signaturePrintf, /*Linkage=*/GlobalValue::ExternalLinkage, /*Name=*/"printf", llvm->module); // (external, no body) refPrintf->setCallingConv(CallingConv::C); } } LoggerPass::LoggerPass(PassManager* manager) : AbstractPass(manager) { initOutput(); init(man->clasp); } void LoggerPass::initDependencies(CompilePass* pass){ compiler = pass; } } /* namespace xreate */ diff --git a/cpp/src/pass/loggerpass.h b/cpp/src/pass/loggerpass.h index 2c15b70..252e9c8 100644 --- a/cpp/src/pass/loggerpass.h +++ b/cpp/src/pass/loggerpass.h @@ -1,44 +1,44 @@ /* * logging.h * * Created on: Jun 23, 2015 * Author: pgess */ #ifndef SRC_LOGGING_H_ #define SRC_LOGGING_H_ #include "ast.h" #include #include "pass/compilepass.h" #include "pass/abstractpass.h" #include "clasplayer.h" namespace xreate { class LoggerPass:public AbstractPass, public IQuery { public: void inject(const Symbol& symbol, const compilation::Context& context); LoggerPass(PassManager* manager); virtual void init(ClaspLayer* clasp); void initDependencies(CompilePass* pass); virtual void process(const Expression& expression, PassContext context, const std::string& varDecl=""); private: CompilePass* compiler = nullptr; llvm::Function* refPrintf; void initOutput(); }; struct IsLogging{}; template<> struct AttachmentsDict { typedef bool Data; - static const unsigned int key = 5; + static const unsigned int key = 2; }; } /* namespace xreate */ #endif /* SRC_LOGGING_H_ */ diff --git a/cpp/src/passmanager.cpp b/cpp/src/passmanager.cpp index 5f2dac3..ccc9338 100644 --- a/cpp/src/passmanager.cpp +++ b/cpp/src/passmanager.cpp @@ -1,112 +1,120 @@ #include #include #include "query/containers.h" #include "passmanager.h" #include "pass/compilepass.h" #include "pass/adhocpass.h" #include "Parser.h" -#include "pass/cfgpass.h" -#include "pass/dfgpass.h" +#include "pass/cfapass.h" +#include "pass/dfapass.h" #include #include using namespace xreate; using namespace std; PassManager* PassManager::prepareForCode(std::string&& code){ Scanner scanner(reinterpret_cast(code.c_str()), code.size()); return prepareForCode(&scanner); } PassManager* PassManager::prepareForCode(FILE* code){ Scanner scanner(code); return prepareForCode(&scanner); } PassManager* PassManager::prepareForCode(Scanner* code){ - Parser parser(code); - parser.Parse(); - assert(!parser.errors->count && "Parser errors"); + Parser parser(code); + parser.Parse(); + assert(!parser.errors->count && "Parser errors"); - PassManager* man = new PassManager; - AST* ast = new AST(parser.root); + PassManager* man = new PassManager; + AST* ast = new AST(parser.root); - man->root = ast; - man->clasp = new ClaspLayer(); + man->root = ast; + man->clasp = new ClaspLayer(); - man->clasp->ast = man->root; - man->llvm = new LLVMLayer(man->root); + man->clasp->ast = man->root; + man->llvm = new LLVMLayer(man->root); - CFGPass* passCFG = new CFGPass(man); - - //TODO is it really DFGPass needs CFGpass? - man->registerPass(new DFGPass(man), PassId::DFGPass, passCFG); - man->registerPass(passCFG, PassId::CFGPass); - man->registerPass(new AdhocPass(man), PassId::AdhocPass); - - CompilePass::prepareQueries(man->clasp); - - return man; + CompilePass::prepareQueries(man->clasp); + return man; } void PassManager::registerPass(AbstractPassBase* pass, const PassId& id, AbstractPassBase* parent) { - __passes.emplace(id, pass); + __passes.emplace(id, pass); __passDependencies.emplace(parent, pass); } AbstractPassBase* PassManager::getPassById(const PassId& id){ assert(__passes.count(id)); return __passes[id]; } +bool +PassManager::isPassRegistered(const PassId& id){ + return __passes.count(id); +} + +void +PassManager::executePasses(){ + std::list passes{nullptr}; + while (passes.size()){ + AbstractPassBase* parent = passes.front(); + + auto range = __passDependencies.equal_range(parent); + + for (auto i=range.first; i!=range.second; ++i){ + AbstractPassBase* pass = i->second; + + pass->run(); + pass->finish(); + + passes.push_back(pass); + } + + passes.pop_front(); + } +} + void* PassManager::run() { - runWithoutCompilation(); + runWithoutCompilation(); CompilePass* compiler = new CompilePass(this); compiler->run(); //Compiler Dependents: LoggerPass* logger = new LoggerPass(this); logger->initDependencies(compiler); logger->run(); llvm->print(); llvm->initJit(); return llvm->getFunctionPointer(compiler->getEntryFunction()); } void PassManager::runWithoutCompilation(){ - if (flagIsProcessed) return; - - std::list passes{nullptr}; - while (passes.size()){ - AbstractPassBase* parent = passes.front(); - - auto range = __passDependencies.equal_range(parent); - - for (auto i=range.first; i!=range.second; ++i){ - AbstractPassBase* pass = i->second; - - pass->run(); - pass->finish(); - - passes.push_back(pass); - } - - passes.pop_front(); - } - + if (flagIsProcessed) return; + + CFAPass* passCFG = new CFAPass(this); + + //TODO is it really DFGPass needs CFGpass? + this->registerPass(new DFAPass(this), PassId::DFGPass, passCFG); + this->registerPass(passCFG, PassId::CFGPass); + this->registerPass(new AdhocPass(this), PassId::AdhocPass); + + this->executePasses(); clasp->run(); flagIsProcessed = true; } PassManager::~PassManager(){} diff --git a/cpp/src/passmanager.h b/cpp/src/passmanager.h index 86de4f3..cb55967 100644 --- a/cpp/src/passmanager.h +++ b/cpp/src/passmanager.h @@ -1,53 +1,56 @@ #ifndef PASSMANAGER_H #define PASSMANAGER_H #include #include //stdio external struct _IO_FILE; typedef struct _IO_FILE FILE; class Scanner; namespace xreate { class AbstractPassBase; class ClaspLayer; class LLVMLayer; class AST; enum class PassId { CFGPass, CompilePass, DFGPass, EnvironmentTestsPass, LoggerPass, AdhocPass, - RulesPass + RulesPass, + InterpretationPass }; class PassManager { public: ~PassManager(); void*run(); void runWithoutCompilation(); + void executePasses(); void registerPass(AbstractPassBase* pass, const PassId& id, AbstractPassBase* prerequisite=nullptr); AbstractPassBase* getPassById(const PassId& id); + bool isPassRegistered(const PassId& id); static PassManager* prepareForCode(std::string&& code); static PassManager* prepareForCode(FILE* code); ClaspLayer* clasp; LLVMLayer* llvm; AST* root; private: //typedef std::multimap FILTERS_STORAGE; //FILTERS_STORAGE __filters; std::map __passes; std::multimap __passDependencies; bool flagIsProcessed = false; static PassManager* prepareForCode(Scanner* code); }; } #endif diff --git a/cpp/src/query/containers.cpp b/cpp/src/query/containers.cpp index 662f41e..8f37165 100644 --- a/cpp/src/query/containers.cpp +++ b/cpp/src/query/containers.cpp @@ -1,163 +1,164 @@ // // Created by pgess on 3/14/15. // #include #include "query/containers.h" using namespace std; using namespace xreate::containers; using namespace xreate; Implementation Query::queryImplementation(xreate::Symbol const &s) { + typedef Attachments attach; - typedef SymbolAttachments attach; - if (attach::exists(s)) + if (attach::exists(s)) { - return attach::get(s); + return attach::get(s); } return Implementation::create(s); } void Query::init(ClaspLayer* clasp) { if (flagIsDataLoaded) return; map prototypes; map roots; //read all proto data auto range = clasp->query(Config::get("containers.id.prototypes")); if (range) for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) { auto data = ClaspLayer::parse(atom->second); Symbol root = clasp->unpack(get<0> (data)); Symbol prototype = clasp->unpack(get<1> (data)); prototypes[root] = prototype; } // fill implementation data for a data sources: range = clasp->query(Config::get("containers.id.implementations")); if (range) for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) { auto data = ClaspLayer::parse(atom->second); Symbol var = clasp->unpack(get<0>(data)); string implSerialized = get<1>(data); //data source, has no prototypes: if (!prototypes.count(var)) { Implementation impl = Implementation::create(var); - SymbolAttachments::put(var, move(impl)); + Attachments::put(var, move(impl)); continue; } roots.emplace(move(var), move(implSerialized)); } //fill implementation data for a cluster roots for (const pair & root: roots) { Symbol prototype = prototypes[root.first]; while (prototypes.count(prototype)) { prototype = prototypes.at(prototype); } - SymbolAttachments::put(root.first, Implementation(SymbolAttachments::get(prototype))); + Attachments::put(root.first, Implementation(Attachments::get(prototype))); } // read cluster data and fill implementation data for cluster members range = clasp->query(Config::get("containers.id.clusters")); if (range) for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) { auto info = ClaspLayer::parse(atom->second); Symbol root = clasp->unpack(get<0>(info)); Symbol child = clasp->unpack(get<1>(info)); if (!(child == root)) { - Implementation rootImpl = SymbolAttachments::get(root); - SymbolAttachments::put(child, move(rootImpl)); + Implementation rootImpl = Attachments::get(root); + Attachments::put(child, move(rootImpl)); } } flagIsDataLoaded = true; } //static ImplementationData* create(Symbol var, std::string implSerialized, const ImplementationData* implPrototype); Implementation Implementation::create(const Symbol &var) { + //TODO review implementation determination strategy Expression varDecl = CodeScope::findDeclaration(var); switch (varDecl.op) { case Operator::LIST_RANGE: { ImplementationRec rec{var}; return {ON_THE_FLY, rec}; } case Operator::LIST: { return {SOLID, ImplementationRec {varDecl.getOperands().size()}}; } - default: break; + default: break; }; ImplementationLinkedList ill(var); if (ill){ return ill.getImplementationData(); } assert(false && "Unable to determine proper implementation for the symbol"); } Implementation Implementation::create(const Symbol& var, const std::string& implSerialized) { Expression varDecl = CodeScope::findDeclaration(var); if (implSerialized == Config::get("containers.impl.solid")) { return {SOLID, ImplementationRec{varDecl.operands.size()}}; } else if (implSerialized == Config::get("containers.impl.onthefly")) { return {ON_THE_FLY, ImplementationRec{var}}; } assert(false && "unable to determine proper implementation for the symbol"); } ImplementationLinkedList::ImplementationLinkedList(const Symbol& source) : flagIsValid(false), s(source){ const Expression& sourceExpr = CodeScope::findDeclaration(source); if (sourceExpr.tags.count(Config::get("containers.id.linkedlist"))){ flagIsValid = true; Expression tagLinkedlist = sourceExpr.tags.at(Config::get("containers.id.linkedlist")); assert(tagLinkedlist.operands.size() == 2); fieldPointer = tagLinkedlist.operands.at(0).getValueString(); terminator = tagLinkedlist.operands.at(1); } } ImplementationLinkedList:: operator bool () const{ return flagIsValid; } Implementation ImplementationLinkedList::getImplementationData() const { return {ON_THE_FLY, ImplementationRec{s}}; } diff --git a/cpp/src/query/containers.h b/cpp/src/query/containers.h index 663b08c..ec474d0 100644 --- a/cpp/src/query/containers.h +++ b/cpp/src/query/containers.h @@ -1,83 +1,83 @@ // // Created by pgess on 3/14/15. // #ifndef _XREATE_CONTAINERSQUERY_H_ #define _XREATE_CONTAINERSQUERY_H_ #include "passmanager.h" #include "clasplayer.h" #include namespace xreate { namespace containers { - enum ImplementationType {SOLID, ON_THE_FLY, LINKED_LIST}; + enum ImplementationType {SOLID, ON_THE_FLY, LINKED_LIST}; template struct ImplementationRec; template<> struct ImplementationRec { size_t size; }; template<> struct ImplementationRec{ Symbol source; }; struct Implementation; struct ImplementationLinkedList { bool flagIsValid; std::string fieldPointer; Expression terminator; ImplementationLinkedList(const Symbol& source); operator bool() const; Implementation getImplementationData() const; private: Symbol s; }; struct Implementation { typedef boost::variant, ImplementationRec> Variant; const ImplementationType impl; Variant data; static Implementation create(const Symbol &var); static Implementation create(const Symbol& var, const std::string &implSerialized); static Implementation create(const Symbol& var, const Implementation& proto); template const ImplementationRec& extract() const{ const ImplementationRec& rec = boost::get>(data); return rec; } }; class Query : public xreate::IQuery { public: static Implementation queryImplementation(xreate::Symbol const &s); void init(ClaspLayer* clasp); ~Query(){} private: bool flagIsDataLoaded = false; PassManager *man; }; } template<> struct AttachmentsDict { typedef containers::Implementation Data; static const unsigned int key = 1; }; } #endif //_XREATE_CONTAINERSQUERY_H_ diff --git a/cpp/src/query/context.cpp b/cpp/src/query/context.cpp index 732ca16..efa6af1 100644 --- a/cpp/src/query/context.cpp +++ b/cpp/src/query/context.cpp @@ -1,167 +1,244 @@ /* * adhoc.cpp * * Created on: Dec 1, 2015 * Author: pgess */ #include #include #include using namespace std; namespace xreate { -ContextQuery::ContextQuery() - : domainEmpty(vector()) {} +const Domain domainEmpty; +const Decisions decisionsEmpty; +const FunctionDemand functionDemandEmpty; + +bool operator < (const Expression&a, const Expression&b) { + if (a.__state != b.__state) return a.__state < b.__state; + assert(a.__state != Expression::INVALID); + switch(a.__state) { + case Expression::IDENT: + case Expression::STRING: + case Expression::VARIANT: + return a.getValueString() < b.getValueString(); + + case Expression::NUMBER: + return a.getValueDouble() < b.getValueDouble(); + + case Expression::COMPOUND: { + assert(a.op == Operator::CALL); + assert(a.blocks.size()==0); + assert(b.blocks.size()==0); + + if (a.operands.size() != b.operands.size()){ + return (a.operands.size() < b.operands.size()); + } + + if (a.getValueString() != b.getValueString()){ + return a.getValueString() < b.getValueString(); + } + + for(size_t i=0; ipack(scope)); } - +//DEBT compatibility of forced context with context resolution for interpretation void ContextQuery::forceContext(const ScopePacked& scopeId, std::list context){ // TODO remove forced context of the same class/type only, possibly //remove any previous forced context for this scopeId //__modelForcedContext.erase(scopeId); //TASK restore forceContext //std::multimap __modelForcedContext; /* std::transform(context.begin(), context.end(), inserter(__modelForcedContext, __modelForcedContext.end()), [scopeId](const Expression& context){return make_pair(scopeId, context);}); */ } void ContextQuery::init(ClaspLayer* clasp){ const std::string& atomEarlyBinding = Config::get("clasp.bindings.scope"); this->clasp = clasp; ClaspLayer::ModelFragment query = clasp->query(atomEarlyBinding); - //static context + //static context if (query){ - map> dictContext; - - for (auto i = query->first; i!=query->second; ++i){ - ScopePacked idScope; - Expression context; - tie(idScope, context) = ClaspLayer::parse(i->second); - dictContext[idScope].push_back(context); - } - - for (map>::value_type& entry: dictContext){ - __modelContext.insert(move(entry)); - } + map> dictContext; + + for (auto i = query->first; i!=query->second; ++i){ + ScopePacked idScope; + Expression context; + tie(idScope, context) = ClaspLayer::parse(i->second); + dictContext[idScope].push_back(context); + } + + for (map>::value_type& entry: dictContext){ + __modelContext.insert(move(entry)); + } } - //static decisions - query = clasp->query(Config::get("clasp.bindings.scope_decision")); - if (query){ - for (auto i = query->first; i!=query->second; ++i){ - ScopePacked scopeId; - string function; - Expression specialization; - tie(scopeId, function, specialization) = ClaspLayer::parse(i->second); - ScopeContextDecisions& scope = __modelStaticDecisions[scopeId]; - assert(scope.emplace(function, specialization).second && "Possibly more than one decision"); - } - } + prepareFunctionDemandModel(); + prepareDecisionModels(); +} - //Fetch function specialization domains - std::multimap modelDomains; - const list& functions = clasp->ast->getAllFunctions(); - for (auto f: functions){ - if (f->guardContext.isValid()){ - modelDomains.emplace(f->getName(), f->guardContext); - } - } - auto adapter = [](const std::pair& p){ return p.second; }; - - auto iBegin = modelDomains.begin(); - while (iBegin!=modelDomains.end()){ - string function = iBegin->first; - auto iEnd = modelDomains.upper_bound(function); - auto iBeginAdapted = boost::make_transform_iterator(iBegin,adapter); - auto iEndAdapted = boost::make_transform_iterator(iEnd,adapter); - ContextDomain dom(iBeginAdapted, iEndAdapted); - __modelFunctionDomain.emplace(function, move(dom)); - iBegin = iEnd; - } - prepareDemandModel(); -} +void +ContextQuery::prepareFunctionDemandModel(){ + const std::string& atomFunctionDemand = Config::get("clasp.bindings.function_demand"); + + ClaspLayer::ModelFragment query = clasp->query(atomFunctionDemand); + if (query) + for (auto i = query->first; i!=query->second; ++i){ + string function; + Expression topic; + tie(function, topic) = ClaspLayer::parse(i->second); -const ContextDomain& -ContextQuery::getFunctionDomain(const std::string& name) const { - if (__modelFunctionDomain.count(name)){ - return __modelFunctionDomain.at(name); + FunctionDemand& demand = __modelFunctionDemand[function]; + demand.left.insert(make_pair(demand.left.size(), topic)); } +} + +void +ContextQuery::prepareDecisionModels(){ + const std::string& atomDecision = Config::get("clasp.bindings.scope_decision"); + const std::string& atomDependentDecision = Config::get("clasp.context.decisions.dependent"); - return domainEmpty; + std::multimap modelDomains; + + + ClaspLayer::ModelFragment query = clasp->query(atomDecision); + if (query){ + for (auto i = query->first; i!=query->second; ++i){ + ScopePacked scopeId; + Expression topic; + Expression decision; + + std::tie(scopeId, topic, decision) = ClaspLayer::parse(i->second); + + if (decision.getValueString() == atomDependentDecision) { + assert(decision.operands.size() == 2); + + const Expression& decisionGuard = decision.operands[1]; + const Expression& decisionValue = decision.operands[0]; + + __modelDependentDecisions[scopeId][topic].emplace(decisionGuard, decisionValue); + modelDomains.emplace(topic, decisionValue); + + } else { + Decisions& decisionsOfScope = __modelStaticDecisions[scopeId]; + assert(decisionsOfScope.emplace(topic, decision).second && "Possibly more than one decision"); + modelDomains.emplace(topic, decision); + } + } + } + + + //populate topic domains: + auto adapter = [](const std::pair& p){ return p.second; }; + + auto iBegin = modelDomains.begin(); + while (iBegin!=modelDomains.end()){ + const Expression topic = iBegin->first; + auto iEnd = modelDomains.upper_bound(topic); + auto iBeginAdapted = boost::make_transform_iterator(iBegin,adapter); + auto iEndAdapted = boost::make_transform_iterator(iEnd,adapter); + Domain dom(iBeginAdapted, iEndAdapted); + __modelTopicDomains.emplace(topic, move(dom)); + iBegin = iEnd; + } } -const FunctionContextDemand& +const FunctionDemand& ContextQuery::getFunctionDemand(const std::string& name) const { if (__modelFunctionDemand.count(name)){ return __modelFunctionDemand.at(name); } - return decisionsEmpty; + return functionDemandEmpty; } -const ScopeContextDecisions& -ContextQuery::getStaticDecisions(const ScopePacked& scopeId){ +const Decisions& +ContextQuery::getFinalDecisions(const ScopePacked& scopeId) const{ if (__modelStaticDecisions.count(scopeId)){ - return __modelStaticDecisions[scopeId]; + return __modelStaticDecisions.at(scopeId); } - return contextDecisionsEmpty; + return decisionsEmpty; +} + +const Domain& +ContextQuery::getTopicDomain(const Expression& topic) const{ + if (__modelTopicDomains.count(topic)){ + return __modelTopicDomains.at(topic); + } + + return domainEmpty; } -void -ContextQuery::prepareDemandModel(){ - const std::string& atomFunctionDemand = Config::get("clasp.bindings.function_demand"); +const DependentDecision& +ContextQuery::getDependentDecision(ScopePacked scope, const Expression& topic) const{ + auto itDecisionsAllTopics = __modelDependentDecisions.find(scope); + if (itDecisionsAllTopics != __modelDependentDecisions.end()){ + auto itDecisions = itDecisionsAllTopics->second.find(topic); - ClaspLayer::ModelFragment query = clasp->query(atomFunctionDemand); - if (query) - for (auto i = query->first; i!=query->second; ++i){ - string function; - string decision; - tie(function, decision) = ClaspLayer::parse(i->second); + if (itDecisions != itDecisionsAllTopics->second.end()){ + return itDecisions->second; + } + } - FunctionContextDemand& decisions = __modelFunctionDemand[function]; - decisions.left.insert(make_pair(decisions.size(), decision)); - } + return decisionsEmpty; } // const std::string& atomLateBinding = Config::get("clasp.bindings.function_uncertain"); // query = clasp->query(atomLateBinding); // // std::map> dictFunctionDomain; // if (query){ // for (auto i = query->first; i!=query->second; ++i){ // string nameFunction; // Expression context; // tie(nameFunction, context) = ClaspLayer::parse(i->second); // dictFunctionDomain.at(nameFunction).push_back(context); // } // // for(auto& entry: dictFunctionDomain){ // __modelFunctionDomain.emplace(entry.first, move(entry.second)); // } // } } /* namespace xreate */ diff --git a/cpp/src/query/context.h b/cpp/src/query/context.h index 7117ac0..b32a021 100644 --- a/cpp/src/query/context.h +++ b/cpp/src/query/context.h @@ -1,89 +1,97 @@ /* * adhoc.h * * Created on: Dec 1, 2015 * Author: pgess */ #ifndef SRC_QUERY_CONTEXT_H_ #define SRC_QUERY_CONTEXT_H_ #include "clasplayer.h" #include "ast.h" #include "serialization.h" #include #include +#include +#include +#include +#include + namespace xreate { -typedef ExpressionSerialization::Serializer ContextDomain; -typedef boost::bimap FunctionContextDemand; -typedef std::map ScopeContextDecisions; +typedef ExpressionSerialization::Serializer Domain; +typedef boost::bimap FunctionDemand; +typedef std::map Decisions; +typedef std::map DependentDecision; class ContextQuery: public IQuery { -public: //AdhocQuery(); - const ContextDomain& getContext(const ScopePacked& scopeId); - const ContextDomain& getContext(CodeScope* const scope); +public: + const Domain& getContext(const ScopePacked& scopeId) const; + const Domain& getContext(CodeScope* const scope) const; void forceContext(const ScopePacked& scopeId, std::list context); - const ContextDomain& getFunctionDomain(const std::string& name) const; - const FunctionContextDemand& getFunctionDemand(const std::string& name) const; - const ScopeContextDecisions& getStaticDecisions(const ScopePacked& scopeId); + const Domain& getTopicDomain(const Expression& topic) const; + const DependentDecision& getDependentDecision(ScopePacked scope, const Expression& topic) const; + const FunctionDemand& getFunctionDemand(const std::string& name) const; + const Decisions& getFinalDecisions(const ScopePacked& scopeId) const; + virtual void init(ClaspLayer* clasp); ContextQuery(); virtual ~ContextQuery(){}; private: ClaspLayer* clasp; - std::map __modelContext; - std::map __modelFunctionDomain; - std::map __modelFunctionDemand; - std::map __modelStaticDecisions; - - const ContextDomain domainEmpty; - const FunctionContextDemand decisionsEmpty; - const ScopeContextDecisions contextDecisionsEmpty; - - void prepareDemandModel(); + std::map __modelContext; + std::map __modelFunctionDemand; + std::map __modelStaticDecisions; + std::map __modelTopicDomains; + std::map> __modelDependentDecisions; + + void prepareFunctionDemandModel(); + void prepareDecisionModels(); }; +bool operator < (const Expression&, const Expression&); + } /* namespace xreate */ /* template class ContextAttachments: private std::unordered_map { typedef std::unordered_map PARENT; public: ContextAttachments(ContextAttachments&& other) : PARENT(std::move(other)), domain(std::move(other.domain)) {} ContextAttachments(std::vector&& expressions, std::vector&& attachments) : domain(move(expressions)) { size_t size = domain.size(); for (size_t i=0; i FunctionSpecializations ; */ #endif /* SRC_QUERY_CONTEXT_H_ */ diff --git a/cpp/src/serialization/expressionserializer.cpp b/cpp/src/serialization/expressionserializer.cpp index af7e8f1..42b5a15 100644 --- a/cpp/src/serialization/expressionserializer.cpp +++ b/cpp/src/serialization/expressionserializer.cpp @@ -1,287 +1,303 @@ /* * expressionserializer.cpp * * Created on: Jan 4, 2016 * Author: pgess */ #include "serialization/expressionserializer.h" -#include -#include -#include -#include +#include using namespace std; -using namespace boost::bimaps; +//using namespace boost::bimaps; namespace xreate { struct Index { - string name; - size_t degree; //count of parameters - unsigned char level; //level in expression tree (depth of tree layer) - - bool operator< (const Index other) const{ - if (name != other.name) return name < other.name; - if (degree != other.degree) return degree < other.degree; - if (name != other.name) return level < other.level; - return false; - } + string name; + size_t degree; //count of parameters + unsigned char level; //level in expression tree (depth of tree layer) + + bool operator< (const Index other) const{ + if (name != other.name) return name < other.name; + if (degree != other.degree) return degree < other.degree; + if (name != other.name) return level < other.level; + return false; + } }; class ExpressionSerializerPrivate { //boost::bimap> __registry; - struct { - map left; - } __registry; - map __range; + struct { + map left; + } __registry; + map __range; public: - void pack(const Expression& e, unsigned char level, OptionalPackedExpression& target){ - if (!target) return; - switch (e.op){ - case Operator::NONE: { - switch (e.__state) { - case Expression::STRING: - case Expression::IDENT: { - Index index{e.getValueString(), 0, level}; - if (!__registry.left.count(index)){ - target = boost::none; - return; - } - - size_t id = __registry.left.at(index); - size_t range = __range[level]; - (*target) << make_pair(id, range); - return; - } - default: break; - } - break; - } - - case Operator::CALL: { - Index index{e.getValueString(), e.operands.size(), level}; - if(!__registry.left.count(index)){ - target = boost::none; - return; - } - - size_t id = __registry.left.at(index); - size_t range = __range[level]; - (*target) << make_pair(id, range); - - for (const Expression& operand: e.operands){ - pack(operand, level+1, target); - } - return; - } - default: break; - } - - assert(false && "Expression too complicate for serialization"); - } - - void registerExpression(const Expression&e, unsigned char level){ - switch (e.op){ - case Operator::CALL: { - Index index{e.getValueString(), e.operands.size(), level}; - if (__registry.left.insert(make_pair(index, __range[level])).second){ - __range[level]++; - } - - for (const Expression& operand: e.operands){ - registerExpression(operand, level+1); - } - return; - } - - case Operator::NONE: { - switch (e.__state) { - case Expression::STRING: - case Expression::IDENT: { - Index index{e.getValueString(), 0, level}; - if (__registry.left.insert(make_pair(index, __range[level])).second){ - __range[level]++; - } - return; - } - default: break; - } - break; - } - - default: break; - } - - assert(false && "Expression too complicate for serialization"); - } + void pack(const Expression& e, unsigned char level, OptionalPackedExpression& target){ + if (!target) return; + switch (e.op){ + case Operator::NONE: { + switch (e.__state) { + case Expression::NUMBER: + case Expression::STRING: + case Expression::IDENT : { + + Index index; + if ((e.__state == Expression::NUMBER)) + index = {std::to_string(e.getValueDouble()), 0, level}; + else index = {e.getValueString(), 0, level}; + + if (!__registry.left.count(index)){ + target = boost::none; + return; + } + + size_t id = __registry.left.at(index); + size_t range = __range[level]; + (*target) << make_pair(id, range); + return; + } + default: break; + } + break; + } + + case Operator::CALL: { + Index index{e.getValueString(), e.operands.size(), level}; + if(!__registry.left.count(index)){ + target = boost::none; + return; + } + + size_t id = __registry.left.at(index); + size_t range = __range[level]; + (*target) << make_pair(id, range); + + for (const Expression& operand: e.operands){ + pack(operand, level+1, target); + } + return; + } + default: break; + } + + assert(false && "Expression too complicate for serialization"); + } + + void registerExpression(const Expression&e, unsigned char level){ + switch (e.op){ + case Operator::CALL: { + Index index{e.getValueString(), e.operands.size(), level}; + if (__registry.left.insert(make_pair(index, __range[level])).second){ + __range[level]++; + } + + for (const Expression& operand: e.operands){ + registerExpression(operand, level+1); + } + return; + } + + case Operator::NONE: { + Index index; + + switch (e.__state) { + case Expression::STRING: + case Expression::IDENT: { + index = {e.getValueString(), 0, level}; + if (__registry.left.insert(make_pair(index, __range[level])).second){ + __range[level]++; + } + return; + } + + case Expression::NUMBER: { + index = {std::to_string(e.getValueDouble()), 0, level}; + if (__registry.left.insert(make_pair(index, __range[level])).second){ + __range[level]++; + } + return; + } + + default: break; + } + break; + } + + default: break; + } + + assert(false && "Expression too complicate for serialization"); + } }; ExpressionSerializer::ExpressionSerializer() : strategy(new ExpressionSerializerPrivate()){ } ExpressionSerializer::~ExpressionSerializer() { delete strategy; } void ExpressionSerializer::registerExpression(const Expression&e){ if (e.isValid()) strategy->registerExpression(e, 0); } PackedExpression ExpressionSerializer::getId(const Expression& e){ OptionalPackedExpression result(move(PackedExpression())); strategy->pack(e, 0, result); assert(result); return move(*result); } OptionalPackedExpression ExpressionSerializer::getIdOptional(const Expression& e) const{ OptionalPackedExpression result(move(PackedExpression())); strategy->pack(e, 0, result); return result; } +ExpressionSerializerIntegral::ExpressionSerializerIntegral():serializer(*this){} + ExpressionSerializerIntegral::ExpressionSerializerIntegral(const std::vector&& expressions) : std::vector(move(expressions)), serializer(*this){ size_t id =0; for (const Expression& e: expressions){ __registry.emplace(serializer.getId(e), id++); } } size_t ExpressionSerializerIntegral::size() const{ return PARENT::size(); } size_t ExpressionSerializerIntegral::count(const Expression& e) const { return (getIdOptional(e)? 1: 0); } ExpressionSerializerIntegral::const_iterator ExpressionSerializerIntegral::begin() const { return PARENT::begin(); } ExpressionSerializerIntegral::const_iterator ExpressionSerializerIntegral::end() const { return PARENT::end(); } size_t ExpressionSerializerIntegral::getId(const Expression& e) const{ const auto& exprPacked = serializer.getIdOptional(e); assert(exprPacked); return __registry.at(*exprPacked); } boost::optional ExpressionSerializerIntegral::getIdOptional(const Expression& e) const{ const auto& exprPacked = serializer.getIdOptional(e); if (!exprPacked){ return boost::none; } return __registry.at(*exprPacked); } const Expression& ExpressionSerializerIntegral::get(size_t id) const{ return at(id); } void PackedExpression::operator<< (const std::pair& value){ static const size_t sizeSizeT = sizeof(size_t); const size_t& id = value.first; const size_t& range = value.second; int countSufficientBits = range <=1? 0 : ceil(log2(range)); if (0 < countRemainedBits && countRemainedBits < countSufficientBits) { size_t* tail = reinterpret_cast(__storage + size- sizeSizeT); (*tail) += id >> (countSufficientBits - countRemainedBits); countSufficientBits-=countRemainedBits; countRemainedBits = 0; } if (countRemainedBits == 0) { if (countSufficientBits == 0) return; char* __storageNew = new char[size+sizeSizeT]; std::memcpy (__storageNew, __storage, size); std::memset(__storageNew + size, 0, sizeSizeT); delete[] __storage; __storage = __storageNew; size += sizeSizeT; countRemainedBits = 8 * sizeSizeT; } if (countRemainedBits >= countSufficientBits) { size_t* tail = reinterpret_cast(__storage + size- sizeSizeT); (*tail) += id << (countRemainedBits - countSufficientBits); countRemainedBits -= countSufficientBits; return; } assert("Unreachable block"); } PackedExpression::PackedExpression(PackedExpression&& other){ __storage = other.__storage; size = other.size; countRemainedBits = other.countRemainedBits; other.__storage = nullptr; } bool PackedExpression::operator==(const PackedExpression& other) const{ if (size == other.size && countRemainedBits == other.countRemainedBits){ return std::memcmp(__storage, other.__storage, size) == 0 ; } return false; } bool PackedExpression::operator<(const PackedExpression& other) const{ if (size < other.size) { return true; } if (countRemainedBits < other.countRemainedBits) return true; if (size == other.size && countRemainedBits == other.countRemainedBits){ return std::memcmp(__storage, other.__storage, size) < 0 ; } return false; } bool PackedExpression::operator!=(const PackedExpression& other) const{ return ! ((*this) == other); } PackedExpression::~PackedExpression() { delete[] __storage; } //PackedExpression::PackedExpression (const PackedExpression& other) // : size(other.size), countRemainedBits(other.countRemainedBits) //{ // __storage = new char[size]; // std::memcpy (__storage, other.__storage, size); //} } /* namespace xreate */ diff --git a/cpp/src/serialization/expressionserializer.h b/cpp/src/serialization/expressionserializer.h index b4b2354..9acf8c4 100644 --- a/cpp/src/serialization/expressionserializer.h +++ b/cpp/src/serialization/expressionserializer.h @@ -1,100 +1,103 @@ /* * expressionserializer.h * * Created on: Jan 4, 2016 * Author: pgess */ #ifndef SRC_EXPRESSIONSERIALIZER_H_ #define SRC_EXPRESSIONSERIALIZER_H_ #include "ast.h" #include #include namespace xreate { struct PackedExpression{ PackedExpression(){}; PackedExpression(PackedExpression&& other); ~PackedExpression(); void operator<< (const std::pair& value); char* operator*(){return __storage;} bool operator==(const PackedExpression& other) const; bool operator!=(const PackedExpression& other) const; bool operator<(const PackedExpression& other) const; private: PackedExpression (const PackedExpression&)=delete; PackedExpression& operator=(const PackedExpression&)=delete; PackedExpression& operator=(PackedExpression&&)=delete; char* __storage = nullptr; size_t size =0; unsigned char countRemainedBits =0; }; typedef boost::optional OptionalPackedExpression; class ExpressionSerializerPrivate; class ExpressionSerializer { public: template ExpressionSerializer(const Container& source): ExpressionSerializer(){ for (const Expression& e: source) { registerExpression(e); } } template ExpressionSerializer(const Container& source, Transformer op): ExpressionSerializer(){ for (const typename Container::value_type& e: source) { registerExpression(op(e)); } } ExpressionSerializer(ExpressionSerializer&& other) : strategy(other.strategy) {other.strategy = 0; } virtual ~ExpressionSerializer(); PackedExpression getId(const Expression& e); OptionalPackedExpression getIdOptional(const Expression& e) const; private: ExpressionSerializerPrivate* strategy; void registerExpression(const Expression&e); ExpressionSerializer(); }; class ExpressionSerializerIntegral: private std::vector{ typedef std::vector PARENT; public: + ExpressionSerializerIntegral(); ExpressionSerializerIntegral(const std::vector&& expressions); + template ExpressionSerializerIntegral(Iterator first, Iterator last) : ExpressionSerializerIntegral(std::vector(first, last)){} ExpressionSerializerIntegral(ExpressionSerializerIntegral&& other) : PARENT(std::move(other)), __registry(std::move(other.__registry)), serializer(std::move(other.serializer)){} + size_t getId(const Expression& e) const; boost::optional getIdOptional(const Expression& e) const; const Expression& get(size_t id) const; size_t size() const; size_t count(const Expression& e) const; ExpressionSerializerIntegral::const_iterator begin() const; ExpressionSerializerIntegral::const_iterator end() const; private: ExpressionSerializerIntegral(const ExpressionSerializerIntegral&)=delete; std::map __registry; ExpressionSerializer serializer; }; } /* namespace xreate */ #endif /* SRC_EXPRESSIONSERIALIZER_H_ */ diff --git a/cpp/src/utils.h b/cpp/src/utils.h index 2778ad0..a2f9b28 100644 --- a/cpp/src/utils.h +++ b/cpp/src/utils.h @@ -1,134 +1,134 @@ #ifndef UTILS_H #define UTILS_H #include "jeayeson/jeayeson.hpp" -//TODO mark dirty members +//TODO use type mark to mark dirty/mutable members /* template struct DdesctructableClass { } */ /* template struct TagUpdatable{ TagUpdatable(const OriginalType& source) : __source(source) {} TagUpdatable() = delete; const OriginalType& __source; }; struct Updatable; template struct TagsDictionary {}; template struct TagsDictionary { typedef TagUpdatable TagName; }; template struct awareOf { awareOf(OT& dest) : __dest(dest) {} awareOf& operator= (const typename TagsDictionary::TagName& source) { __dest = source.__source; } private: OT& __dest; }; template> const OT& awareOf(const Tag& holder) { return std::forward(holder.__source); } */ namespace xreate { template struct AddTag { explicit AddTag(const Source &src) : __src(src) { } explicit AddTag(Source &&src) : __src(std::move(src)) { } operator const Source&() const{ return __src; } const Source& get() const{ return __src; } const Source* operator->() const { return &__src; } private: Source __src; }; struct Expand_t{}; template using Expanded = AddTag; //DEBT move to resources compiler. https://github.com/markusfisch/cpprc class Config { private: json_map __storage; static Config __self; Config(); public: static std::string get(std::string key) { return __self.__storage.get_for_path(key).get(); } }; } #define RST "\x1B[0m" #define KRED "\x1B[31m" #define KGRN "\x1B[32m" #define KYEL "\x1B[33m" #define KBLU "\x1B[34m" #define KMAG "\x1B[35m" #define KCYN "\x1B[36m" #define KWHT "\x1B[37m" #define FRED(x) KRED << x << RST #define FGRN(x) KGRN < +#include + using namespace xreate; using namespace std; TEST(CFG, testFunctionAnnotationsClasp){ string&& program = - "f2 = function()::int; annotationF2 {\n" + "f2 = function::int; annotationF2 {\n" " 0\n" "}\n" "\n" - "f1 = function():: int; entry; annotationF1 {\n" + "f1 = function:: int; entry; annotationF1 {\n" " f2() + 10\n" "}"; PassManager* man = PassManager::prepareForCode(move(program)); man->runWithoutCompilation(); ClaspLayer::ModelFragment answer = man->clasp->query("annotationF1"); int countNoneValue = 0; if (answer) countNoneValue = std::distance(answer->first, answer->second); EXPECT_EQ(1, countNoneValue); answer = man->clasp->query("annotationF2"); countNoneValue = 0; if (answer) countNoneValue = std::distance(answer->first, answer->second); EXPECT_EQ(1, countNoneValue); } TEST(CFG, testLoopContextExists){ PassManager* man = PassManager::prepareForCode ( "interface(cfa){\n" " operator fold:: annotation1.\n" "}\n" "\n" - "main = function() :: int; entry {\n" + "main = function:: int; entry {\n" " x = [1..10]:: [int].\n" - " sum = loop fold (x->el:: int, 0->sum:: int):: [int] {\n" + " sum = loop fold (x->el:: int, 0->sum):: int {\n" " el + sum + f1()\n" " }. \n" " sum\n" "}" - "f1 = function()::int {\n" + "f1 = function::int {\n" " x = 0:: int. " " x\n" "}" ); man->runWithoutCompilation(); } + +TEST(CFG, CFGRoots){ + std::string program = +R"CODE( + main = function::int{a()+ b()} + a= function::int {c1() + c2()} + b= function::int {c2()} + c1=function::int{0} + c2=function::int{0} +)CODE"; + + boost::scoped_ptr manager + (PassManager::prepareForCode(move(program))); + + manager->registerPass(new CFAPass(manager.get()) , PassId::CFGPass); + manager->executePasses(); + manager->clasp->run(); + + DominatorsTreeAnalysisProvider domProvider; + domProvider.run(manager->clasp); + + DominatorsTreeAnalysisProvider::Dominators expectedFDom= { + {0, {0, 9}} + ,{1, {1, 4}} + ,{2, {7, 8}} + ,{3, {2, 3}} + ,{4, {5, 6}} + }; + + DominatorsTreeAnalysisProvider::Dominators expectedPostDom= { + {0, {5, 6}} + ,{1, {3, 4}} + ,{2, {8, 9}} + ,{3, {1, 2}} + ,{4, {7, 10}} + }; + + ASSERT_EQ(expectedFDom, domProvider.getForwardDominators()); + ASSERT_EQ(expectedPostDom, domProvider.getPostDominators()); +} diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt index c729026..e980a74 100644 --- a/cpp/tests/CMakeLists.txt +++ b/cpp/tests/CMakeLists.txt @@ -1,19 +1,18 @@ cmake_minimum_required(VERSION 2.8.11) project(xreate-tests) find_package(GTest REQUIRED) INCLUDE_DIRECTORIES(${GTEST_INCLUDE_DIRS}) INCLUDE_DIRECTORIES("/usr/include/libxml2") INCLUDE_DIRECTORIES($) - # TESTS #========================= aux_source_directory(. TEST_FILES) add_executable(${PROJECT_NAME} ${TEST_FILES}) target_link_libraries(${PROJECT_NAME} xreate ${GTEST_LIBRARIES} pthread xml2 gcov) add_custom_target (coverage COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/src/code-coverage.sh WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/cpp/tests/DFGtests.cpp b/cpp/tests/DFGtests.cpp index 7371367..088bc40 100644 --- a/cpp/tests/DFGtests.cpp +++ b/cpp/tests/DFGtests.cpp @@ -1,42 +1,42 @@ /* * DFGtests.cpp * * Created on: Jul 23, 2015 * Author: pgess */ #include "passmanager.h" -#include "pass/dfgpass.h" +#include "pass/dfapass.h" #include "gtest/gtest.h" using namespace xreate; using namespace std; TEST(DFG, testFunctionRetSymbolExists){ PassManager* man = PassManager::prepareForCode ("test = function():: int; entry {\n" " data = [1..5]::[int].\n" " \n" " result = loop fold(data->i::int, 0->sum::int)::int{\n" " if (i==3)::int {valNull = null. valNull} else {i+sum}\n" " }.\n" " \n" " result\n" "}"); man->runWithoutCompilation(); ClaspLayer::ModelFragment answer = man->clasp->query(Config::get("clasp.ret.symbol")); if (answer) EXPECT_EQ(1, std::distance(answer->first, answer->second)); for (auto functionIt = answer->first; functionIt != answer->second; ++functionIt){ - auto ret = ClaspLayer::parse(functionIt->second); + auto ret = ClaspLayer::parse(functionIt->second); ASSERT_EQ("test", std::get<0>(ret)); SymbolPacked symbolRet = std::get<0>(ClaspLayer::parse(std::get<1>(ret))); ASSERT_EQ(3, symbolRet.identifier); ASSERT_EQ(0, symbolRet.scope); } } diff --git a/cpp/tests/adhoc-skipdetection.cpp b/cpp/tests/adhoc-skipdetection.cpp index c1ba1a2..603891c 100644 --- a/cpp/tests/adhoc-skipdetection.cpp +++ b/cpp/tests/adhoc-skipdetection.cpp @@ -1,32 +1,34 @@ /* * skipdetection.cpp * * Created on: Jul 10, 2015 * Author: pgess */ #include "passmanager.h" #include "clasplayer.h" #include "gtest/gtest.h" using namespace xreate; using namespace std; -TEST(SkipDetection, testNoneValueTagExists){ + +//TASK implement loop "skip" command +TEST(Adhoc_Loop_SkipDetection, testNoneValueTagExists){ PassManager* man = PassManager::prepareForCode ("test = function():: int; entry {\n" " data = [1..5]::[int].\n" " \n" " result = loop fold(data->i::int, 0->sum::int)::int{\n" " if (i==3)::int {valNull = null. valNull} else {i+sum}\n" " }.\n" " \n" " result\n" "}"); man->runWithoutCompilation(); ClaspLayer::ModelFragment answer = man->clasp->query(Config::get("clasp.nonevalue")); int countNoneValue = 0; if (answer) countNoneValue = std::distance(answer->first, answer->second); EXPECT_EQ(1, countNoneValue); } diff --git a/cpp/tests/ast.cpp b/cpp/tests/ast.cpp index 7c4de20..4868d3a 100644 --- a/cpp/tests/ast.cpp +++ b/cpp/tests/ast.cpp @@ -1,49 +1,49 @@ /* * ast.cpp * * Created on: Jun 11, 2015 * Author: pgess */ #include "gtest/gtest.h" #include "passmanager.h" #include "Parser.h" using namespace std; using namespace xreate; TEST(AST, Containers1){ FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); const AST& ast = parser.root; fclose(input); } TEST(AST, InterfacesDataCFA) { PassManager* man = PassManager::prepareForCode ("interface(cfa){\n" " operator map :: annotation1.\n" "}"); auto answer = man->root->__interfacesData.equal_range(CFA); EXPECT_EQ(1, std::distance(answer.first, answer.second)); Expression&& scheme = move(answer.first->second); EXPECT_EQ(Operator::MAP, scheme.op); EXPECT_EQ("annotation1", scheme.getOperands().at(0).getValueString()); } TEST(AST, DISABLED_InterfacesDataDFA){ } TEST(AST, DISABLED_InterfacesDataExtern){ } - +//TODO xreate.atg: replace all Type<> as ExprAnnotations<> diff --git a/cpp/tests/compilation.cpp b/cpp/tests/compilation.cpp index 97e4087..58cb59d 100644 --- a/cpp/tests/compilation.cpp +++ b/cpp/tests/compilation.cpp @@ -1,62 +1,62 @@ #include "passmanager.h" #include "gtest/gtest.h" using namespace xreate; -//TEST FunctionUnit::compileInline +//TOTEST FunctionUnit::compileInline TEST(Compilation, DISABLED_functionInline1){ } //DEBT implement no pkgconfig ways to link libs TEST(Compilation, Sequence1){ PassManager* man = PassManager::prepareForCode( "interface(extern-c){\n" " libFake = library:: pkgconfig(\"libxml-2.0\").\n" " \n" " include {\n" " libFake = [\"stdio.h\", \"stdlib.h\"]\n" " }.\n" "}" "main = function:: int; entry {\n" " sequence [" " printf(\"FIRST-\"),\n" " printf(\">SECOND\")\n" " ]" "}" ); int (*main)() = (int (*)()) man->run(); testing::internal::CaptureStdout(); main(); std::string output = testing::internal::GetCapturedStdout(); ASSERT_STREQ("FIRST->SECOND", output.c_str()); } TEST(Compilation, full_IFStatementWithVariantType){ PassManager* man = PassManager::prepareForCode( "COLORS = type variant (RED, BLUE, GREEN).\n" "\n" " main = function(x::int):: int; entry {\n" " color = if (x == 0 )::COLORS {RED} else {BLUE}.\n" " if (color == BLUE)::int {1} else {0}\n" " }" ); int (*main)(int) = (int (*)(int)) man->run(); ASSERT_EQ(0, main(0)); ASSERT_EQ(1, main(1)); } // "main = function:: int; entry {\n" // " context:: expectNoErrors. " // " buf1 = \"aaaaa\"::string.\n" // " buf2 = \"aaaaa\"::string.\n" // " sequence [" // " sprintf(buf1, \"%d\", exec(\"bazaar --version\"))," // " sprintf(buf2, \"%d\", exec(\"svn --version\"))," // " printf(buf1),\n" // " printf(buf2)\n" // "]" // "}" diff --git a/cpp/tests/context.cpp b/cpp/tests/context.cpp index 56655b3..4c05c02 100644 --- a/cpp/tests/context.cpp +++ b/cpp/tests/context.cpp @@ -1,325 +1,370 @@ /* * frame-context.cpp * * Created on: Dec 3, 2015 * Author: pgess */ #include "passmanager.h" #include "query/context.h" #include "gtest/gtest.h" #include #include using namespace xreate; //TEST(Context, frame_Context1){ // PassManager* man = PassManager::prepareForCode( // " import raw (\"core/control-context.lp\")\n" // " testC = function::int {\n" // " context:: testC.\n" // // " 0\n" // " }\n" // // " testA = function:: int {\n" // " context:: testA; test.\n" // // " testC()\n" // " }\n" // // " testB = function:: int {\n" // " context:: testB; test.\n" // // " testC()\n" // " }\n" // ); // // ContextQuery* query = (ContextQuery*) man->clasp->registerQuery(new ContextQuery(), QueryId::ContextQuery); // man->runWithoutCompilation(); // // CodeScope* scopeTestC = man->root->findFunction("testC")->getEntryScope(); // const ContextDomain& context = query->getContext(man->clasp->pack(scopeTestC)); // // int contextSize = context.size(); // EXPECT_EQ(2, contextSize); //} // //TEST(Context, full_ContextBasedFunctionSpecialization){ // // PassManager* man = PassManager::prepareForCode( // " case context::toMillimeters {\n" // " convert = function(source:: num)::num {\n" // " 10 * source \n" // " }\n" // " }\n" // // " case context::toInches {\n" // " convert = function(source:: num)::num {\n" // " 2 * source \n" // " }\n" // " }\n" // // "test = function(vrnt:: int)::int; entry {\n" // " switch(vrnt):: int\n" // " case 0 {\n" // " context:: toMillimeters.\n" // " convert(1)\n" // " }\n" // "\n" // " case 1 {\n" // " context:: toInches.\n" // " convert(1)\n" // " }\n" // " case default {0}\n" // " }" ); // // int (*main)(int) = (int (*)(int)) man->run(); // ASSERT_EQ(10, main(0)); // ASSERT_EQ(2, main(1)); //} // //TEST(Context, full_LoopContext){ // // PassManager* man = PassManager::prepareForCode("case context:: a {\n" // " print = function:: string {\n" // " \"a\"\n" // " }}\n" // "\n" // " case context:: b {\n" // " print = function:: string {\n" // " \"b\"\n" // " }}\n" // "\n" // " case context:: c {\n" // " print = function:: string {\n" // " \"c\"\n" // " }}\n" // "\n" // " case context:: d {\n" // " print = function:: string {\n" // " \"d\"\n" // " }}\n" // "\n" // " start = function(command::int)::string; entry {\n" // " switch (command) :: string \n" // " case 0 {\n" // " context:: print(a); print(b); print(d).\n" // "\n" // " loop context (\"print\") {\n" // " print()\n" // " }\n" // " }\n" // "\n" // " case default {\n" // " context:: print(c).\n" // " loop context (\"print\") {\n" // " print()\n" // " }\n" // " }\n" // " }"); // // // char* (*main)(int) =(char* (*)(int)) man->run(); // ASSERT_STREQ("c", main(1)); // ASSERT_STREQ("a", main(0)); //} // //TEST(Context, full_RuleContext){ // /* // "rule context:: childs(Child)\n" // " case artefact(Item)\n" // " {\n" // " artefact_depends(Item, Child)\n" // " }"; // */ // // PassManager* man = PassManager::prepareForCode( // " case context:: toMilli {\n" // " convert = function(length::int)::int{\n" // " 10 * length\n" // " }\n" // " }\n" // "\n" // " case context:: toCenti {\n" // " convert = function(length::int)::int{\n" // " length\n" // " }\n" // " }\n" // "\n" // " main=function::int; entry {\n" // " context:: output(milli).\n" // "\n" // " rule context::toMilli\n" // " case output(milli) {true}\n" // "\n" // " convert(1)\n" // " }" ); // man->clasp->addRawScript("true."); // // int (*entry)() = (int (*)()) man->run(); // ASSERT_EQ(10, entry()); //} // //TEST(Context, full_InheritedRuleContext){ // PassManager* man = PassManager::prepareForCode( // " import raw (\"core/control-context.lp\") \n" // // " case context:: toMilli {\n" // " convert = function(length::int)::int{\n" // " 10 * length\n" // " }\n" // " }\n" // // " case context:: toCenti {\n" // " convert = function(length::int)::int{\ n" // " length\n" // " }\n" // " }\n" // "\n" // // "main = function(comm:: num)::num; entry{\n" // " rule context::X case output(X) {true}\n" // "\n" // " switch (comm)::num \n" // " case 0 {\n" // " context:: output(toMilli).\n" // " convert(1)\n" // " }\n" // " case default {\n" // " context:: output(toCenti).\n" // " convert(1)\n" // " }\n" // " }"); // // man->clasp->addRawScript("true."); // int (*entry)(int) = (int (*)(int)) man->run(); // ASSERT_EQ(10, entry(0)); // ASSERT_EQ(1, entry(1)); //} // // // //TEST(Context, full_LateContext){ // PassManager* man = PassManager::prepareForCode( // "import raw (\"core/control-context.lp\")\n" // // " convert = function(length:: num)::num{\n" // " 0\n" // " }\n" // // "case context:: milli {\n" // " convert = function(length:: num)::num{\n" // " 1000 * length\n" // " }\n" // "}\n" // "\n" // "case context:: centi {\n" // " convert = function(length:: num)::num{\n" // " 100 * length\n" // " }\n" // "}\n" // "\n" // "calculate = function(length:: num)::num {\n" // " convert(length)\n" // "}\n" // "\n" // "main = function(com:: num):: num; entry {\n" // " switch (com):: num \n" // " case 0 {\n" // " context:: milli.\n" // " calculate(1)\n" // " }\n" // "\n" // " case default{\n" // " context:: centi. \n" // " calculate(1)\n" // " }\n" // "}"); // // man->runWithoutCompilation(); // ContextQuery* queryContext = reinterpret_cast(man->clasp->getQuery(QueryId::ContextQuery)); // Expression exprSwitch = man->root->findFunction("main")->__entry->__body; // CodeScope* blockDefault = man->root->findFunction("main")->__entry->__body.operands[1].blocks.front(); // ScopePacked blockDefaultId = man->clasp->pack(blockDefault); // const ContextDomain& domDefault = queryContext->getContext(blockDefaultId); // ASSERT_EQ(1, domDefault.count(Expression(Atom("centi")))); // // std::list variants = man->root->getFunctionVariants("convert"); // for (ManagedFnPtr f: variants){ // const Expression guard = f->guardContext; // bool result = (guard.getValueString() == "centi" || guard.getValueString() == "milli" || !guard.isValid()); // ASSERT_TRUE(result); // } // // const FunctionContextDemand& demMain = queryContext->getFunctionDemand("main"); // ASSERT_EQ(0, demMain.size()); // // const FunctionContextDemand& demCalculate = queryContext->getFunctionDemand("calculate"); // ASSERT_EQ(1, demCalculate.size()); // ASSERT_EQ(1, demCalculate.right.count("convert")); // // int (*entry)(int) = (int (*)(int)) man->run(); // ASSERT_EQ(1000, entry(0)); // ASSERT_EQ(100, entry(1)); //} TEST(Context, pathDependent_context){ std::string program = -R"CODE(case context:: convert(milli, meters) { +R"CODE( +import raw("core/control-context.lp") + +convert = function(length:: num) :: num { + 0 +} + +case context:: convert(milli, meters) { convert = function(length:: num) :: num { 1000 * length } } case context:: convert(centi, meters) { convert = function(length:: num) :: num { 100 * length } } case context:: convert(centi, kilo) { convert = function(length:: num) :: num { 100000 * length } } case context:: convert(milli, kilo) { convert = function(length:: num) :: num { 1000000 * length } } + +main = function(value::num, unitsInput::num, unitsOutput::num)::num; entry{ + switch (unitsInput)::num + case 0 { + test_fromMilli(value, unitsOutput) + } + case 1 { + test_fromCenti(value, unitsOutput) + } -test1_fromCentiToKilo = function(a::num)::num { - context:: input(centi). - - toKilo(a) + case default {0} } - - -test2_fromMilliToMeters = function(a::num)::num{ +test_fromCenti = function(value::num, output::num)::num{ + context:: input(centi). + + switch(output):: num + case 0 { + toMeters(value) + } + + case 1 { + toKilo(value) + } + + case default {0} +} + +test_fromMilli = function(value::num, output::num)::num{ context:: input(milli). - - toMeters(a) + + switch(output):: num + case 0 { + toMeters(value) + } + + case 1 { + toKilo(value) + } + + case default {0} } -toMeters = function(a::num)::num { - rule context :: convert(X, meters) case input(X) {true} +toMeters = function(value::num)::num { + rule context:: convert(X, meters) case input(X) {true} - convert(a) + doConvert(value) } -toKilo = function(a::num)::num { - rule context :: convert(X, kilo) case input(X) {true} +toKilo = function(value::num)::num { + rule context:: convert(X, kilo) case input(X) {true} - convert(a) + doConvert(value) +} + +doConvert = function(value::num)::num{ + convert(value) })CODE"; - - boost::scoped_ptr man(PassManager::prepareForCode(move(program))); man->runWithoutCompilation(); -} + + int (*test)(int, int, int) = (int (*)(int, int, int))man->run(); + + enum {INPUT_MILLI, INPUT_CENTI}; + enum {OUTPUT_METERS, OUTPUT_KILO}; + + ASSERT_EQ(1000000, test(1, INPUT_MILLI, OUTPUT_KILO)); + ASSERT_EQ(200, test(2, INPUT_CENTI, OUTPUT_METERS)); +} diff --git a/cpp/tests/diagnostic-messages.cpp b/cpp/tests/diagnostic-messages.cpp index 5c7c946..dbd21a1 100644 --- a/cpp/tests/diagnostic-messages.cpp +++ b/cpp/tests/diagnostic-messages.cpp @@ -1,32 +1,32 @@ /* * diagnostic-messages.cpp * * Created on: Oct 27, 2015 * Author: pgess */ #include "passmanager.h" -#include "pass/dfgpass.h" +#include "pass/dfapass.h" #include "gtest/gtest.h" using namespace std; using namespace xreate; TEST(Diagnostic_DFA, DISABLED_recursion1){ //Error while processing recursion, There should be some diagnostic complaints std::string code = \ "test1 = function()::[int] {\n" " varRecursion = loop map(varRecursion->el:: int)::[int]{\n" " el\n" " }.\n" " \n" " varRecursion\n" "}"; PassManager* man = PassManager::prepareForCode(move(code)); - DFGPass* pass = new DFGPass(man); + DFAPass* pass = new DFAPass(man); pass->run(); pass->finish(); } diff --git a/cpp/tests/externc.cpp b/cpp/tests/externc.cpp index ba12e3c..2ec0e44 100644 --- a/cpp/tests/externc.cpp +++ b/cpp/tests/externc.cpp @@ -1,104 +1,104 @@ #include "gtest/gtest.h" #include "passmanager.h" #include "Scanner.h" #include "Parser.h" #include #include using namespace std; TEST(InterfaceExternC, testAST){ std::string code = " \ interface(extern-c){ \ xml2 = library:: pkgconfig(\"libxml-2.0\"). \ \ include { \ xml2 = [\"libxml/tree.h\"] \ }. \ } \ "; Scanner scanner(reinterpret_cast(code.c_str()), code.size()); Parser parser(&scanner); parser.Parse(); ASSERT_EQ(1, parser.root.__externdata.size()); for (const ExternEntry& lib: parser.root.__externdata){ ASSERT_EQ("libxml-2.0", lib.package); ASSERT_EQ(1, lib.headers.size()); ASSERT_EQ("libxml/tree.h", lib.headers.at(0)); } } TEST(InterfaceExternC, testfetchPackageHeaders){ ExternEntry entry{"libxml-2.0", {}}; vector args = ExternLayer::fetchPackageFlags(entry); ASSERT_EQ(1, args.size()); ASSERT_EQ("-I/usr/include/libxml2", args.at(0)); } TEST(InterfaceExternC, testfetchPackageLibs){ ExternEntry entry{"libxml-2.0", {}}; vector args = ExternLayer::fetchPackageLibs(entry); ASSERT_EQ(1, args.size()); ASSERT_EQ("xml2", args.at(0)); } TEST(InterfaceExternC, testLoadLib){ std::string msgErr; if (!llvm::sys::DynamicLibrary::LoadLibraryPermanently("-lpcre -lxml2", &msgErr)){ cout << msgErr; ASSERT_EQ("", msgErr); } ASSERT_TRUE(true); } TEST(InterfaceExternC, testBSD1){ std::string code = " \n\ interface(extern-c){ \n\ libbsd = library:: pkgconfig(\"libbsd\"). \n\ \n\ include { \n\ libbsd = [\"bsd/stdlib.h\"] \n\ }. \n\ }\n" "main= function():: int; entry{arc4random() }"; std::unique_ptr program(PassManager::prepareForCode(move(code))); void* entryPtr = program->run(); int (*entry)() = (int (*)())(intptr_t)entryPtr; int answer = 24; answer = entry(); cout << answer; ASSERT_NE(24, answer); } TEST(InterfaceExternC, testStructFields1){ FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST& ast = parser.root; CodeScope* body = ast.findFunction("test")->getEntryScope(); Symbol symbTree = body->findSymbol("tree"); - const TypeAnnotation& tTree = CodeScope::findDefinition(symbTree); + const TypeAnnotation& tTree = CodeScope::findDeclaration(symbTree).type; const ExpandedType& t2Tree = ast.expandType(tTree); LLVMLayer llvm(&ast); TypeUtils utils(&llvm); std::vectorfields = utils.getStructFields(t2Tree); auto field = std::find(fields.begin(), fields.end(), "children"); ASSERT_TRUE(field != fields.end()); } diff --git a/cpp/tests/sprint1-installation.cpp b/cpp/tests/installation.cpp similarity index 94% rename from cpp/tests/sprint1-installation.cpp rename to cpp/tests/installation.cpp index b4dda10..dd2e1e2 100644 --- a/cpp/tests/sprint1-installation.cpp +++ b/cpp/tests/installation.cpp @@ -1,22 +1,22 @@ /* - * sprint1-installation.cpp + * installation.cpp * * Created on: 26 Feb 2016 * Author: pgess */ #include "passmanager.h" #include "gtest/gtest.h" #include using namespace std; using namespace xreate; //TODO replace string identifiers with Atoms in order to hold position, etc TEST(Sprint1, test1){ const string filenameSource("scripts/testspass/sprint1-Installation1.xreate"); FILE* fileSource; ASSERT_TRUE(fileSource = fopen(filenameSource.c_str(), "rb")); PassManager* man = PassManager::prepareForCode(fileSource); man->run(); } diff --git a/cpp/tests/interpretation.cpp b/cpp/tests/interpretation.cpp new file mode 100644 index 0000000..d092f25 --- /dev/null +++ b/cpp/tests/interpretation.cpp @@ -0,0 +1,286 @@ +#include "attachments.h" + +using namespace xreate; + +#include "passmanager.h" +#include "compilation/targetinterpretation.h" + +#include "gtest/gtest.h" +#include "boost/scoped_ptr.hpp" + +#define private public +#include "Parser.h" +#include "pass/interpretationpass.h" + +using namespace xreate; +using namespace xreate::compilation; + +TEST(Interpretation, Analysis_StatementIF_1){ + PassManager* man = PassManager::prepareForCode( + +R"Code( + main = function::int { + x = "a":: string. + + y = if (x=="b"):: string; interpretation(force) { + 1 + + } else { + 0 + }. + + y + } +)Code" ); + + InterpretationPass* pass; + if (man->isPassRegistered(PassId::InterpretationPass)){ + pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); + } else { + pass = new InterpretationPass(man); + pass->run(); + } + Symbol symbolY = man->root->findFunction("main")->__entry->findSymbol("y"); + InterpretationData& dataSymbolY = Attachments::get(symbolY); + + ASSERT_EQ(INTR_ONLY, dataSymbolY.resolution); +} + +TEST(Interpretation, Compilation_StatementIF_1){ + PassManager* man = PassManager::prepareForCode( + +R"Code( + main = function::int; entry { + x = "a":: string. + + y = if (x=="b"):: string; interpretation(force) { + 1 + + } else { + 0 + }. + + y + } +)Code" ); + + man->runWithoutCompilation(); + + InterpretationPass* pass; + if (man->isPassRegistered(PassId::InterpretationPass)){ + pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); + } else { + pass = new InterpretationPass(man); + pass->run(); + } + + + int (*main)() = (int (*)())man->run(); + int result = main(); + + ASSERT_EQ(0, result); +} + +TEST(Interpretation, Analysis_StatementIF_InterpretCondition_1){ + PassManager* man = PassManager::prepareForCode( + +R"Code( + main = function::int { + x = "a":: string; interpretation(force). + + y = if (x=="b"):: string { + 1 + + } else { + 0 + }. + + y + } +)Code" ); + + InterpretationPass* pass; + if (man->isPassRegistered(PassId::InterpretationPass)){ + pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); + } else { + pass = new InterpretationPass(man); + pass->run(); + } + + Symbol symbolY = man->root->findFunction("main")->__entry->findSymbol("y"); + InterpretationData& dataSymbolY = Attachments::get(symbolY); + + ASSERT_EQ(BOTH, dataSymbolY.resolution); + ASSERT_EQ(IF_INTERPRET_CONDITION, dataSymbolY.op); +} + +TEST(Interpretation, Compilation_StatementIF_InterpretCondition_1){ + PassManager* man = PassManager::prepareForCode( + +R"Code( + main = function::int; entry { + x = "a":: string; interpretation(force). + + y = if (x=="b"):: string { + 1 + + } else { + 0 + }. + + y + } +)Code" ); + + man->runWithoutCompilation(); + + InterpretationPass* pass; + if (man->isPassRegistered(PassId::InterpretationPass)){ + pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); + } else { + pass = new InterpretationPass(man); + pass->run(); + } + + int (*main)() = (int (*)())man->run(); + int result = main(); + + ASSERT_EQ(0, result); +} + +TEST(Interpretation, Compilation_StatementFOLD_INTERPRET_INPUT_1){ + PassManager* man = PassManager::prepareForCode( + +R"Code( + main = function::int; entry { + commands = ["inc", "double", "dec"]:: [string]; interpretation(force). + + loop fold(commands->comm::string, 10->operand):: int{ + switch(comm)::int + + case ("inc"){ + operand + 1 + } + + case ("dec"){ + operand - 1 + } + + case ("double"){ + operand * 2 + } + } + } +)Code" ); + + man->runWithoutCompilation(); + + InterpretationPass* pass; + if (man->isPassRegistered(PassId::InterpretationPass)){ + pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); + } else { + pass = new InterpretationPass(man); + pass->run(); + } + + int (*main)() = (int (*)())man->run(); + int result = main(); + + ASSERT_EQ(21, result); +} + +TEST(Interpretation, StatementCall_RecursionNo_1){ + PassManager* man = PassManager::prepareForCode( +R"Code( + unwrap = function(data::undef, keys::undef):: undef; interpretation(force){ + loop fold(keys->key::string, data->a):: undef { + a[key] + } + } + + start = function::num; entry{ + result = unwrap( + { + a = { + b = + { + c = "core" + } + } + }, ["a", "b", "c"])::undef. + + result == "core" + } +)Code" ); + + man->runWithoutCompilation(); + + InterpretationPass* pass; + if (man->isPassRegistered(PassId::InterpretationPass)){ + pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); + } else { + pass = new InterpretationPass(man); + pass->run(); + } + + int (*main)() = (int (*)())man->run(); + int result = main(); + + ASSERT_EQ(1, result); +} + +TEST(Interpretation, StatementCall_RecursionDirect_1){ + PassManager* man = PassManager::prepareForCode( +R"Code( + unwrap = function(data:: X):: Y { + if (data[0] == "a")::Y {0} else {unwrap(data[0])} + } + + entry = function:: i8; entry { + unwrap([[[["a"]]]]):: i8; interpretation(force) + } +)Code" ); + + man->runWithoutCompilation(); + + InterpretationPass* pass; + if (man->isPassRegistered(PassId::InterpretationPass)){ + pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); + } else { + pass = new InterpretationPass(man); + pass->run(); + } + + InterpretationResolution resolutionActual = pass->process(man->root->findFunction("unwrap")); + ASSERT_EQ(BOTH, resolutionActual); + + int (*main)() = (int (*)())man->run(); + int result = main(); + + ASSERT_EQ(0, result); +} + +TEST(Interpretation, StatementCall_RecursionIndirect_1){ + PassManager* man = PassManager::prepareForCode( +R"Code( + funcA = function(data:: X):: Y { + if (data == "a")::Y {0} else {funcB(data)} + } + + funcB = function(data:: X):: Y { + if (data == "b")::Y {1} else {funcA(data)} + } + + entry = function:: i8; entry { + funcA(""):: i8; interpretation(force) + } +)Code" ); + + InterpretationPass* pass = new InterpretationPass(man); + ASSERT_DEATH(pass->run(), "Indirect recursion detected"); +} + +//TOTEST call indirect recursion(w/o tags) +//TASK implement and test Loop Inf (fix acc types in coco grammar) + + diff --git a/cpp/tests/loops.cpp b/cpp/tests/loops.cpp new file mode 100644 index 0000000..7d1d5d7 --- /dev/null +++ b/cpp/tests/loops.cpp @@ -0,0 +1,59 @@ +#include "passmanager.h" + +#include "gtest/gtest.h" + +using namespace std; + +TEST(Loop, Break1){ + string code = +R"CODE( + main = function:: int; entry { + input = [0..10]:: [int]. + + loop fold(input->el::int, 0->a)::[int] + { + if (a>=5)::int { + 5:: int; break + + } else {a+el} + } + } + +)CODE"; + + xreate::PassManager* man = xreate::PassManager::prepareForCode(move(code)); + int (*funcMain)() = (int (*)()) man->run(); + + int answerActual = funcMain(); + ASSERT_EQ(5, answerActual); +} + +TEST(Loop, InfiniteLoop1){ + + string code = +R"Code( + interface(extern-c){ + libFake = library:: pkgconfig("libxml-2.0"). + + include { + libFake = ["math.h"] + }. + } + + main = function:: int; entry { + loop fold inf(0->state) :: int { + if (pow(2, state)==32)::int { + state::int; break + + } else {state + 1} + } + } + +)Code" ; + + xreate::PassManager* man = xreate::PassManager::prepareForCode(move(code)); + int (*funcMain)() = (int (*)()) man->run(); + + int answerActual = funcMain(); + ASSERT_EQ(5, answerActual); +} \ No newline at end of file diff --git a/cpp/tests/pass-Logger.cpp b/cpp/tests/pass-Logger.cpp index 2999b73..46d4ba4 100644 --- a/cpp/tests/pass-Logger.cpp +++ b/cpp/tests/pass-Logger.cpp @@ -1,85 +1,85 @@ /* * testLogging.cpp * * Created on: Jun 23, 2015 * Author: pgess */ #include #include "gtest/gtest.h" #include "passmanager.h" #include "llvmlayer.h" #include "Parser.h" using namespace std; using namespace xreate; TEST(LoggerPass, simpleInjection){ PassManager* man = PassManager::prepareForCode("test= function():: int; entry{x = 2+8::int. return x}"); man->runWithoutCompilation(); CompilePass* compiler = new CompilePass(man); compiler->run(); compilation::FunctionUnit* fTest = compiler->getFunctionUnit(man->root->findFunction("test")); ASSERT_NE(fTest, nullptr); compilation::CodeScopeUnit* scopeUnitTest = fTest->getEntry(); CodeScope* scopeTest = scopeUnitTest->scope; Symbol symbX = scopeTest->findSymbol("x"); - TypeAnnotation typX = scopeTest->findDefinition(symbX); + TypeAnnotation typX = CodeScope::findDeclaration(symbX).type; llvm::Value* retRaw = scopeUnitTest->compile(); llvm::BasicBlock& blockTestRaw = fTest->raw->getEntryBlock(); LLVMLayer* llvm = man->llvm; //llvm->builder.SetInsertPoint(&blockTestRaw); - compilation::Context params{fTest, scopeUnitTest, compiler}; + compilation::Context params{scopeUnitTest, fTest, compiler}; LoggerPass l(man); l.inject(symbX, params); llvm->initJit(); int (*f)() = (int(*)()) llvm->getFunctionPointer(fTest->raw); testing::internal::CaptureStdout(); f(); std::string&& output = testing::internal::GetCapturedStdout(); EXPECT_STREQ("10\n", output.c_str()); } TEST(LoggerPass, simpleInjection2){ PassManager* man = PassManager::prepareForCode("test= function():: int; entry{x = 2+8::int; logging. x}"); man->runWithoutCompilation(); CompilePass* compiler= new CompilePass(man); compiler->run(); LoggerPass* logger = new LoggerPass(man); logger->initDependencies(compiler); logger->run(); man->llvm->initJit(); man->llvm->print(); int (*f)() = (int(*)()) man->llvm->getFunctionPointer(compiler->getEntryFunction()); testing::internal::CaptureStdout(); f(); std::string&& output = testing::internal::GetCapturedStdout(); EXPECT_STREQ("10\n", output.c_str()); } TEST(LoggerPass, simpleInjection3){ FILE* input = fopen("scripts/cases/log.xreate","r"); assert(input); std::unique_ptr program(PassManager::prepareForCode(input)); void* mainPtr = program->run(); int (*main)() = (int (*)())(intptr_t)mainPtr; int answer = main(); fclose(input); } diff --git a/cpp/tests/testClangAPI.cpp b/cpp/tests/testClangAPI.cpp index 0005ad2..a1d96ce 100644 --- a/cpp/tests/testClangAPI.cpp +++ b/cpp/tests/testClangAPI.cpp @@ -1,190 +1,197 @@ // // Created by pgess on 4/16/15. // #include "gtest/gtest.h" #include #include "clang/Driver/Options.h" #include "clang/AST/AST.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Frontend/ASTConsumers.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Tooling.h" #include "clang/Rewrite/Core/Rewriter.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/CodeGen/CodeGenAction.h" -#include "/opt/llvm-toolchain-3.6-3.6/clang/lib/CodeGen/CodeGenTypes.h" -#include "/opt/llvm-toolchain-3.6-3.6/clang/lib/CodeGen/CodeGenModule.h" #include "clang/CodeGen/CodeGenABITypes.h" #include "llvm/IR/LLVMContext.h" #include "clang/Basic/TargetInfo.h" #include +#include "../../vendors/clang-codegen-private-3.8/CodeGenModule.h" using namespace std; using namespace clang; using namespace clang::driver; using namespace clang::tooling; using namespace clang::ast_matchers; using namespace llvm; /* class PrintFunctionsConsumer : public ASTConsumer { public: bool HandleTopLevelDecl(DeclGroupRef DG) override { for (DeclGroupRef::iterator i = DG.begin(), e = DG.end(); i != e; ++i) { const Decl *D = *i; if (const NamedDecl *ND = dyn_cast(D)) llvm::errs() << "top-level-decl: \"" << ND->getNameAsString() << "\"\n"; } return true; } }; class PFAction : public ASTFrontendAction { public: virtual std::unique_ptr CreateASTConsumer(CompilerInstance &CI, StringRef file) { return llvm::make_unique(); } }; */ class PrinterType : public MatchFinder::MatchCallback { public : virtual void run(const MatchFinder::MatchResult &Result) { ASTContext* C = Result.Context; llvm::Module* M = new llvm::Module("module1", llvm::getGlobalContext()); if (const TypedefDecl* decl = Result.Nodes.getNodeAs("typename")) { QualType Ty = decl->getUnderlyingType(); llvm::errs() << "<" << Ty.getAsString() << ">" ; - CodeGenOptions *CGO = new CodeGenOptions; - - const llvm::DataLayout& TD = llvm::DataLayout(C->getTargetInfo().getTargetDescription()); - CodeGen::CodeGenModule *CGM = new CodeGen::CodeGenModule(*C, *CGO, *M, TD, C->getDiagnostics()); + M->setDataLayout(C->getTargetInfo().getDataLayoutString()); + CodeGen::CodeGenModule *CGM = new CodeGen::CodeGenModule( + *C, + *(new HeaderSearchOptions()), + *(new PreprocessorOptions()), + *(new CodeGenOptions()), + *M, + C->getDiagnostics()); llvm::Type *rawTy = CGM->getTypes().ConvertType(Ty); rawTy->dump(); results.push_back(rawTy); } } std::vector results; }; class PrinterFunction: public MatchFinder::MatchCallback { public : virtual void run(const MatchFinder::MatchResult &Result) { if (const FunctionDecl* decl = Result.Nodes.getNodeAs("function")) { - QualType Ty = decl->getType(); - - llvm::errs() << "<" << Ty.getAsString() << ">" ; - ASTContext* C = Result.Context; - llvm::Module* M = new llvm::Module("module1", llvm::getGlobalContext()); - CodeGenOptions *CGO = new CodeGenOptions; - - const llvm::DataLayout& TD = llvm::DataLayout(C->getTargetInfo().getTargetDescription()); - CodeGen::CodeGenModule *CGM = new CodeGen::CodeGenModule(*C, *CGO, *M, TD, C->getDiagnostics()); - - llvm::Type *rawTy = CGM->getTypes().ConvertType(Ty); - - //const clang::FunctionType* Ty = decl->getType()->getAs(); - llvm::FunctionType* rawFuncTy = llvm::dyn_cast(rawTy); - rawFuncTy->dump(); - results.push_back(rawFuncTy); - - /* - llvm::Function* fDeclaration = llvm::Function::Create(rawFuncTy, llvm::GlobalValue::ExternalLinkage, "xxxx", M); - fDeclaration->dump(); - */ + QualType Ty = decl->getType(); + + llvm::errs() << "<" << Ty.getAsString() << ">" ; + ASTContext* C = Result.Context; + llvm::Module* M = new llvm::Module("module1", llvm::getGlobalContext()); + + CodeGen::CodeGenModule *CGM = new CodeGen::CodeGenModule( + *C, + *(new HeaderSearchOptions()), + *(new PreprocessorOptions()), + *(new CodeGenOptions()), + *M, + C->getDiagnostics()); + + llvm::Type *rawTy = CGM->getTypes().ConvertType(Ty); + + //const clang::FunctionType* Ty = decl->getType()->getAs(); + llvm::FunctionType* rawFuncTy = llvm::dyn_cast(rawTy); + rawFuncTy->dump(); + results.push_back(rawFuncTy); + + /* + llvm::Function* fDeclaration = llvm::Function::Create(rawFuncTy, llvm::GlobalValue::ExternalLinkage, "xxxx", M); + fDeclaration->dump(); + */ } } std::vector results; }; //DEBT fix dependency on clasp/gcc version vector argv = { "-I/usr/include/libxml2" ,"-I/usr/local/include" ,"-I/usr/lib/llvm-3.6/lib/clang/3.6.0/include" ,"-I/usr/include" }; TEST(ClangAPI, testExternalType) { //,, "-I/usr/include/linux" // "-cc1", "-emit-pch", "-disable-free", "-disable-llvm-verifier", "-mrelocation-model", "static", // "-mthread-model", "posix", "-mdisable-fp-elim", "-fmath-errno", "-masm-verbose", // "-mconstructor-aliases", "-munwind-tables", "-fuse-init-array", "-target-cpu", "x86-64", "-target-linker-version", "2.25", //"-dwarf-column-info", "-resource-dir", "/usr/lib/llvm-3.7/bin/../lib/clang/3.7.0", //"clang", "--", /* int argc= argv.size(); llvm::cl::OptionCategory cat("aaaa"); LLVMInitializeNativeTarget(); CommonOptionsParser op(argc, &*(argv.begin()), cat); ClangTool tool(op.getCompilations(), op.getSourcePathList()); */ auto matcherType = typedefDecl(hasName("xmlNodePtr")).bind("typename"); MatchFinder finder; PrinterType printer; finder.addMatcher(matcherType, &printer); std::string code = (boost::format("#include \"%1%\"") % ("libxml/tree.h")).str(); //runToolOnCodeWithArgs(newFrontendActionFactory(&finder).get()->create(), code, argv); std::unique_ptr ast = buildASTFromCodeWithArgs(code, argv); ASTContext & context = ast->getASTContext(); finder.matchAST(context); string signatureExpected = "%struct._xmlNode*"; ASSERT_EQ(1, printer.results.size()); llvm::Type* tyActual = printer.results.at(0); string strActual; llvm::raw_string_ostream ss(strActual); tyActual->print(ss); ASSERT_EQ(signatureExpected, ss.str()); //int x = tool.run(newFrontendActionFactory(&finder).get()); } TEST(ClangAPI, testExternalFunction){ auto matcherType = functionDecl(hasName("arc4random")).bind("function"); MatchFinder finder; PrinterFunction printer; finder.addMatcher(matcherType, &printer); std::string code = (boost::format("#include \"%1%\"") % ("bsd/stdlib.h")).str(); std::unique_ptr ast = buildASTFromCodeWithArgs(code, argv); ASTContext & context = ast->getASTContext(); finder.matchAST(context); string signatureExpected = "i32 ()"; ASSERT_EQ(1, printer.results.size()); llvm::Type* tyActual = printer.results.at(0); string strActual; llvm::raw_string_ostream ss(strActual); tyActual->print(ss); ASSERT_EQ(signatureExpected, ss.str()); } diff --git a/cpp/tests/testExploitation.cpp b/cpp/tests/testExploitation.cpp new file mode 100644 index 0000000..88cbc4d --- /dev/null +++ b/cpp/tests/testExploitation.cpp @@ -0,0 +1,49 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +#include "passmanager.h" + +#include "gtest/gtest.h" +#include + +using namespace xreate; +using namespace std; + +//TEST(Exploitation, append1){ +// std::string program = +//R"CODE( +// +//test1 = function :: num; entry { +// appendA() + appendB() +//} +// +//appendA = function:: num { +// append("a", "/tmp/test1.txt") +//} +// +//appendB = function:: num { +// append("b", "/tmp/test1.txt") +//} +// +//append = function(msg::string, filename::string):: num +//{ +// f = initialize(filename):: FILE. +// +// fprintf(f, msg) +//} +// +//)CODE"; +// +// boost::scoped_ptr man(PassManager::prepareForCode(move(program))); +// man->runWithoutCompilation(); +//} + +#include +#include +#include "clasplayer.h" + +TEST(Exploitation, clasp1){ +} diff --git a/cpp/tests/types.cpp b/cpp/tests/types.cpp index 5815c3b..97e2354 100644 --- a/cpp/tests/types.cpp +++ b/cpp/tests/types.cpp @@ -1,167 +1,167 @@ /* * types.cpp * * Created on: Jun 4, 2015 * Author: pgess */ #include "gtest/gtest.h" #include "passmanager.h" #include "llvmlayer.h" #include "Parser.h" using namespace std; using namespace xreate; TEST(Types, DependantTypes1) { string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n"; std::unique_ptr program(PassManager::prepareForCode(move(code))); ExpandedType typeXmlNode = program->root->findType("XmlNode"); ASSERT_EQ(TypeOperator::STRUCT, typeXmlNode->__operator); ASSERT_EQ(2, typeXmlNode->__operands.size()); ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(0).__value); ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(1).__value); } TEST(Types, DependantTypes2) { string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n" "" "Template = type Template(Leaf) [Leaf, [Leaf[content]]]." "Concrete = type alias Template(XmlNode)."; std::unique_ptr program(PassManager::prepareForCode(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); ASSERT_EQ(TypeOperator::TUPLE, typeConcrete->__operator); ASSERT_EQ(2, typeConcrete->__operands.size()); ASSERT_EQ(TypeOperator::STRUCT, typeConcrete->__operands.at(0).__operator); ASSERT_EQ(TypeOperator::ARRAY, typeConcrete->__operands.at(1).__operator); ASSERT_EQ(TypePrimitive::String, typeConcrete->__operands.at(1).__operands.at(0).__value); } TEST(Types, TreeType1) { string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n" "" "Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]." "Concrete = type alias Tree(XmlNode)."; std::unique_ptr program(PassManager::prepareForCode(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); ASSERT_EQ(TypeOperator::TUPLE, typeConcrete->__operator); ASSERT_EQ(2, typeConcrete->__operands.size()); ASSERT_EQ(TypeOperator::STRUCT, typeConcrete->__operands.at(0).__operator); ASSERT_EQ(TypeOperator::ARRAY, typeConcrete->__operands.at(1).__operator); auto typeLink = typeConcrete->__operands.at(1).__operands.at(0); ASSERT_EQ(TypeOperator::LINK, typeLink.__operator); ASSERT_EQ(typeConcrete->conjuctionId,typeLink.conjuctionId); } TEST(Types, TreeType1LLvm){ string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n" "" "Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]." "Concrete = type alias Tree(XmlNode)."; std::unique_ptr program(PassManager::prepareForCode(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); llvm::Type* raw = program->llvm->toLLVMType(typeConcrete); } TEST(Types, ArrayOfExternal1){ FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST& ast = parser.root; CodeScope* body = ast.findFunction("test")->getEntryScope(); Symbol symb = body->findSymbol("childrenRaw"); - const TypeAnnotation& t = CodeScope::findDefinition(symb); + const TypeAnnotation& t = CodeScope::findDeclaration(symb).type; const ExpandedType& t2 = ast.expandType(t); EXPECT_EQ(t2->__operator, TypeOperator::ARRAY); } TEST(Types, ExternType1){ FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST& ast = parser.root; CodeScope* body = ast.findFunction("test")->getEntryScope(); Symbol symbTree = body->findSymbol("tree"); - const TypeAnnotation& t = CodeScope::findDefinition(symbTree); + const TypeAnnotation& t = CodeScope::findDeclaration(symbTree).type; const ExpandedType& t2 = ast.expandType(t); EXPECT_EQ(t2->__operator, TypeOperator::CUSTOM); } TEST(Types, ast_VariantType1){ string&& code = " colors = type variant (RED, BLUE, GREEN).\n" " test = function:: colors; entry {GREEN}"; std::unique_ptr program(PassManager::prepareForCode(move(code))); ExpandedType typ = program->root->findType("colors"); EXPECT_EQ(TypeOperator::VARIANT, typ->__operator); Expression eRed = program->root->findFunction("test")->getEntryScope()->__body; EXPECT_EQ(Expression::VARIANT, eRed.__state); const ExpandedType& typ2 = program->root->expandType(eRed.type); EXPECT_EQ(TypeOperator::VARIANT, typ2->__operator); program->run(); } TEST(Types, full_VariantType_Switch1){ string&& code = " colors = type variant (RED, BLUE, GREEN).\n" " test = function:: colors; entry {GREEN}" "main = function:: int; entry {\n" " switch(test():: color)\n" " case GREEN {0}\n" " case default {1}\n" "}"; PassManager* man = PassManager::prepareForCode(move(code)); int (*main)() = (int (*)()) man->run(); EXPECT_EQ(0, main()); } -//TEST string type +//TOTEST string type diff --git a/documentation/Articles/gestalts.remarkup b/documentation/Articles/gestalts.remarkup index 338b33f..39efc54 100644 --- a/documentation/Articles/gestalts.remarkup +++ b/documentation/Articles/gestalts.remarkup @@ -1,12 +1,12 @@ ==Computational gestalts== There are number of commonly accepted concepts that are redefined or reevaluated in xreate. * Interface is comprised of common subset of features supported by all concrete implementations. See [[concepts/containers]] * Entity's annotations(like function, objects annotations) are exposed to and could be intospected by client code in other words by caller. Most usefull is exposing of caller annotations to a callee code. *Lazy/eager execution opposition. It's possible to determine which sites of using resource should treat it as lazy resource or eager otherwise. - See [[concepts/usage]] for details. \ No newline at end of file + See [[concepts/exploitation]] for details. \ No newline at end of file diff --git a/documentation/Aspects/highlevel.remarkup b/documentation/Aspects/highlevel.remarkup new file mode 100644 index 0000000..f724e71 --- /dev/null +++ b/documentation/Aspects/highlevel.remarkup @@ -0,0 +1,5 @@ +High-level: + +*Focus on current task +*Program Addtitivity +*Reduce refactoring needs \ No newline at end of file diff --git a/documentation/Aspects/refactoring.remarkup b/documentation/Aspects/refactoring.remarkup index 6b1531f..5623b2a 100644 --- a/documentation/Aspects/refactoring.remarkup +++ b/documentation/Aspects/refactoring.remarkup @@ -1 +1,4 @@ -Refactoring - ability to quiclky transform and apply software to different tasks \ No newline at end of file +Refactoring - ability to quiclky adjust and apply software to a different tasks + +reduce refactoring dimensions by 2. +2D refactoring: (rigid-soft software axe, memory-computation on the fly axe) is unnecessary and covered by additive annotations. \ No newline at end of file diff --git a/documentation/Concepts/usage.remarkup b/documentation/Concepts/exploitation.remarkup similarity index 57% rename from documentation/Concepts/usage.remarkup rename to documentation/Concepts/exploitation.remarkup index 67f3a6b..6589240 100644 --- a/documentation/Concepts/usage.remarkup +++ b/documentation/Concepts/exploitation.remarkup @@ -1,10 +1,11 @@ -Analyzing CFG to find first/last usage of resources: +Analyzing CFG to find common resource exploitation patterns, +like to determine sites of first and last usage of resources in order to check(provide) safe initialization or releasing. **Usecases:** * resource using in loop: acquire resource right before loop, and freeing right after that. * group of probable first/last using: every site in the group should treat resource as lazy(with safety check), and eager otherwise **Examples:** * appending to a file * memory management \ No newline at end of file diff --git a/documentation/Internal/todo.remarkup b/documentation/Internal/todo.remarkup new file mode 100644 index 0000000..37344cf --- /dev/null +++ b/documentation/Internal/todo.remarkup @@ -0,0 +1,2 @@ +* syntax/switch: mention about a case body scope is a subscope (or a child) of a case parameters scope + (as of now expression resolution only, not for annotations resolution) diff --git a/documentation/Syntax/control-flow-statements.remarkup b/documentation/Syntax/control-flow-statements.remarkup index 4901695..b9deedd 100644 --- a/documentation/Syntax/control-flow-statements.remarkup +++ b/documentation/Syntax/control-flow-statements.remarkup @@ -1,132 +1,132 @@ ==Control flow statements== These statements control execution flow of a program. === If-Else === The If-Else statement executes a //main-expression// branch if a specified condition is true. If the condition is false, //alternative-expression// branch will be executed. SYNTAX: if (//condition//):: //type// { [//declaration//. [ //declaration//.]... ] //main-expression// } else { [//declaration//. [ //declaration//.]... ] //alternative-expression// } //condition// Bool type expression(see [[types]]) in order to decide which branch of IF-ELSE statement should be executed. //main expression// Executed if condition yelds ##true## //alternative expression// Executed if condition yelds ##false## Example: x = if (y<0) :: num {-1} else {1} ===Switch=== Executes one of the given branches depending on condition. -SYNTAX: switch (//condition// :: //type-of-condition//) +SYNTAX: switch (//condition//) :: //type-of-switch// [case //variant// { [declaration. [ declaration.]... ] //transformation-expression// }]... //condition// Expression to determing which case branch should be executed -//type-of-condition// -Type of condition result +//type-of-switch// +Type of switch result //variant// Expression to compare against //condition//. If the //condition// evaluation result corresponds to the //variant// then a relevant branch is executed. Special label **default** is allowed and designates default branch executed if no other branches are selected. //transformation-expression// Determines result of a switch statement if relevant branch is selected based on //condition//. Example: x = 2:: num. - y = switch (x:: string) + y = switch (x) ::string case 0 {"zero"} case 1 {"one"} case 2 {"two"} case default {"unknown"} ===Map loop=== Iterates over input collection and stores result in another collection. Every input collection's value transformed using //transformation-expression//. SYNTAX: loop map ( //input-collection// -> //alias// :: //type-of-element//) :: //type-of-collection// { [declaration. [ declaration.]... ] //transformation-expression// } //input-collection// Variable or expression to designate collection for transformation //alias// Variable name to designate current collection element in scope of inner code block //type-of-element// Type of collection's element //type-of-collection// Type of resulting transformed collection //transformation-expression// Transformation applied to an every collection element Example: input = [1..10]. twice = loop map (input -> x:: num):: [num] { 2 * x } ===Fold loop=== Iterates over input collection in order to accumulate result by applying //transformation-expression// to each element and intermediate accumulator. SYNTAX: loop fold (//input-collection// -> //alias// :: //type-of-element//, //accumulator//->//accumulator-alias//) :: //type-of-accumulator// { [declaration. [ declaration.]... ] //transformation-expression// } //input-collection// Variable or expression to designate collection //alias// Variable name to designate current collection element in scope of inner code block //type-of-element// Type of collection's element //accumulator// Expression to evaluate initial value of accumulator //accumulator-alias// Variable name to designate current value of accumulator in scope of inner code block //type-of-accumulator// Type of folding result //transformation-expression// Expression applied to an every collection's element and current state of accumulator in order to calculate accumulator value for next step of iteration. This is an example: numbers = [1..10] :: [num]. sumOfNumbers = loop fold(numbers->x; 0->result) {result + x} diff --git a/documentation/Syntax/index.remarkup b/documentation/Syntax/index.remarkup index 6e2d7e1..5467fe4 100644 --- a/documentation/Syntax/index.remarkup +++ b/documentation/Syntax/index.remarkup @@ -1 +1,22 @@ -This section devoted to a syntax description \ No newline at end of file +This section devoted to a syntax description + +In general, syntax follows SSA form: every symbol has a single site of assignment. + +SYNTAX: +{ + [declaration.]... + //result-expression// +} + +Example: + { + t = Pi / 2 :: num. + left = sin(2 * t):: num. + right = cos(8 * t):: num. + + left + right // result expression + } + +SSA form being very simple and intuitive, however does not posssess expressiveness enough to cope +with more compilcated cases like [[loops | control-flow-statements]]. That's why there are specific syntax constructions +provided in order to keep basic SSA syntax but with different semantics suited for those compicated cases. \ No newline at end of file diff --git a/geany-plugin-sort.lua b/geany-plugin-sort.lua new file mode 100644 index 0000000..bee8616 --- /dev/null +++ b/geany-plugin-sort.lua @@ -0,0 +1,25 @@ +function split(str, pat) + local t = {} -- NOTE: use {n = 0} in Lua-5.0 + local fpat = "(.-)" .. pat + local last_end = 1 + local s, e, cap = str:find(fpat, 1) + while s do + if s ~= 1 or cap ~= "" then + table.insert(t,cap) + end + last_end = e+1 + s, e, cap = str:find(fpat, last_end) + end + if last_end <= #str then + cap = str:sub(last_end) + table.insert(t, cap) + end + return t +end + +geany.select(0, geany.length()) +local text = geany.selection() +local lines = split(text, " ") +table.sort(lines) +local output = table.concat(lines, "\n") +geany.selection(output) diff --git a/install-dependencies-opensuse b/install-dependencies-opensuse new file mode 100755 index 0000000..cebf18d --- /dev/null +++ b/install-dependencies-opensuse @@ -0,0 +1,39 @@ +#!/bin/sh +CURRENT_DIR=$PWD + +sudo zypper in tbb-devel cmake llvm-devel llvm-clang-devel git bison re2c scons unzip gcc-c++ libgtest0 googletest-devel boost-devel libxml2-devel + +# COCO +mkdir /opt/coco-cpp/ +cd /opt/coco-cpp/ +if [ ! -f ./CocoSourcesCPP.zip ]; then + wget http://www.ssw.uni-linz.ac.at/Coco/CPP/CocoSourcesCPP.zip + unzip ./CocoSourcesCPP.zip +fi + +g++ *.cpp -o Coco -g -Wall + +# POTASSCO +mkdir /opt/potassco/ +cd /opt/potassco/ +git clone https://github.com/potassco/clingo.git +cd clingo +sed -i "s/CXXFLAGS = \[\(.*\)\]/CXXFLAGS = \['-fPIC', \1\]/" build/debug.py +scons --build-dir=debug + +sed -i "s/CXXFLAGS = \[\(.*\)\]/CXXFLAGS = \['-fPIC', \1\]/" build/release.py +scons --build-dir=release + + +cd $CURRENT_DIR +mkdir ./build/xreate-tests-debug +cd ./build/xreate-tests-debug +cmake -DBUILD_XREATE_TESTS=1 -build ../../cpp + +make -j2 + + + + + + diff --git a/scripts/containers/containers-indexed-1.xreate b/scripts/containers/containers-indexed-1.xreate new file mode 100644 index 0000000..69fd40c --- /dev/null +++ b/scripts/containers/containers-indexed-1.xreate @@ -0,0 +1,29 @@ +//Expose indexes signature(anonymous): + a:: [(string, string, num)]; byName <- index(0); byCity <- index(1); + byNameAndCity <- index(0, 1). + +//Expose index signature(named) + type Record = + { + name:: string, + city:: string, + age:: num + }. + + b:: [Record]; byName <- index(Record.name). + +//Use determined index + x = a["Rabat"]:: Record; index(byCity). + +//Determined syntax(view) + viewByCity = a:: [Record]; index(byCIty). + x = viewByCity["Rabat"]. + +//Determined index(inline) + x = a[byCity: "Rabbat"]:: Record. + + +//Undefined index + x = a[{city: "Rabat"}] :: Record. <- index byCity should be deduced + x = a[{name: "Hind", city: "Rabat"}] + diff --git a/scripts/dsl/regexps.xreate b/scripts/dsl/regexps.xreate new file mode 100644 index 0000000..b02d3e1 --- /dev/null +++ b/scripts/dsl/regexps.xreate @@ -0,0 +1,81 @@ +=========================== + DATA + +patternAB = { + sequence: [ + {zeroOrMore: 'a'}, + {text: 'b'}, + ] +} + +mod sequence{ +[ + mod zeroOrMore (text("a")), + matcher text("b") +] +) + + +========================== + HANDLERS + + case matcher:: mod sequence +match = function(text, matcher) { + loop fold(node-> matcher, 0->pos){ + n = match(matcher, mid(text, pos, length(text))).// <-- every time length? + + if (pos == pos_FAIL || n == pos_FAIL){ + pos_FAIL:: break + } else { + pos+n + } + } +} + + case matcher:: mod zeroOrMore (Dereferenced) +match= function(text, matcher){ + matcherChild = matcher:: Dereferenced. //<--- extract child(unification) + + loop fold inf(0->pos, n==pos_FAIL){ //<--- infinite loop? + n = match(matcherChild, mid(text, pos, length(text))). + + if (n == pos_FAIL:: break){ + pos + + } else { + pos+n + } + } +} + + case matcher:: matcher text +match = function(text, matcher) { + pattern = matcher:: string. + + if (length(text)>0 && + length(pattern) <= length(text) && + mid(text, 0, length(pattern)) == pattern) + { + length(pattern); + + } else { + pos_FAIL; + } +} + +match = function(text::string, pattern::string)::string{ + n= match(pattern, text). + + if (n != pos_FAIL) + {mid(text, 0, n)} + else + {text_FAIL} +} + +================================= + CLIENT + +test = function(){ + match(patternAB, "aaaaab"). + match(patternAB, "baaaaa"). +} diff --git a/scripts/exploitation/test1-fixture.lp b/scripts/exploitation/test1-fixture.lp new file mode 100644 index 0000000..491a935 --- /dev/null +++ b/scripts/exploitation/test1-fixture.lp @@ -0,0 +1,50 @@ +function(test1). +bind_func(test1, entry). +function(appendA; appendB; append). +scope(0..3). +%scope tags: no tags at all + +% Static analysis: CFA +cfa_parent(0, function(test1)). +cfa_parent(1, function(appendA)). +cfa_parent(2, function(appendB)). +cfa_parent(3, function(append)). +cfa_call(0, appendA). +cfa_call(0, appendB). +cfa_call(1, append). +cfa_call(2, append). + +% Static analysis: DFA +dfa_connection((2, 3), (anonym(0), 1), weak). %append:msg - anonym(0) +dfa_connection((3, 3), (anonym(1), 1), weak). %append:filename - anonym(1) +dfa_connection((0, 1), (0, 3), strong). %appendA: *retv - append: *retv +dfa_connection((2, 3), (anonym(2), 2), weak). %append:msg - anonym(2) +dfa_connection((3, 3), (anonym(3), 2), weak). %append:filename - anonym(3) +dfa_connection((0, 2), (0, 3), strong). %appendB: *retv - append: *retv + +v((anonym(0), 1)). %anonym(0) +v((anonym(1), 1)). %anonym(1) +v((0, 2)). %appendB: *retv +v((anonym(2), 2)). %anonym(2) +v((anonym(3), 2)). %anonym(3) +v((0, 3)). %append: *retv +v((2, 3)). %append:msg +v((3, 3)). %append:filename + +cfa_forwdom(0, range(0, 7)). +cfa_forwdom(1, range(1, 2)). +cfa_forwdom(2, range(5, 6)). +cfa_forwdom(3, range(3, 4)). +cfa_postdom(0, range(3, 4)). +cfa_postdom(1, range(1, 2)). +cfa_postdom(2, range(5, 6)). +cfa_postdom(3, range(0, 7)). + +% EXPLOITATION TAGS: +bind((3,3), exploitation_initialized(file)). + +% BIND ACTUAL DATA FOR STATIC SYMBOLS +bind((anonym(0), 1), static(data(a))). %anonym(0) +bind((anonym(1), 1), static(data(tmp_test1_txt))). %anonym(1) +bind((anonym(2), 2), static(data(b))). %anonym(2) +bind((anonym(3), 2), static(data(tmp_test1_txt))). %anonym(3) diff --git a/scripts/exploitation/test1.xreate b/scripts/exploitation/test1.xreate new file mode 100644 index 0000000..cc8eced --- /dev/null +++ b/scripts/exploitation/test1.xreate @@ -0,0 +1,38 @@ +test1 = function :: int; entry { + appendA() + appendB +} + +appendA = function:: int { + append("a", "/tmp/test1.txt") +} + +appendB = function:: int { + append("b", "/tmp/test1.txt") +} + +append:: function(message::string, filename::string):: int, +{ + f = initialize(filename):: FILE. + + fprintf(f, message) +} + +====================================================== +initialize(filename:: string; exploitation_file_initialized) +{ + // get cached descriptor for FileName: + files:: cached(exploitation_files). + + files[filename] +} + +attach scope:: openFile(FileName) { + fid = fopen(FileName). + (FileName, fid):: cached(exploitation_files). +} + +attach scope:: closeFile(FileName){ + files:: cached(exploitation_files). + fid = files[FileName]. + fclose(fid) +} diff --git a/scripts/metatests/aux/graphs_trees_depth-test1.lp b/scripts/metatests/aux/graphs_trees_depth-test1.lp new file mode 100644 index 0000000..00f89f7 --- /dev/null +++ b/scripts/metatests/aux/graphs_trees_depth-test1.lp @@ -0,0 +1,9 @@ +#include "core/aux/graphs_trees_depth.lp". + +graphs_node(a; b; c; d). +graphs_tree_depends(b,a). +graphs_tree_depends(c,a). +graphs_tree_depends(d, a). +graphs_tree_depends(d, c). + +#show graphs_tree_depth/2. \ No newline at end of file diff --git a/scripts/metatests/aux/graphs_trees_depth-test2.lp b/scripts/metatests/aux/graphs_trees_depth-test2.lp new file mode 100644 index 0000000..630d807 --- /dev/null +++ b/scripts/metatests/aux/graphs_trees_depth-test2.lp @@ -0,0 +1,8 @@ +#include "core/aux/graphs_trees_depth.lp". + +graphs_node(a; b; c). +graphs_tree_depends(b,a). +graphs_tree_depends(b,c). +graphs_tree_depends(c,b). + +#show graphs_tree_depth/2. \ No newline at end of file diff --git a/scripts/metatests/exploitation-test1.lp b/scripts/metatests/exploitation-test1.lp new file mode 100644 index 0000000..c217721 --- /dev/null +++ b/scripts/metatests/exploitation-test1.lp @@ -0,0 +1,10 @@ +#include "core/precompilation.lp". +#include "core/exploitation.lp". + +#include "scripts/exploitation/test1-fixture.lp". + +#show bind/2. +#show expl_sites/2. +#show expl_resources/2. +#show expl_parent/2. +#show bind_scope/2. diff --git a/scripts/metatests/tests1-context-latecontext3.lp b/scripts/metatests/tests1-context-latecontext3.lp index 28c84be..f344ff0 100644 --- a/scripts/metatests/tests1-context-latecontext3.lp +++ b/scripts/metatests/tests1-context-latecontext3.lp @@ -1,39 +1,75 @@ -#include "context-latecontext3.lp". -function(a;b;r0; r1; sink; fnOut). -scope(0..5). +#include "core/control-context-v3.lp". +function(a1;b1;a2;b2;a3;b3; sink; fnOut). +scope(0..7). %CFA -cfa_parent(0, function(a)). -cfa_parent(1, function(b)). -cfa_parent(2, function(r0)). -cfa_parent(3, function(r1)). -cfa_parent(4, function(sink)). -cfa_parent(5, function(fnOut)). - -cfa_function_specializations(fnOut, keys(keyA0)). -cfa_function_specializations(fnOut, keys(keyA1)). -cfa_function_specializations(fnOut, keys(keyB0)). -cfa_function_specializations(fnOut, keys(keyB1)). - - -cfa_call(0, r0). -cfa_call(0, r1). -cfa_call(1, r0). -cfa_call(1, r1). -cfa_call(2, sink). -cfa_call(3, sink). -cfa_call(4, fnOut). +cfa_parent(0, function(a1)). +cfa_parent(1, function(b1)). +cfa_parent(2, function(a2)). +cfa_parent(3, function(b2)). +cfa_parent(4, function(a3)). +cfa_parent(5, function(b3)). + +cfa_parent(6, function(sink)). +cfa_parent(7, function(fnOut)). + +cfa_function_specializations(fnOut, keys(keyA1A2A3)). +cfa_function_specializations(fnOut, keys(keyA1A2B3)). +cfa_function_specializations(fnOut, keys(keyA1B2A3)). +cfa_function_specializations(fnOut, keys(keyA1B2B3)). +cfa_function_specializations(fnOut, keys(keyB1A2A3)). +cfa_function_specializations(fnOut, keys(keyB1A2B3)). +cfa_function_specializations(fnOut, keys(keyB1B2A3)). +cfa_function_specializations(fnOut, keys(keyB1B2B3)). + + +cfa_call(0, a2). +cfa_call(0, b2). +cfa_call(1, a2). +cfa_call(1, b2). +cfa_call(2, a3). +cfa_call(2, b3). +cfa_call(3, a3). +cfa_call(3, b3). +cfa_call(4, sink). +cfa_call(5, sink). +cfa_call(6, fnOut). %context rules % r0: keyA->keyA0, keyB->keyB0 % r1: keyA->keyA1, keyB->keyB1 -bind_scope(2, keys(keyA0), Info) :- bind_scope(2, keys(keyA), Info). -bind_scope(2, keys(keyB0), Info) :- bind_scope(2, keys(keyB), Info). -bind_scope(3, keys(keyA1), Info) :- bind_scope(3, keys(keyA), Info). -bind_scope(3, keys(keyB1), Info) :- bind_scope(3, keys(keyB), Info). +bind_scope(2, keys(keyA1A2), Info) :- bind_scope(2, keys(keyA1), Info). +bind_scope(2, keys(keyB1A2), Info) :- bind_scope(2, keys(keyB1), Info). +bind_scope(3, keys(keyA1B2), Info) :- bind_scope(3, keys(keyA1), Info). +bind_scope(3, keys(keyB1B2), Info) :- bind_scope(3, keys(keyB1), Info). + +bind_scope(4, keys(keyA1A2A3), Info):-bind_scope(4, keys(keyA1A2), Info). +bind_scope(4, keys(keyB1A2A3), Info):-bind_scope(4, keys(keyB1A2), Info). +bind_scope(4, keys(keyA1B2A3), Info):-bind_scope(4, keys(keyA1B2), Info). +bind_scope(4, keys(keyB1B2A3), Info):-bind_scope(4, keys(keyB1B2), Info). + +bind_scope(5, keys(keyA1A2B3), Info):-bind_scope(5, keys(keyA1A2), Info). +bind_scope(5, keys(keyB1A2B3), Info):-bind_scope(5, keys(keyB1A2), Info). +bind_scope(5, keys(keyA1B2B3), Info):-bind_scope(5, keys(keyA1B2), Info). +bind_scope(5, keys(keyB1B2B3), Info):-bind_scope(5, keys(keyB1B2), Info). + %initial context -keys(keyA; keyB; keyA0; keyA1; keyB0; keyB1). +keys( + keyA1; keyB1; + keyA1A2; + keyB1A2; + keyA1B2; + keyB1B2; + keyA1A2A3; + keyA1A2B3; + keyA1B2A3; + keyA1B2B3; + keyB1A2A3; + keyB1A2B3; + keyB1B2A3; + keyB1B2B3 +). -bind_scope(0, keys(keyA), strong). -bind_scope(1, keys(keyB), strong). +bind_scope(0, keys(keyA1), strong). +bind_scope(1, keys(keyB1), strong). diff --git a/scripts/precompilation-1.lp b/scripts/precompilation-1.lp new file mode 100644 index 0000000..1c14007 --- /dev/null +++ b/scripts/precompilation-1.lp @@ -0,0 +1,11 @@ +%%DATA EMBEDDING: + %bind(S, static(Data)):- Data= ref(_); bind(SymbolFrom, static(Data)); dfa_connection(S, SymbolFrom, _). + %bind(S, static(ref(Root))):- Data= data(_); bind(Root, static(Data)); dfa_connection(S, Root, _). + +%% SCHEME: + % bind(S, static). + % dfa_static(S, data(Data)) + % dfa_static(S, ref(RootSymbol)) + +bind(S2, static) :- bind(S1, static): dfa_connection(S2, S1, _). + diff --git a/scripts/metatests/(invalid)tests-context.lp b/scripts/sprint1_environment/(invalid)tests-context.lp similarity index 100% rename from scripts/metatests/(invalid)tests-context.lp rename to scripts/sprint1_environment/(invalid)tests-context.lp diff --git a/scripts/metatests/context-latecontext1.lp b/scripts/sprint1_environment/context-latecontext1.lp similarity index 100% rename from scripts/metatests/context-latecontext1.lp rename to scripts/sprint1_environment/context-latecontext1.lp diff --git a/scripts/metatests/context-latecontext2.lp b/scripts/sprint1_environment/context-latecontext2.lp similarity index 100% rename from scripts/metatests/context-latecontext2.lp rename to scripts/sprint1_environment/context-latecontext2.lp diff --git a/scripts/metatests/context-latecontext3.lp b/scripts/sprint1_environment/context-latecontext3.lp similarity index 100% rename from scripts/metatests/context-latecontext3.lp rename to scripts/sprint1_environment/context-latecontext3.lp diff --git a/scripts/sprint1_environment/dependencies.lp b/scripts/sprint1_environment/dependencies.lp deleted file mode 100644 index 5dab87b..0000000 --- a/scripts/sprint1_environment/dependencies.lp +++ /dev/null @@ -1,9 +0,0 @@ -node(a; b; c; d). -depends(b,a). -depends(c,a). -depends(d, a). -depends(d, c). - -level(X, 0) :- not depends(X, _); node(X). - -level(X, LEVEL):- LEVEL = #max{L+1, level(Y, L): level(Y, L), depends(X, Y)}; node(X); LEVEL > 0. diff --git a/scripts/sprint1_environment/dependencies.lp b/scripts/sprint1_environment/dependencies.lp new file mode 120000 index 0000000..5d00940 --- /dev/null +++ b/scripts/sprint1_environment/dependencies.lp @@ -0,0 +1 @@ +/private/prg/code/xreate/core/graphs_trees_depth.lp \ No newline at end of file diff --git a/scripts/sprint1_environment/solution-latecontext-3layers b/scripts/sprint1_environment/solution-latecontext-3layers new file mode 100644 index 0000000..2d13d91 --- /dev/null +++ b/scripts/sprint1_environment/solution-latecontext-3layers @@ -0,0 +1,192 @@ + +bind_function_demand(a2,dependency(dependency(specialization(fnOut,6),4),2)) +bind_function_demand(a2,dependency(dependency(specialization(fnOut,6),5),2)) +bind_function_demand(a2,dependency(specialization(fnOut,6),2)) +bind_function_demand(a3,dependency(specialization(fnOut,6),4)) +bind_function_demand(b2,dependency(dependency(specialization(fnOut,6),4),3)) +bind_function_demand(b2,dependency(dependency(specialization(fnOut,6),5),3)) +bind_function_demand(b2,dependency(specialization(fnOut,6),3)) +bind_function_demand(b3,dependency(specialization(fnOut,6),5)) +bind_function_demand(sink,specialization(fnOut,6)) + +bind_scope_demand(2,dependency(dependency(specialization(fnOut,6),4),2)) +bind_scope_demand(2,dependency(dependency(specialization(fnOut,6),5),2)) +bind_scope_demand(2,dependency(specialization(fnOut,6),2)) +bind_scope_demand(3,dependency(dependency(specialization(fnOut,6),4),3)) +bind_scope_demand(3,dependency(dependency(specialization(fnOut,6),5),3)) +bind_scope_demand(3,dependency(specialization(fnOut,6),3)) +bind_scope_demand(4,dependency(specialization(fnOut,6),4)) +bind_scope_demand(5,dependency(specialization(fnOut,6),5)) +bind_scope_demand(6,specialization(fnOut,6)) + +bind_scope_decision(0,dependency(dependency(specialization(fnOut,6),4),2),weak(0)) +bind_scope_decision(0,dependency(dependency(specialization(fnOut,6),4),3),weak(0)) +bind_scope_decision(0,dependency(dependency(specialization(fnOut,6),5),2),weak(0)) +bind_scope_decision(0,dependency(dependency(specialization(fnOut,6),5),3),weak(0)) +bind_scope_decision(0,dependency(specialization(fnOut,6),2),weak(0)) +bind_scope_decision(0,dependency(specialization(fnOut,6),3),weak(0)) +bind_scope_decision(1,dependency(dependency(specialization(fnOut,6),4),2),weak(1)) +bind_scope_decision(1,dependency(dependency(specialization(fnOut,6),4),3),weak(1)) +bind_scope_decision(1,dependency(dependency(specialization(fnOut,6),5),2),weak(1)) +bind_scope_decision(1,dependency(dependency(specialization(fnOut,6),5),3),weak(1)) +bind_scope_decision(1,dependency(specialization(fnOut,6),2),weak(1)) +bind_scope_decision(1,dependency(specialization(fnOut,6),3),weak(1)) +bind_scope_decision(2,dependency(specialization(fnOut,6),4),resolution_dependency(weak(2,weak(0)),weak(0))) +bind_scope_decision(2,dependency(specialization(fnOut,6),4),resolution_dependency(weak(2,weak(1)),weak(1))) +bind_scope_decision(2,dependency(specialization(fnOut,6),5),resolution_dependency(weak(2,weak(0)),weak(0))) +bind_scope_decision(2,dependency(specialization(fnOut,6),5),resolution_dependency(weak(2,weak(1)),weak(1))) +bind_scope_decision(3,dependency(specialization(fnOut,6),4),resolution_dependency(weak(3,weak(0)),weak(0))) +bind_scope_decision(3,dependency(specialization(fnOut,6),4),resolution_dependency(weak(3,weak(1)),weak(1))) +bind_scope_decision(3,dependency(specialization(fnOut,6),5),resolution_dependency(weak(3,weak(0)),weak(0))) +bind_scope_decision(3,dependency(specialization(fnOut,6),5),resolution_dependency(weak(3,weak(1)),weak(1))) +bind_scope_decision(4,specialization(fnOut,6),resolution_dependency(keys(keyA1A2A3),weak(2,weak(0)))) +bind_scope_decision(4,specialization(fnOut,6),resolution_dependency(keys(keyA1B2A3),weak(3,weak(0)))) +bind_scope_decision(4,specialization(fnOut,6),resolution_dependency(keys(keyB1A2A3),weak(2,weak(1)))) +bind_scope_decision(4,specialization(fnOut,6),resolution_dependency(keys(keyB1B2A3),weak(3,weak(1)))) +bind_scope_decision(5,specialization(fnOut,6),resolution_dependency(keys(keyA1A2B3),weak(2,weak(0)))) +bind_scope_decision(5,specialization(fnOut,6),resolution_dependency(keys(keyA1B2B3),weak(3,weak(0)))) +bind_scope_decision(5,specialization(fnOut,6),resolution_dependency(keys(keyB1A2B3),weak(2,weak(1)))) +bind_scope_decision(5,specialization(fnOut,6),resolution_dependency(keys(keyB1B2B3),weak(3,weak(1)))) + +scope_dependencies(dependency(dependency(specialization(fnOut,6),4),2),weak(0)) +scope_dependencies(dependency(dependency(specialization(fnOut,6),4),2),weak(1)) +scope_dependencies(dependency(dependency(specialization(fnOut,6),4),3),weak(0)) +scope_dependencies(dependency(dependency(specialization(fnOut,6),4),3),weak(1)) +scope_dependencies(dependency(dependency(specialization(fnOut,6),5),2),weak(0)) +scope_dependencies(dependency(dependency(specialization(fnOut,6),5),2),weak(1)) +scope_dependencies(dependency(dependency(specialization(fnOut,6),5),3),weak(0)) +scope_dependencies(dependency(dependency(specialization(fnOut,6),5),3),weak(1)) +scope_dependencies(dependency(specialization(fnOut,6),2),weak(0)) +scope_dependencies(dependency(specialization(fnOut,6),2),weak(1)) +scope_dependencies(dependency(specialization(fnOut,6),3),weak(0)) +scope_dependencies(dependency(specialization(fnOut,6),3),weak(1)) +scope_dependencies(dependency(specialization(fnOut,6),4),weak(2,weak(0))) +scope_dependencies(dependency(specialization(fnOut,6),4),weak(2,weak(1))) +scope_dependencies(dependency(specialization(fnOut,6),4),weak(3,weak(0))) +scope_dependencies(dependency(specialization(fnOut,6),4),weak(3,weak(1))) +scope_dependencies(dependency(specialization(fnOut,6),5),weak(2,weak(0))) +scope_dependencies(dependency(specialization(fnOut,6),5),weak(2,weak(1))) +scope_dependencies(dependency(specialization(fnOut,6),5),weak(3,weak(0))) +scope_dependencies(dependency(specialization(fnOut,6),5),weak(3,weak(1))) + +bind_scope(0,keys(keyA1),strong) +bind_scope(1,keys(keyB1),strong) +bind_scope(2,keys(keyA1),weak(0)) +bind_scope(2,keys(keyA1A2),weak(0)) +bind_scope(2,keys(keyB1),weak(1)) +bind_scope(2,keys(keyB1A2),weak(1)) +bind_scope(3,keys(keyA1),weak(0)) +bind_scope(3,keys(keyA1B2),weak(0)) +bind_scope(3,keys(keyB1),weak(1)) +bind_scope(3,keys(keyB1B2),weak(1)) +bind_scope(4,keys(keyA1),weak(0)) +bind_scope(4,keys(keyA1A2),weak(2,weak(0))) +bind_scope(4,keys(keyA1A2A3),weak(2,weak(0))) +bind_scope(4,keys(keyA1B2),weak(3,weak(0))) +bind_scope(4,keys(keyA1B2A3),weak(3,weak(0))) +bind_scope(4,keys(keyB1),weak(1)) +bind_scope(4,keys(keyB1A2),weak(2,weak(1))) +bind_scope(4,keys(keyB1A2A3),weak(2,weak(1))) +bind_scope(4,keys(keyB1B2),weak(3,weak(1))) +bind_scope(4,keys(keyB1B2A3),weak(3,weak(1))) +bind_scope(5,keys(keyA1),weak(0)) +bind_scope(5,keys(keyA1A2),weak(2,weak(0))) +bind_scope(5,keys(keyA1A2B3),weak(2,weak(0))) +bind_scope(5,keys(keyA1B2),weak(3,weak(0))) +bind_scope(5,keys(keyA1B2B3),weak(3,weak(0))) +bind_scope(5,keys(keyB1),weak(1)) +bind_scope(5,keys(keyB1A2),weak(2,weak(1))) +bind_scope(5,keys(keyB1A2B3),weak(2,weak(1))) +bind_scope(5,keys(keyB1B2),weak(3,weak(1))) +bind_scope(5,keys(keyB1B2B3),weak(3,weak(1))) +bind_scope(6,keys(keyA1),weak(0)) +bind_scope(6,keys(keyA1A2),weak(2,weak(0))) +bind_scope(6,keys(keyA1A2A3),weak(4,weak(2,weak(0)))) +bind_scope(6,keys(keyA1A2B3),weak(5,weak(2,weak(0)))) +bind_scope(6,keys(keyA1B2),weak(3,weak(0))) +bind_scope(6,keys(keyA1B2A3),weak(4,weak(3,weak(0)))) +bind_scope(6,keys(keyA1B2B3),weak(5,weak(3,weak(0)))) +bind_scope(6,keys(keyB1),weak(1)) +bind_scope(6,keys(keyB1A2),weak(2,weak(1))) +bind_scope(6,keys(keyB1A2A3),weak(4,weak(2,weak(1)))) +bind_scope(6,keys(keyB1A2B3),weak(5,weak(2,weak(1)))) +bind_scope(6,keys(keyB1B2),weak(3,weak(1))) +bind_scope(6,keys(keyB1B2A3),weak(4,weak(3,weak(1)))) +bind_scope(6,keys(keyB1B2B3),weak(5,weak(3,weak(1)))) +bind_scope(7,keys(keyA1),weak(0)) +bind_scope(7,keys(keyA1A2),weak(2,weak(0))) +bind_scope(7,keys(keyA1A2A3),weak(4,weak(2,weak(0)))) +bind_scope(7,keys(keyA1A2B3),weak(5,weak(2,weak(0)))) +bind_scope(7,keys(keyA1B2),weak(3,weak(0))) +bind_scope(7,keys(keyA1B2A3),weak(4,weak(3,weak(0)))) +bind_scope(7,keys(keyA1B2B3),weak(5,weak(3,weak(0)))) +bind_scope(7,keys(keyB1),weak(1)) +bind_scope(7,keys(keyB1A2),weak(2,weak(1))) +bind_scope(7,keys(keyB1A2A3),weak(4,weak(2,weak(1)))) +bind_scope(7,keys(keyB1A2B3),weak(5,weak(2,weak(1)))) +bind_scope(7,keys(keyB1B2),weak(3,weak(1))) +bind_scope(7,keys(keyB1B2A3),weak(4,weak(3,weak(1)))) +bind_scope(7,keys(keyB1B2B3),weak(5,weak(3,weak(1)))) + + + + +cfa_call(0,a2) +cfa_call(0,b2) +cfa_call(1,a2) +cfa_call(1,b2) +cfa_call(2,a3) +cfa_call(2,b3) +cfa_call(3,a3) +cfa_call(3,b3) +cfa_call(4,sink) +cfa_call(5,sink) +cfa_call(6,fnOut) +cfa_function_specializations(fnOut,keys(keyA1A2A3)) +cfa_function_specializations(fnOut,keys(keyA1A2B3)) +cfa_function_specializations(fnOut,keys(keyA1B2A3)) +cfa_function_specializations(fnOut,keys(keyA1B2B3)) +cfa_function_specializations(fnOut,keys(keyB1A2A3)) +cfa_function_specializations(fnOut,keys(keyB1A2B3)) +cfa_function_specializations(fnOut,keys(keyB1B2A3)) +cfa_function_specializations(fnOut,keys(keyB1B2B3)) +cfa_parent(0,function(a1)) +cfa_parent(1,function(b1)) +cfa_parent(2,function(a2)) +cfa_parent(3,function(b2)) +cfa_parent(4,function(a3)) +cfa_parent(5,function(b3)) +cfa_parent(6,function(sink)) +cfa_parent(7,function(fnOut)) +function(a1) +function(a2) +function(a3) +function(b1) +function(b2) +function(b3) +function(fnOut) +function(sink) +keys(keyA1) +keys(keyA1A2) +keys(keyA1A2A3) +keys(keyA1A2B3) +keys(keyA1B2) +keys(keyA1B2A3) +keys(keyA1B2B3) +keys(keyB1) +keys(keyB1A2) +keys(keyB1A2A3) +keys(keyB1A2B3) +keys(keyB1B2) +keys(keyB1B2A3) +keys(keyB1B2B3) +scope(0) +scope(1) +scope(2) +scope(3) +scope(4) +scope(5) +scope(6) +scope(7) + +true \ No newline at end of file diff --git a/scripts/sprint1_environment/tests1-context-latecontext3.lp b/scripts/sprint1_environment/tests1-context-latecontext3.lp new file mode 120000 index 0000000..c21293f --- /dev/null +++ b/scripts/sprint1_environment/tests1-context-latecontext3.lp @@ -0,0 +1 @@ +/private/prg/code/xreate/scripts/metatests/tests1-context-latecontext3.lp \ No newline at end of file