No OneTemporary

File Metadata

Created
Sat, Mar 14, 4:38 AM
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/core/containers.lp b/core/containers.lp
index 16b5432..d2f472d 100644
--- a/core/containers.lp
+++ b/core/containers.lp
@@ -1,44 +1,48 @@
+% This Source Code Form is subject to the terms of the Mozilla Public
+% License, v. 2.0. If a copy of the MPL was not distributed with this
+% file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
%defines
impl(llvm_array; llvm_const_array; on_the_fly).
op(seqaccess). op(randaccess).
relation(recommends; satisfied; unsupported).
relation_score(satisfied, 0).
relation_score(recommends, 1).
relation_score(unsupported, -1).
score(-1..1).
%domain facts:
relation_op(seqaccess, on_the_fly, recommends).
relation_op(randaccess, llvm_const_array, recommends).
relation_op(randaccess, on_the_fly, unsupported).
%dfa analysis:
% --
%compilation:
%--
%domain rules:
-impl_fulfill(OP, IMPL) :- relation_op(OP, IMPL, unsupported).
impl_fulfill(OP, IMPL, SCORE):- SCORE = #sum{SCORE1, (OP, IMPL, RL): relation_op(OP, IMPL, RL),relation_score(RL, SCORE1)}
; op(OP); impl(IMPL); not -impl_fulfill(OP, IMPL).
cluster_root(VAR) :- not dfa_connection(VAR, _, strong), v(VAR).
var_cluster(VAR0, VAR_TO) :- dfa_connection(VAR_TO, VAR0, strong), cluster_root(VAR0).
var_cluster(VAR0, VAR_TO2) :- dfa_connection(VAR_TO2, VAR_TO1, strong), var_cluster(VAR0, VAR_TO1).
var_cluster(VAR0, VAR0):- cluster_root(VAR0).
-impl_fulfill_cluster(Var0, Impl) :- var_cluster(Var0, Var_Any); bind(Var_Any, op(Op)); -impl_fulfill(Op, Impl).
impl_fulfill_cluster(VAR0, IMPL, Score) :-
Score = #sum{SCORE, (OP, IMPL, VAR_ANY): impl_fulfill(OP, IMPL, SCORE), var_cluster(VAR0, VAR_ANY), bind(VAR_ANY, op(OP))}
; bind(VAR0, impl(IMPL)); cluster_root(VAR0); not -impl_fulfill_cluster(VAR0, IMPL).
proto_cluster(V0, Vproto) :- cluster_root(V0); cluster_root(Vproto); var_cluster(Vproto, Vp); dfa_connection(V0, Vp, proto).
%optimization
% #maximize {SCORE, (VAR0, IMPL) : impl_fulfill_cluster(VAR0, IMPL, SCORE)}.
#show var_cluster/2.
#show impl_fulfill_cluster/3.
diff --git a/core/control-context-v1.lp b/core/control-context-v1.lp
index 62237fe..220461a 100644
--- a/core/control-context-v1.lp
+++ b/core/control-context-v1.lp
@@ -1,24 +1,28 @@
+% This Source Code Form is subject to the terms of the Mozilla Public
+% License, v. 2.0. If a copy of the MPL was not distributed with this
+% file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
% 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/core/control-context-v3.lp b/core/control-context-v3.lp
index 1b651f1..a04f1b6 100644
--- a/core/control-context-v3.lp
+++ b/core/control-context-v3.lp
@@ -1,52 +1,56 @@
+% This Source Code Form is subject to the terms of the Mozilla Public
+% License, v. 2.0. If a copy of the MPL was not distributed with this
+% file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
%% 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_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/cpp/src/ExternLayer.cpp b/cpp/src/ExternLayer.cpp
index 8874a23..949d23a 100644
--- a/cpp/src/ExternLayer.cpp
+++ b/cpp/src/ExternLayer.cpp
@@ -1,310 +1,321 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * ExternLayer.cpp
+ *
+ * Created on: 4/21/15
+ * Author: pgess <v.melnychenko@xreate.org>
+ */
+
+
//
-// Created by pgess on 4/21/15.
+// Created by pgess on .
//
#include "ExternLayer.h"
#include <cstdio>
#include <iostream>
#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 <llvm/Support/DynamicLibrary.h>
#include <boost/format.hpp>
#include <boost/algorithm/string/join.hpp>
#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<clang::TypedefDecl>("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<clang::FunctionDecl>("function")) {
typeResult = decl->getType();
}
}
};
void
ExternData::addLibrary(Atom<Identifier_t>&& name, Atom<String_t>&& 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<string>);
for(size_t i=0, size=e.operands.size(); i<size; ++i)
{
std::string library = e.bindings.at(i);
assert(__dictLibraries.count(library));
std::string package = __dictLibraries.at(library);
Expression listHeaders = e.operands.at(i);
assert(listHeaders.op == Operator::LIST);
std::vector<std::string> 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<ExternEntry>& data){
entries.insert(entries.end(), data.begin(), data.end());
}
ExternLayer::ExternLayer(LLVMLayer *llvm)
: __llvm(llvm)
{}
std::vector<string>
ExternLayer::fetchPackageFlags(const ExternEntry& entry){
std::vector<string> 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;
//cut unwanted symbols at the end
char symbLast = linebuf[linelen-1 ];
if (symbLast == ' ' || symbLast == '\n') linebuf[linelen-1] = 0;
//print header for debug purposes
llvm::outs() << '<' << linebuf << "> ";
args.push_back(linebuf);
free(linebuf);
linebuf = 0;
}
pclose(flags);
return (args);
}
std::vector<string>
ExternLayer::fetchPackageLibs(const ExternEntry& entry){
std::vector<string> 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;
//cut unwanted symbols at the end
char symbLast = linebuf[linelen-1 ];
if (symbLast == ' ' || symbLast == '\n') linebuf[linelen-1] = 0;
//cut unwanted symbols at the beginning
if (linelen>1 && linebuf[0] == '-' && linebuf[1] == 'l'){
libs.push_back(linebuf + 2);
} else {
libs.push_back(linebuf);
}
//print lib name for debug purposes
llvm::outs() << '<' << linebuf << "> ";
free(linebuf);
linebuf = 0;
}
pclose(flags);
return (libs);
}
void
ExternLayer::loadLibraries(vector<string>&& 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 "<<lib<<". " <<msgErr<<"\n";
}
}
}
void
ExternLayer::init(const AST* root) {
addExternalData(root->__externdata);
// TODO -EXTERN01.DIP, use default include path from 'clang -xc++ -E'
list<string> code;
std::vector<string> 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<string> libs;
boost::format formatInclude("#include \"%1%\"");
for(const ExternEntry& entry: entries)
{
llvm::outs()<<"[ExternC] Processing package: "<< entry.package << "\n";
llvm::outs()<<"[ExternC] args: ";
vector<string>&& 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);
__llvm->module->setDataLayout(ast->getASTContext().getTargetInfo().getDataLayoutString());
std::unique_ptr<clang::HeaderSearchOptions> __hso(new HeaderSearchOptions());
std::unique_ptr<clang::PreprocessorOptions> __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<std::string>
ExternLayer::getStructFields(const clang::QualType& ty)
{
clang::QualType t = ty;
if (isPointer(ty)){
const clang::PointerType* tPtr = ty->getAs<clang::PointerType>();
t = tPtr->getPointeeType();
}
assert(t.getTypePtr()->isRecordType());
const RecordType *record = t->getAsStructureType();
assert(record);
std::vector<std::string> 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: "<<name << endl;
assert(false && "Unknown external function");
}
const QualType& tyFuncQual = callback.typeResult;
llvm::Type *tyRaw = __cgm->getTypes().ConvertType(tyFuncQual);
llvm::FunctionType* tyRawFunc = llvm::dyn_cast<llvm::FunctionType>(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 a126843..183b233 100644
--- a/cpp/src/ExternLayer.h
+++ b/cpp/src/ExternLayer.h
@@ -1,54 +1,60 @@
-//
-// Created by pgess on 4/21/15.
-//
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * ExternLayer.h
+ *
+ * Created on: 4/21/15
+ * Author: pgess <v.melnychenko@xreate.org>
+ */
#ifndef XREATE_EXTERNLAYER_H
#define XREATE_EXTERNLAYER_H
#include "llvmlayer.h"
#include <vector>
#include <string>
#include <map>
#include "ast.h"
#include "clang/AST/ASTContext.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "clang/CodeGen/CodeGenABITypes.h"
namespace xreate {
struct ExternData {
void addLibrary(Atom<Identifier_t>&& name, Atom<String_t>&& package);
void addIncludeDecl(Expression&& e);
std::vector<ExternEntry> entries;
std::map<std::string, std::string> __dictLibraries;
};
class ExternLayer {
public:
ExternLayer(LLVMLayer* llvm);
llvm::Function* lookupFunction(const std::string& name);
clang::QualType lookupType(const std::string& id);
std::vector<std::string> 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<std::string> fetchPackageFlags(const ExternEntry& entry);
static std::vector<std::string> fetchPackageLibs(const ExternEntry& entry);
private:
std::unique_ptr<clang::ASTUnit> ast;
std::unique_ptr<clang::CodeGen::CodeGenModule> __cgm;
std::unique_ptr<clang::CodeGenOptions> __cgo;
LLVMLayer* __llvm;
std::vector<ExternEntry> entries;
std::map<std::string, llvm::Function*> __functions;
void addExternalData(const std::vector<ExternEntry>& data);
void loadLibraries(std::vector<std::string>&& libs);
};
}
#endif //XREATE_EXTERNLAYER_H
diff --git a/cpp/src/analysis/DominatorsTreeAnalysisProvider.cpp b/cpp/src/analysis/DominatorsTreeAnalysisProvider.cpp
index 99a1a64..463c1f7 100644
--- a/cpp/src/analysis/DominatorsTreeAnalysisProvider.cpp
+++ b/cpp/src/analysis/DominatorsTreeAnalysisProvider.cpp
@@ -1,239 +1,236 @@
-/*
- * 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.
- */
-
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* File: DominatorsTreeAnalysisProvider.cpp
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*
* 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 <list>
#include <iostream>
#include <boost/format.hpp>
using namespace std;
using namespace xreate;
using namespace boost;
using namespace boost::bimaps;
namespace xreate{ namespace dominators {
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<ScopePacked>, multiset_of<ScopePacked>> CHILD_RELATIONS;
CHILD_RELATIONS edges;
std::vector<Node> 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());
cfa::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; i<tree->size; ++i){
tree->nodes[i]= Node{(unsigned int) i, tree};
}
return tree;
}
std::list<unsigned int> getRootFunctions() const{
size_t idMax = size;
size_t id =0;
std::list<unsigned int> 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);
}
};
}} //end of namespace xreate::dominators
namespace llvm {
using namespace xreate::dominators;
template <> struct GraphTraits<Node*> {
typedef Node* nodes_iterator;
typedef Node NodeType;
typedef std::function<Node*(ControlFlowTree::CHILD_RELATIONS::left_value_type)> Transformer;
typedef typename boost::transform_iterator<Transformer, ControlFlowTree::CHILD_RELATIONS::left_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<Inverse<Node*>> {
typedef Node* nodes_iterator;
typedef Node NodeType;
typedef std::function<Node*(ControlFlowTree::CHILD_RELATIONS::right_value_type)> Transformer;
typedef typename boost::transform_iterator<Transformer, ControlFlowTree::CHILD_RELATIONS::right_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<ControlFlowTree*>: public GraphTraits<Node*> {
static NodeType*
getEntryNode(ControlFlowTree* F) {
if (F->entry) return F->entry;
list<unsigned int>&& 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; }
};
}
namespace xreate{ namespace dominators {
class DominatorTree: public llvm::DominatorTreeBase<Node> {
public:
DominatorsTreeAnalysisProvider::Dominators dominators;
DominatorTree(bool isPostDom): llvm::DominatorTreeBase<Node>(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<ControlFlowTree> 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() {}
}} //end of namespace xreate::dominators
//void
//CodeScopesTree::print(){
// typedef llvm::GraphTraits<Node*> Traits;
// for (size_t i=0; i<size; ++i){
//
// for (auto j = Traits::child_begin(&nodes[i]); j!= Traits::child_end(&nodes[i]); ++j){
// cout << i << "->" << (*j)->scope << endl;
// }
// }
-//}
\ No newline at end of file
+//}
diff --git a/cpp/src/analysis/DominatorsTreeAnalysisProvider.h b/cpp/src/analysis/DominatorsTreeAnalysisProvider.h
index c9a274f..3a087a7 100644
--- a/cpp/src/analysis/DominatorsTreeAnalysisProvider.h
+++ b/cpp/src/analysis/DominatorsTreeAnalysisProvider.h
@@ -1,44 +1,41 @@
-/*
- * 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.
- */
-
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* File: DominatorsTreeAnalysisProvider.h
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*
* Created on May 13, 2016, 11:39 AM
*/
#ifndef DOMINATORSTREEANALYSISPROVIDER_H
#define DOMINATORSTREEANALYSISPROVIDER_H
#include "clasplayer.h"
#include <boost/smart_ptr/scoped_ptr.hpp>
namespace xreate{namespace dominators{
class DominatorTree;
class DominatorsTreeAnalysisProvider: public IAnalysisData {
public:
typedef std::pair<ScopePacked, ScopePacked> DominatedRange;
typedef std::map<ScopePacked, DominatedRange> 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<DominatorTree> treeForwardDominators;
boost::scoped_ptr<DominatorTree> treePostDominators;
};
}} //end of namespace xreate::dominators
#endif /* DOMINATORSTREEANALYSISPROVIDER_H */
diff --git a/cpp/src/analysis/aux.cpp b/cpp/src/analysis/aux.cpp
index 505231f..0b9dadb 100644
--- a/cpp/src/analysis/aux.cpp
+++ b/cpp/src/analysis/aux.cpp
@@ -1,141 +1,150 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * aux.cpp
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ */
+
#include "aux.h"
#include <boost/format.hpp>
namespace xreate { namespace analysis {
using namespace std;
list<string>
multiplyLists(list<list<string>> &&lists) {
typedef list<string> 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<std::string>
compile(const Expression &e){
list<string> result;
switch (e.op) {
case Operator::CALL: {
assert(e.__state == Expression::COMPOUND);
if(!e.operands.size()){
result.push_back(e.getValueString());
break;
}
std::list<list<string>> operands;
std::transform(e.operands.begin(), e.operands.end(), std::inserter(operands, operands.begin()),
[](const Expression &e) {
return compile(e);
});
list<string> &&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<string> &&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<std::string>
compileNeg(const Expression &e){
list<string> result;
switch (e.op) {
case Operator::IMPL: {
assert(e.__state == Expression::COMPOUND);
assert(e.operands.size() == 2);
list<string> operands1 = compile(e.operands.at(0));
list<string> 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<string> &&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%, %3%)");
boost::format formatSymbAnonymous("anonym(%1%, %2%)");
if (!s.categoryTransient){
return formatSymbNamed % s.identifier % s.version % 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
index c8bad41..e470d5d 100644
--- a/cpp/src/analysis/aux.h
+++ b/cpp/src/analysis/aux.h
@@ -1,25 +1,28 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* File: aux.h
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*
* Created on June 26, 2016, 6:49 PM
*/
#ifndef AUX_H
#define AUX_H
#include "ast.h"
#include "clasplayer.h"
#include <list>
#include <boost/format.hpp>
namespace xreate { namespace analysis {
std::list<std::string> compile(const Expression &e);
std::list<std::string> compileNeg(const Expression &e);
std::list<std::string> multiplyLists(std::list<std::list<std::string>> &&lists);
boost::format formatSymbol(const SymbolPacked& s);
}}
#endif /* AUX_H */
diff --git a/cpp/src/analysis/cfagraph.cpp b/cpp/src/analysis/cfagraph.cpp
index 5a2d7e6..5f896ab 100644
--- a/cpp/src/analysis/cfagraph.cpp
+++ b/cpp/src/analysis/cfagraph.cpp
@@ -1,166 +1,169 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* File: CFAGraph.cpp
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*
* Created on June 27, 2016, 2:09 PM
*/
#include "analysis/cfagraph.h"
#include "analysis/aux.h"
using namespace xreate::cfa;
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<string> 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<string> 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<ManagedFnPtr>& functions = __clasp->ast->getAllFunctions();
for (auto f: functions){
if (f->guardContext.isValid()){
list<string> 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<std::string, Expression>& tags) {
unsigned int fid = registerNodeFunction(function);
for (auto& tag: tags){
__functionTags.emplace(fid, tag.second);
}
}
void
CFAGraph::addScopeAnnotations(const ScopePacked& scope, const std::vector<Expression>& tags){
for (Expression tag: tags){
__scopeTags.emplace(scope, tag);
}
}
void
CFAGraph::addContextRules(const ScopePacked& scope, const std::vector<Expression>& 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
index 7372446..9a5bfd8 100644
--- a/cpp/src/analysis/cfagraph.h
+++ b/cpp/src/analysis/cfagraph.h
@@ -1,56 +1,59 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* File: CFAGraph.h
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*
* Created on June 27, 2016, 2:09 PM
*/
#ifndef CFAGRAPH_H
#define CFAGRAPH_H
#include "clasplayer.h"
namespace xreate {namespace cfa {
class CFAGraph: public IAnalysisData {
public:
typedef boost::bimap<ScopePacked, boost::bimaps::multiset_of<unsigned int>> PARENT_FUNCTION_RELATIONS;
PARENT_FUNCTION_RELATIONS __parentFunctionRelations;
std::map<ScopePacked, ScopePacked> __parentScopeRelations;
typedef boost::bimap<
boost::bimaps::multiset_of<ScopePacked>,
boost::bimaps::multiset_of<unsigned int>,
boost::bimaps::set_of_relation<>
> CALL_RELATIONS;
CALL_RELATIONS __callRelations;
boost::bimap<unsigned int, std::string > __nodesFunction;
std::multimap<unsigned int, Expression> __functionTags;
std::multimap<ScopePacked, Expression> __scopeTags;
std::multimap<ScopePacked, ContextRule> __contextRules;
void print(std::ostringstream& output) const;
CFAGraph(ClaspLayer* engine): __clasp(engine){}
void addFunctionAnnotations(const std::string& function, const std::map<std::string, Expression>& tags);
void addScopeAnnotations(const ScopePacked& scope, const std::vector<Expression>&tags);
void addContextRules(const ScopePacked& scope, const std::vector<Expression>&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);
};
}} //end of namespace xreate::cfa
#endif /* CFAGRAPH_H */
diff --git a/cpp/src/analysis/dfagraph.cpp b/cpp/src/analysis/dfagraph.cpp
index 46c448c..8863259 100644
--- a/cpp/src/analysis/dfagraph.cpp
+++ b/cpp/src/analysis/dfagraph.cpp
@@ -1,245 +1,254 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * File: DFAGraph.h
+ * Author: pgess <v.melnychenko@xreate.org>
+ *
+ */
+
#include "analysis/dfagraph.h"
#include "analysis/aux.h"
#include <list>
using namespace std;
namespace xreate { namespace dfa {
void
DFAGraph::print(std::ostringstream& output) const {
std::set<SymbolPacked> symbols;
output << endl << "%\t\tStatic analysis: DFA" << endl;
std::vector<std::pair<SymbolPacked, SymbolPacked>>::const_iterator i1;
std::vector<DFGConnection>::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
% analysis::formatSymbol(i1->first)
% analysis::formatSymbol(i1->second)
% edgeName
<< " %" << this->__clasp->getHintForPackedSymbol(i1->first) << " - " << this->__clasp->getHintForPackedSymbol(i1->second)
<< endl;
symbols.insert(i1->first);
symbols.insert(i1->second);
}
boost::format formatDfaDependency("dfa_dependency(%1%, %2%).");
for (auto i = this->__dependencies.begin(); i != this->__dependencies.end(); ++i) {
output << formatDfaDependency
% analysis::formatSymbol(i->first)
% analysis::formatSymbol(i->second)
<< " %"
<< this->__clasp->getHintForPackedSymbol(i->first) << " - "
<< this->__clasp->getHintForPackedSymbol(i->second)
<< endl;
}
boost::format formatBind("bind(%1%, %2%).");
for (const pair<SymbolPacked, Expression>& tag : this->__tags) {
for (string variant : xreate::analysis::compile(tag.second)) {
output << formatBind
% analysis::formatSymbol(tag.first)
% (variant)
<< "%" << this->__clasp->getHintForPackedSymbol(tag.first)
<< endl;
}
symbols.insert(tag.first);
}
for (const SymbolPacked& s : symbols) {
output << "v(" << analysis::formatSymbol(s) << ")."
<< " %" << this->__clasp->getHintForPackedSymbol(s)
<< endl;
}
}
class VisitorAddTag : public boost::static_visitor<> {
public:
void operator()(const SymbolPacked& symbol) {
__graph->__tags.emplace(symbol, move(__tag));
}
void operator()(SymbolAnonymous& 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 SymbolAnonymous& 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<list<SymbolPacked>>
{
public:
list<SymbolPacked>
operator()(const SymbolPacked & nodeFrom) {
return
{
nodeFrom
};
}
list<SymbolPacked>
operator()(const SymbolAnonymous & nodeFrom) {
return nodeFrom.dependencies;
}
list<SymbolPacked>
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()(SymbolAnonymous& 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<SymbolPacked, EdgeId>::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(ScopedSymbol{__countAnonymousSymbols++, 0}, scope, true);
}
-}} //end of namespace xreate::dfa
\ No newline at end of file
+}} //end of namespace xreate::dfa
diff --git a/cpp/src/analysis/dfagraph.h b/cpp/src/analysis/dfagraph.h
index 5d6e513..9ba5af0 100644
--- a/cpp/src/analysis/dfagraph.h
+++ b/cpp/src/analysis/dfagraph.h
@@ -1,60 +1,63 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* File: dfa.h
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*
* Created on June 27, 2016, 1:50 PM
*/
#ifndef DFA_H
#define DFA_H
#include "clasplayer.h"
namespace xreate {namespace dfa {
struct SymbolAnonymous {
SymbolAnonymous(unsigned int symbolId): id(symbolId){}
unsigned int id;
std::list<Expression> tags;
ScopePacked scope;
std::list<SymbolPacked> dependencies;
};
struct SymbolInvalid { };
typedef boost::variant<SymbolInvalid, SymbolAnonymous, SymbolPacked> 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<std::pair<SymbolPacked, SymbolPacked>> __edges;
std::multimap<SymbolPacked, EdgeId> __outEdges;
std::vector<DFGConnection> __data;
std::multimap<SymbolPacked, Expression> __tags;
std::multimap<SymbolPacked, SymbolPacked> __dependencies;
unsigned int __countAnonymousSymbols=0;
ClaspLayer* __clasp;
};
}} // end of namespace xreate::dfa
#endif /* DFA_H */
diff --git a/cpp/src/analysis/typeinference.cpp b/cpp/src/analysis/typeinference.cpp
index 50d0efb..26e098a 100644
--- a/cpp/src/analysis/typeinference.cpp
+++ b/cpp/src/analysis/typeinference.cpp
@@ -1,60 +1,63 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* typeinference.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on April 16, 2017, 10:13 AM
*/
#include "typeinference.h"
#include "llvmlayer.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/DerivedTypes.h"
namespace xreate {namespace typeinference {
//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)
llvm::Value*
doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, llvm::IRBuilder<>& builder){
if (tyTarget->isIntegerTy() && source->getType()->isIntegerTy())
{
llvm::IntegerType* tyTargetInt = llvm::dyn_cast<llvm::IntegerType>(tyTarget);
llvm::IntegerType* tySourceInt = llvm::dyn_cast<llvm::IntegerType>(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);
}
}
if (source->getType()->isIntegerTy() && tyTarget->isFloatingPointTy()){
return builder.CreateCast(llvm::Instruction::SIToFP, source, tyTarget);
}
return source;
}
ExpandedType
getType(const Expression& expression, const AST& ast){
if (expression.type.isValid()){
return ast.expandType(expression.type);
}
if (expression.__state == Expression::IDENT){
Symbol s = Attachments::get<Symbol>(expression);
return getType(CodeScope::getDeclaration(s), ast);
}
assert(false && "Type can't be determined for an expression");
}
-} } //end of namespace xreate::typeinference
\ No newline at end of file
+} } //end of namespace xreate::typeinference
diff --git a/cpp/src/analysis/typeinference.h b/cpp/src/analysis/typeinference.h
index a35e33e..1b8cece 100644
--- a/cpp/src/analysis/typeinference.h
+++ b/cpp/src/analysis/typeinference.h
@@ -1,27 +1,30 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* File: typeinference.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on April 16, 2017, 10:17 AM
*/
#ifndef TYPEINFERENCE_H
#define TYPEINFERENCE_H
#include "ast.h"
#include "llvm/IR/IRBuilder.h"
namespace llvm {
class Value;
class Type;
};
namespace xreate { namespace typeinference {
llvm::Value* doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, llvm::IRBuilder<>& builder);
ExpandedType getType(const Expression& expression, const AST& ast);
} }//namespace xreate::typeinference
#endif /* TYPEINFERENCE_H */
diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp
index 06cdd55..dd8a17a 100644
--- a/cpp/src/ast.cpp
+++ b/cpp/src/ast.cpp
@@ -1,951 +1,961 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ * File: ast.cpp
+ */
+
+
+
#include "ast.h"
#include "ExternLayer.h"
#include "analysis/typeinference.h"
#include <stdexcept>
#include <iostream>
//TODO BDecl. forbid multiple body declaration (ExprTyped)
namespace std {
std::size_t
hash<xreate::ScopedSymbol>::operator()(xreate::ScopedSymbol const& s) const {
return s.id ^ (s.version << 2);
}
bool
equal_to<xreate::ScopedSymbol>::operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const {
return __x.id == __y.id && __x.version == __y.version;
}
size_t
hash<xreate::Symbol>::operator()(xreate::Symbol const& s) const {
return hash<xreate::ScopedSymbol>()(s.identifier) ^ ((long int) s.scope << 1);
}
bool
equal_to<xreate::Symbol>::operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const {
return __x == __y;
};
}
using namespace std;
namespace xreate {
Atom<Identifier_t>::Atom(const std::wstring& value) {
__value = wstring_to_utf8(value);
}
Atom<Identifier_t>::Atom(std::string && name) : __value(name) {
}
const std::string&
Atom<Identifier_t>::get() const {
return __value;
}
Atom<Number_t>::Atom(wchar_t* value) {
//DEBT reconsider number literal recognition
__value = wcstol(value, 0, 10);
}
Atom<Number_t>::Atom(int value)
: __value(value) {
}
double
Atom<Number_t>::get()const {
return __value;
}
Atom<String_t>::Atom(const std::wstring& value) {
assert(value.size() >= 2);
__value = wstring_to_utf8(value.substr(1, value.size() - 2));
}
const std::string&
Atom<String_t>::get() const {
return __value;
}
class ExpressionHints {
public:
static bool
isStringValueValid(const Expression& e) {
switch (e.__state) {
case Expression::INVALID:
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:
return true;
default: return false;
}
}
}
return false;
}
static bool
isDoubleValueValid(const Expression& e) {
switch (e.__state) {
case Expression::NUMBER:
return true;
case Expression::INVALID:
assert(false);
case Expression::IDENT:
case Expression::STRING:
case Expression::BINDING:
return false;
case Expression::COMPOUND: {
switch (e.op) {
case Operator::VARIANT:
return true;
default: return false;
}
}
}
return false;
}
};
class TypesResolver {
private:
const AST* ast;
std::map<std::string, TypeAnnotation> scope;
std::map<TypeAnnotation, int> signatures;
ExpandedType expandType(const TypeAnnotation &t, const std::vector<TypeAnnotation> &args = std::vector<TypeAnnotation>()) {
return TypesResolver(ast, scope, signatures)(t, args);
}
std::vector<TypeAnnotation>
expandOperands(const std::vector<TypeAnnotation>& operands) {
std::vector<TypeAnnotation> 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<std::string, TypeAnnotation>& scopeOuter = std::map<std::string, TypeAnnotation>(),
std::map<TypeAnnotation, int> signaturesOuter = std::map<TypeAnnotation, int>())
: ast(root), scope(scopeOuter), signatures(signaturesOuter) {
}
ExpandedType
operator()(const TypeAnnotation &t, const std::vector<TypeAnnotation> &args = std::vector<TypeAnnotation>()) {
//assert(args.size() == t.bindings.size()); // invalid number of arguments
for (size_t i = 0; i < args.size(); ++i) {
scope[t.bindings.at(i)] = args.at(i);
}
switch (t.__operator) {
case TypeOperator::ARRAY:
{
assert(t.__operands.size() == 1);
Expanded<TypeAnnotation> elTy = expandType(t.__operands.at(0));
return ExpandedType(TypeAnnotation(tag_array, elTy, 0));
}
case TypeOperator::STRUCT:
{
assert(t.__operands.size());
std::vector<TypeAnnotation>&& packOperands = expandOperands(t.__operands);
auto typNew = TypeAnnotation(TypeOperator::STRUCT, move(packOperands));
typNew.fields = t.fields;
return ExpandedType(move(typNew));
};
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<TypeAnnotation>&& 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::VARIANT:
{
return ExpandedType(TypeAnnotation(t));
}
case TypeOperator::NONE:
{
return ExpandedType(TypeAnnotation(t));
}
default:
assert(false);
}
assert(false);
return ExpandedType(TypeAnnotation());
}
};
TypeAnnotation::TypeAnnotation()
: __operator(TypeOperator::NONE), __value(TypePrimitive::Invalid) {
}
TypeAnnotation::TypeAnnotation(TypePrimitive typ)
: __value(typ) {
}
TypeAnnotation::TypeAnnotation(TypeOperator op, std::initializer_list<TypeAnnotation> operands)
: __operator(op), __operands(operands) {
}
TypeAnnotation::TypeAnnotation(TypeOperator op, std::vector<TypeAnnotation>&& operands)
: __operator(op), __operands(operands) {
}
TypeAnnotation::TypeAnnotation(llvm_array_tag, TypeAnnotation typ, int size)
: TypeAnnotation(TypeOperator::ARRAY,{typ}) {
__size = size;
}
bool
TypeAnnotation::isValid() const {
return !(__value == TypePrimitive::Invalid && __operator == TypeOperator::NONE);
}
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<TypeAnnotation>)
{}
*/
void
TypeAnnotation::addBindings(std::vector<Atom<Identifier_t>>&& params) {
bindings.reserve(bindings.size() + params.size());
std::transform(params.begin(), params.end(), std::inserter(bindings, bindings.end()),
[](const Atom<Identifier_t>& ident) {
return ident.get(); });
}
void
TypeAnnotation::addFields(std::vector<Atom<Identifier_t>>&& listFields) {
fields.reserve(fields.size() + listFields.size());
std::transform(listFields.begin(), listFields.end(), std::inserter(fields, fields.end()),
[](const Atom<Identifier_t>& ident) {
return ident.get(); });
}
unsigned int Expression::nextVacantId = 0;
Expression::Expression(const Atom<Number_t>& number)
: Expression() {
__state = NUMBER;
op = Operator::NONE;
__valueD = number.get();
}
Expression::Expression(const Atom<String_t>& a)
: Expression() {
__state = STRING;
op = Operator::NONE;
__valueS = a.get();
}
Expression::Expression(const Atom<Identifier_t> &ident)
: Expression() {
__state = IDENT;
op = Operator::NONE;
__valueS = ident.get();
}
Expression::Expression(const Operator &oprt, std::initializer_list<Expression> params)
: Expression() {
__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::addTags(const std::list<Expression> tags) const {
std::transform(tags.begin(), tags.end(), std::inserter(this->tags, this->tags.end()),
[](const Expression & tag) {
return make_pair(tag.getValueString(), tag);
});
}
void
Expression::addBindings(std::initializer_list<Atom<Identifier_t>> params) {
addBindings(params.begin(), params.end());
}
void
Expression::bindType(TypeAnnotation t) {
type = move(t);
}
void
Expression::addBlock(ManagedScpPtr scope) {
blocks.push_back(scope.operator->());
}
const std::vector<Expression>&
Expression::getOperands() const {
return operands;
}
double
Expression::getValueDouble() const {
return __valueD;
}
const std::string&
Expression::getValueString() const {
return __valueS;
}
void
Expression::setValue(const Atom<Identifier_t>&& 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), id(nextVacantId++) {
}
namespace details { namespace incomplete {
AST::AST() {
Attachments::init<versions::VariableVersion>();
Attachments::init<Symbol>();
}
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<Identifier_t> 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(), 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<Function>
AST::findFunction(const std::string& name) {
int count = __indexFunctions.count(name);
if (!count) {
return ManagedFnPtr::Invalid();
}
assert(count == 1);
auto range = __indexFunctions.equal_range(name);
return ManagedPtr<Function>(range.first->second, &this->__functions);
}
std::list<ManagedFnPtr>
AST::getAllFunctions() const {
const size_t size = __functions.size();
std::list<ManagedFnPtr> result;
for (size_t i = 0; i < size; ++i) {
result.push_back(ManagedFnPtr(i, &this->__functions));
}
return result;
}
//TASK select default specializations
std::list<ManagedFnPtr>
AST::getFunctionVariants(const std::string& name) const {
auto functions = __indexFunctions.equal_range(name);
std::list<ManagedFnPtr> result;
std::transform(functions.first, functions.second, inserter(result, result.end()),
[this](auto f) {
return ManagedFnPtr(f.second, &this->__functions);
});
return result;
}
template<>
ManagedPtr<Function>
AST::begin<Function>() {
return ManagedPtr<Function>(0, &this->__functions);
}
template<>
ManagedPtr<CodeScope>
AST::begin<CodeScope>() {
return ManagedPtr<CodeScope>(0, &this->__scopes);
}
template<>
ManagedPtr<MetaRuleAbstract>
AST::begin<MetaRuleAbstract>() {
return ManagedPtr<MetaRuleAbstract>(0, &this->__rules);
}
void
AST::recognizeVariantConstructor(Expression& function) {
assert(function.op == Operator::CALL);
std::string variant = function.getValueString();
if (!__dictVariants.count(variant)) {
return;
}
auto record = __dictVariants.at(variant);
const TypeAnnotation& typ = record.first;
function.op = Operator::VARIANT;
function.setValueDouble(record.second);
function.type = typ;
}
Atom<Number_t>
AST::recognizeVariantConstructor(Atom<Identifier_t> ident) {
std::string variant = ident.get();
assert(__dictVariants.count(variant) && "Can't recognize variant constructor");
auto record = __dictVariants.at(variant);
return Atom<Number_t>(record.second);
}
void
AST::postponeIdentifier(CodeScope* scope, const Expression& id) {
bucketUnrecognizedIdentifiers.emplace(scope, id);
}
void
AST::recognizePostponedIdentifiers() {
for (const auto& identifier : bucketUnrecognizedIdentifiers) {
if (!identifier.first->recognizeIdentifier(identifier.second)) {
//exception: Ident not found
std::cout << "Unknown symbol: " << identifier.second.getValueString() << std::endl;
assert(false && "Symbol not found");
}
}
}
xreate::AST*
AST::finalize() {
//all finalization steps:
recognizePostponedIdentifiers();
return reinterpret_cast<xreate::AST*> (this);
}
} } //namespace details::incomplete
Expanded<TypeAnnotation>
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));
}
Expanded<TypeAnnotation>
AST::expandType(const TypeAnnotation &t) const {
return TypesResolver(this)(t);
}
ExpandedType
AST::getType(const Expression& expression) {
return typeinference::getType(expression, *this);
}
Function::Function(const Atom<Identifier_t>& name)
: __entry(new CodeScope(0)) {
__name = name.get();
}
void
Function::addTag(Expression&& tag, const TagModifier mod) {
string name = tag.getValueString();
__tags.emplace(move(name), move(tag));
}
const std::map<std::string, Expression>&
Function::getTags() const {
return __tags;
}
CodeScope*
Function::getEntryScope() const {
return __entry;
}
void
Function::addBinding(Atom <Identifier_t>&& name, Expression&& argument) {
__entry->addBinding(move(name), move(argument));
}
const std::string&
Function::getName() const {
return __name;
}
ScopedSymbol
CodeScope::registerIdentifier(const Expression& identifier) {
versions::VariableVersion version = Attachments::get<versions::VariableVersion>(identifier, versions::VERSION_NONE);
auto result = __identifiers.emplace(identifier.getValueString(), __vCounter);
if (result.second) {
++__vCounter;
return { __vCounter - 1, version };
}
return { result.first->second, version };
}
bool
CodeScope::recognizeIdentifier(const Expression& identifier) const {
versions::VariableVersion version = Attachments::get<versions::VariableVersion>(identifier, versions::VERSION_NONE);
const std::string& name = identifier.getValueString();
//search identifier in the current block
if (__identifiers.count(name)) {
VNameId id = __identifiers.at(name);
Symbol s;
s.identifier = ScopedSymbol{id, version};
s.scope = const_cast<CodeScope*> (this);
Attachments::put<Symbol>(identifier, s);
return true;
}
//search in the parent scope
if (__parent) {
return __parent->recognizeIdentifier(identifier);
}
return false;
}
ScopedSymbol
CodeScope::getSymbol(const std::string& alias) {
assert(__identifiers.count(alias));
VNameId id = __identifiers.at(alias);
return {id, versions::VERSION_NONE };
}
void
CodeScope::addBinding(Expression&& var, Expression&& argument) {
argument.__state = Expression::BINDING;
__bindings.push_back(var.getValueString());
ScopedSymbol binding = registerIdentifier(var);
__declarations[binding] = move(argument);
}
void
CodeScope::addDeclaration(Expression&& var, Expression&& body) {
ScopedSymbol s = registerIdentifier(var);
__declarations[s] = move(body);
}
CodeScope::CodeScope(CodeScope* parent)
: __parent(parent) {
}
CodeScope::~CodeScope() {
}
void
CodeScope::setBody(const Expression &body) {
__declarations[ScopedSymbol::RetSymbol] = body;
}
Expression&
CodeScope::getBody() {
return __declarations[ScopedSymbol::RetSymbol];
}
const Expression&
CodeScope::getDeclaration(const Symbol& symbol) {
CodeScope* self = symbol.scope;
return self->getDeclaration(symbol.identifier);
}
const Expression&
CodeScope::getDeclaration(const ScopedSymbol& symbol) {
assert(__declarations.count(symbol) && "Symbol's declaration not found");
return __declarations.at(symbol);
}
void
RuleArguments::add(const Atom<Identifier_t> &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<String_t>&& 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 ScopedSymbol& s1, const ScopedSymbol& s2) {
return (s1.id < s2.id) || (s1.id == s2.id && s1.version < s2.version);
}
bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2) {
return (s1.id == s2.id) && (s1.version == s2.version);
}
bool operator<(const Symbol& s1, const Symbol& s2) {
return (s1.scope < s2.scope) || (s1.scope == s2.scope && s1.identifier < s2.identifier);
}
bool operator==(const Symbol& s1, const Symbol& s2) {
return (s1.scope == s2.scope) && (s1.identifier == s2.identifier);
}
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:
return a.getValueString() < b.getValueString();
case Expression::NUMBER:
return a.getValueDouble() < b.getValueDouble();
case Expression::COMPOUND:
{
assert(a.blocks.size() == 0);
assert(b.blocks.size() == 0);
if (a.op != b.op) {
return a.op < b.op;
}
bool flagAValid = ExpressionHints::isStringValueValid(a);
bool flagBValid = ExpressionHints::isStringValueValid(b);
if (flagAValid != flagBValid) {
return flagAValid < flagBValid;
}
if (flagAValid) {
if (a.getValueString() != b.getValueString()) {
return a.getValueString() < b.getValueString();
}
}
flagAValid = ExpressionHints::isDoubleValueValid(a);
flagBValid = ExpressionHints::isDoubleValueValid(b);
if (flagAValid != flagBValid) {
return flagAValid < flagBValid;
}
if (flagAValid) {
if (a.getValueDouble() != b.getValueDouble()) {
return a.getValueDouble() < b.getValueDouble();
}
}
if (a.operands.size() != b.operands.size()) {
return (a.operands.size() < b.operands.size());
}
for (size_t i = 0; i < a.operands.size(); ++i) {
bool result = a.operands[i] < b.operands[i];
if (result) return true;
}
return false;
}
case Expression::BINDING:
case Expression::INVALID:
assert(false);
}
return false;
}
bool
Expression::operator==(const Expression& other) const {
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->op != other.op) {
return false;
}
if (this->operands.size() != other.operands.size()) {
return false;
}
for (size_t i = 0; i<this->operands.size(); ++i) {
if (!(this->operands[i] == other.operands[i])) return false;
}
assert(!this->blocks.size());
assert(!other.blocks.size());
return true;
}
const ScopedSymbol
ScopedSymbol::RetSymbol = ScopedSymbol{0, versions::VERSION_NONE};
} //end of namespace xreate
diff --git a/cpp/src/ast.h b/cpp/src/ast.h
index 0a9e308..1216df3 100644
--- a/cpp/src/ast.h
+++ b/cpp/src/ast.h
@@ -1,576 +1,584 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ * File: ast.h
+ */
+
#ifndef AST_H
#define AST_H
#include "attachments.h"
#include <vector>
#include <stdlib.h>
#include <string>
#include <list>
#include <unordered_map>
#include <unordered_set>
#include <climits>
#include "utils.h"
#include <algorithm>
namespace llvm {
class Value;
}
namespace xreate {
struct ScopedSymbol;
struct Symbol;
}
namespace std {
template<>
struct hash<xreate::ScopedSymbol> {
std::size_t operator()(xreate::ScopedSymbol const& s) const;
};
template<>
struct equal_to<xreate::ScopedSymbol> {
bool operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const;
};
template<>
struct hash<xreate::Symbol> {
size_t operator()(xreate::Symbol const& s) const;
};
template<>
struct equal_to<xreate::Symbol> {
bool operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const;
};
}
namespace xreate {
struct String_t {
};
struct Identifier_t {
};
struct Number_t {
};
struct Type_t {
};
template<typename A>
class Atom {
};
//DEBT hold for all atoms/identifiers Parser::Token data, like line:col position
template<> class
Atom<Identifier_t> {
public:
Atom(const std::wstring& value);
Atom(std::string && name);
const std::string& get() const;
private:
std::string __value;
};
template<>
class Atom<Number_t> {
public:
Atom(wchar_t* value);
Atom(int value);
double get()const;
private:
double __value;
};
template<>
class Atom<String_t> {
public:
Atom(const std::wstring& value);
const std::string& get() const;
private:
std::string __value;
};
enum class TypePrimitive {
Invalid, Bool, I8, I32, I64, Num, Int, Float, String
};
enum class TypeOperator {
NONE, CALL, CUSTOM, VARIANT, ARRAY, 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<Type_t>& typ);
TypeAnnotation(TypePrimitive typ);
TypeAnnotation(llvm_array_tag, TypeAnnotation typ, int size);
TypeAnnotation(TypeOperator op, std::initializer_list<TypeAnnotation> operands);
TypeAnnotation(TypeOperator op, std::vector<TypeAnnotation>&& operands);
void addBindings(std::vector<Atom<Identifier_t>>&& params);
void addFields(std::vector<Atom<Identifier_t>>&& listFields);
bool operator<(const TypeAnnotation& t) const;
// TypeAnnotation (struct_tag, std::initializer_list<TypePrimitive>);
bool isValid() const;
TypeOperator __operator = TypeOperator::NONE;
std::vector<TypeAnnotation> __operands;
TypePrimitive __value;
std::string __valueCustom;
int conjuctionId = -1; //conjunction point id (relevant for recursive types)
uint64_t __size = 0;
std::vector<std::string> fields;
std::vector<std::string> bindings;
private:
};
enum class Operator {
ADD, SUB, MUL, DIV,
EQU, NE, NEG, LSS,
LSE, GTR, GTE, LIST,
LIST_RANGE, LIST_NAMED,
CALL, CALL_INTRINSIC, NONE,
IMPL/* implication */, MAP,
FOLD, FOLD_INF, LOOP_CONTEXT,
INDEX, IF, SWITCH, SWITCH_ADHOC, SWITCH_VARIANT,
CASE, CASE_DEFAULT, LOGIC_AND,
ADHOC, CONTEXT_RULE, VARIANT
};
class Function;
class AST;
class CodeScope;
class MetaRuleAbstract;
template<class Target>
struct ManagedPtr {
static ManagedPtr<Target> Invalid() {
return ManagedPtr<Target>();
}
ManagedPtr() : __storage(0) {
}
ManagedPtr(unsigned int id, const std::vector<Target*>* storage)
: __id(id), __storage(storage) {
}
Target&
operator*() const {
assert(isValid() && "Invalid Ptr");
return *__storage->at(__id);
}
void operator=(const ManagedPtr<Target>& other) {
__id = other.__id;
__storage = other.__storage;
}
bool
operator==(const ManagedPtr<Target>& other) {
return isValid() && (__id == other.__id);
}
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();
}
ManagedPtr<Target>& operator++() {
++__id;
return *this;
}
inline unsigned int id() const {
return __id;
}
private:
unsigned int __id = 0;
const std::vector<Target*> * __storage = 0;
};
typedef ManagedPtr<Function> ManagedFnPtr;
typedef ManagedPtr<CodeScope> ManagedScpPtr;
typedef ManagedPtr<MetaRuleAbstract> 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<Expression> params);
Expression(const Atom<Identifier_t>& ident);
Expression(const Atom<Number_t>& number);
Expression(const Atom<String_t>& a);
Expression();
void setOp(Operator oprt);
void addArg(Expression&& arg);
void addBindings(std::initializer_list<Atom<Identifier_t>> params);
void bindType(TypeAnnotation t);
template<class InputIt>
void addBindings(InputIt paramsBegin, InputIt paramsEnd);
void addTags(const std::list<Expression> tags) const;
void addBlock(ManagedScpPtr scope);
const std::vector<Expression>& getOperands() const;
double getValueDouble() const;
void setValueDouble(double value);
const std::string& getValueString() const;
void setValue(const Atom<Identifier_t>&& v);
bool isValid() const;
bool isDefined() const;
bool operator==(const Expression& other) const;
enum {
INVALID, COMPOUND, IDENT, NUMBER, STRING, BINDING
} __state = INVALID;
Operator op;
unsigned int id;
std::vector<std::string> bindings;
std::map<std::string, size_t> __indexBindings;
std::vector<Expression> operands;
TypeAnnotation type;
mutable std::map<std::string, Expression> tags;
std::list<CodeScope*> blocks;
private:
std::string __valueS;
double __valueD;
static unsigned int nextVacantId;
};
bool operator<(const Expression&, const Expression&);
template<class InputIt>
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<Identifier_t> atom) {
std::string key = atom.get();
this->__indexBindings[key] = index++;
return key;
});
}
typedef std::list<Expression> ExpressionList;
enum class TagModifier {
NONE, ASSERT, REQUIRE
};
enum class DomainAnnotation {
FUNCTION, VARIABLE
};
class RuleArguments : public std::vector<std::pair<std::string, DomainAnnotation>>
{
public:
void add(const Atom<Identifier_t>& name, DomainAnnotation typ);
};
class RuleGuards : public std::vector<Expression> {
public:
void add(Expression&& e);
};
class ClaspLayer;
class LLVMLayer;
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<String_t>&& message);
virtual void compile(ClaspLayer& layer);
~RuleWarning();
private:
std::string __message;
Expression __condition;
};
typedef unsigned int VNameId;
namespace versions {
typedef int VariableVersion;
const VariableVersion VERSION_NONE = -2;
const VariableVersion VERSION_INIT = 0;
}
template<>
struct AttachmentsDict<versions::VariableVersion> {
typedef versions::VariableVersion Data;
static const unsigned int key = 6;
};
struct ScopedSymbol {
VNameId id;
versions::VariableVersion version;
static const ScopedSymbol RetSymbol;
};
struct Symbol {
ScopedSymbol identifier;
CodeScope * scope;
};
template<>
struct AttachmentsDict<Symbol> {
typedef Symbol Data;
static const unsigned int key = 7;
};
typedef std::pair<Expression, TagModifier> Tag;
bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2);
bool operator==(const ScopedSymbol& s1, const ScopedSymbol& 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;
public:
CodeScope(CodeScope* parent = 0);
void setBody(const Expression& body);
Expression& getBody();
void addDeclaration(Expression&& var, Expression&& body);
void addBinding(Expression&& var, Expression&& argument);
static const Expression& getDeclaration(const Symbol& symbol);
const Expression& getDeclaration(const ScopedSymbol& symbol);
~CodeScope();
std::vector<std::string> __bindings;
std::map<std::string, VNameId> __identifiers;
CodeScope* __parent;
//TODO move __definitions to SymbolsAttachments data
//NOTE: definition of return type has zero(0) variable index
std::unordered_map<ScopedSymbol, Expression> __declarations;
std::vector<Expression> tags;
std::vector<Expression> contextRules;
private:
VNameId __vCounter = 1;
ScopedSymbol registerIdentifier(const Expression& identifier);
public:
bool recognizeIdentifier(const Expression& identifier) const;
ScopedSymbol getSymbol(const std::string& alias);
};
class Function {
friend class Expression;
friend class CodeScope;
friend class AST;
public:
Function(const Atom<Identifier_t>& name);
void addBinding(Atom <Identifier_t>&& name, Expression&& argument);
void addTag(Expression&& tag, const TagModifier mod);
const std::string& getName() const;
const std::map<std::string, Expression>& getTags() const;
CodeScope* getEntryScope() const;
CodeScope* __entry;
std::string __name;
bool isPrefunction = false; //SECTIONTAG adhoc Function::isPrefunction flag
Expression guardContext;
private:
std::map<std::string, Expression> __tags;
};
class ExternData;
struct ExternEntry {
std::string package;
std::vector<std::string> headers;
};
typedef Expanded<TypeAnnotation> ExpandedType;
enum ASTInterface {
CFA, DFA, Extern, Adhoc
};
struct FunctionSpecialization {
std::string guard;
size_t id;
};
struct FunctionSpecializationQuery {
std::unordered_set<std::string> context;
};
template<>
struct AttachmentsId<Expression>{
static unsigned int getId(const Expression& expression){
return expression.id;
}
};
template<>
struct AttachmentsId<Symbol>{
static unsigned int getId(const Symbol& s){
return s.scope->__declarations.at(s.identifier).id;
}
};
template<>
struct AttachmentsId<ManagedFnPtr>{
static unsigned int getId(const ManagedFnPtr& f){
const Symbol symbolFunction{ScopedSymbol::RetSymbol, f->getEntryScope()};
return AttachmentsId<Symbol>::getId(symbolFunction);
}
};
namespace details { namespace incomplete {
class AST {
public:
AST();
//TASK extern and DFA interfaces move into addInterfaceData
/**
* DFA Interface
*/
void addDFAData(Expression&& data);
/**
* Extern Interface
*/
void addExternData(ExternData&& data);
void addInterfaceData(const ASTInterface& interface, Expression&& data);
void add(Function* f);
void add(MetaRuleAbstract* r);
ManagedScpPtr add(CodeScope* scope);
std::string getModuleName();
ManagedPtr<Function> findFunction(const std::string& name);
typedef std::multimap<std::string, unsigned int> FUNCTIONS_REGISTRY;
std::list<ManagedFnPtr> getAllFunctions() const;
std::list<ManagedFnPtr> getFunctionVariants(const std::string& name) const;
template<class Target>
ManagedPtr<Target> begin();
std::vector<ExternEntry> __externdata;
std::list<Expression> __dfadata; //TODO move to more appropriate place
std::list<std::string> __rawImports; //TODO move to more appropriate place
std::multimap<ASTInterface, Expression> __interfacesData; //TODO CFA data here.
private:
std::vector<MetaRuleAbstract*> __rules;
std::vector<Function*> __functions;
std::vector<CodeScope*> __scopes;
FUNCTIONS_REGISTRY __indexFunctions;
// ***** TYPES SECTION *****
public:
std::map<std::string, TypeAnnotation> __indexTypeAliases;
void add(TypeAnnotation t, Atom<Identifier_t> alias);
// ***** SYMBOL RECOGNITION *****
//TODO revisit enums/variants, move to codescope
void recognizeVariantConstructor(Expression& function);
Atom<Number_t> recognizeVariantConstructor(Atom<Identifier_t> ident);
private:
std::map<std::string, std::pair<TypeAnnotation, int>> __dictVariants;
public:
std::set<std::pair<CodeScope*, Expression>> bucketUnrecognizedIdentifiers;
public:
void postponeIdentifier(CodeScope* scope, const Expression& id);
void recognizePostponedIdentifiers();
xreate::AST* finalize();
};
template<>
ManagedPtr<Function>
AST::begin<Function>();
template<>
ManagedPtr<CodeScope>
AST::begin<CodeScope>();
template<>
ManagedPtr<MetaRuleAbstract>
AST::begin<MetaRuleAbstract>();
} } // namespace details::incomplete
class AST : public details::incomplete::AST {
public:
AST() : details::incomplete::AST() {}
ExpandedType expandType(const TypeAnnotation &t) const;
ExpandedType findType(const std::string& name);
ExpandedType getType(const Expression& expression);
};
}
#endif // AST_H
diff --git a/cpp/src/attachments.cpp b/cpp/src/attachments.cpp
index 61fcdcd..9340962 100644
--- a/cpp/src/attachments.cpp
+++ b/cpp/src/attachments.cpp
@@ -1,10 +1,15 @@
-//
-// Created by pgess on 3/15/15.
-//
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ * File: attachments.cpp
+ * Date: 3/15/15
+ */
#include "attachments.h"
using namespace xreate;
std::vector<void*>
-Attachments::__storage = std::vector<void*>();
\ No newline at end of file
+Attachments::__storage = std::vector<void*>();
diff --git a/cpp/src/attachments.h b/cpp/src/attachments.h
index 9d7463a..5812a6d 100644
--- a/cpp/src/attachments.h
+++ b/cpp/src/attachments.h
@@ -1,170 +1,175 @@
-//
-// Created by pgess on 3/15/15.
-//
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ * File: attachments.h
+ * Date: 3/15/15
+ */
#ifndef _XREATE_ATTACHMENTS_H_
#define _XREATE_ATTACHMENTS_H_
#include <unordered_map>
#include <vector>
#include <assert.h>
#include <type_traits>
namespace xreate
{
//Attachments dictionary
template<class Tag>
struct AttachmentsDict
{
// typedef void Data;
// static const unsigned int key (current unreserved - 9);
//reserved attachments:
// 1 containers::Implementation
// 3 interpretation::InterpretationData
// 5 interpretation::FunctionInterpretationData
// 6 VariableVersion
// 7 Symbol
// 8 versions::VersionImposedDependency
};
template<class Object>
struct AttachmentsId{
//static unsigned int getId(const Object& object);
};
template<class Data>
class IAttachmentsContainer{
protected:
virtual bool __exists(const unsigned int object)=0;
virtual Data& __get(const unsigned int object)=0;
virtual void __put(const unsigned int object, Data data)=0;
public:
template<class Id>
bool exists(const Id& object){
unsigned int id = AttachmentsId<Id>::getId(object);
return __exists(id);
}
template<class Id>
Data& get(const Id& object){
unsigned int id = AttachmentsId<Id>::getId(object);
return __get(id);
}
template<class Id>
Data get(const Id& object, const Data& dataDefault){
unsigned int id = AttachmentsId<Id>::getId(object);
if (! __exists(id)){
return dataDefault;
}
return __get(id);
}
template<class Id>
void put(const Id& object, Data data){
unsigned int id = AttachmentsId<Id>::getId(object);
__put(id, data);
}
virtual ~IAttachmentsContainer(){};
};
template<class Data>
class AttachmentsContainerDefault: public IAttachmentsContainer<Data>{
private:
std::unordered_map<unsigned int, Data> __data;
virtual bool __exists(const unsigned int id){
return __data.count(id);
}
virtual Data& __get(const unsigned int id){
return __data.at(id);
}
virtual void __put(const unsigned int id, Data data){
auto result = __data.emplace(id, data);
assert(result.second);
}
public:
std::unordered_map<unsigned int, Data>& getRawStorage() {
return __data;
}
};
class Attachments{
private:
static std::vector<void*> __storage;
template<class Tag>
using Data = typename AttachmentsDict<Tag>::Data;
public:
template<class Tag, class Id>
static bool exists(const Id& object) {
assert(AttachmentsDict<Tag>::key < __storage.size());
assert(__storage.at(AttachmentsDict<Tag>::key));
IAttachmentsContainer<Data<Tag>>* self = reinterpret_cast<IAttachmentsContainer<Data<Tag>>*>(__storage.at(AttachmentsDict<Tag>::key));
return self->exists<Id>(object);
}
template<class Tag, class Id>
static Data<Tag>& get(const Id& object){
assert(AttachmentsDict<Tag>::key < __storage.size());
assert(__storage.at(AttachmentsDict<Tag>::key));
IAttachmentsContainer<Data<Tag>>* self = reinterpret_cast<IAttachmentsContainer<Data<Tag>>*>(__storage.at(AttachmentsDict<Tag>::key));
return self->get<Id>(object);
}
template<class Tag, class Id>
static Data<Tag> get(const Id& object, const Data<Tag>& dataDefault){
assert(AttachmentsDict<Tag>::key < __storage.size());
assert(__storage.at(AttachmentsDict<Tag>::key));
IAttachmentsContainer<Data<Tag>>* self = reinterpret_cast<IAttachmentsContainer<Data<Tag>>*>(__storage.at(AttachmentsDict<Tag>::key));
return self->get<Id>(object, dataDefault);
}
template<class Tag, class Id>
static void put(const Id& object, Data<Tag> data){
assert(AttachmentsDict<Tag>::key < __storage.size());
assert(__storage.at(AttachmentsDict<Tag>::key));
IAttachmentsContainer<Data<Tag>>* self = reinterpret_cast<IAttachmentsContainer<Data<Tag>>*>(__storage.at(AttachmentsDict<Tag>::key));
self->put<Id>(object, data);
}
template<class Tag>
static void init(){
unsigned int keyStorage = AttachmentsDict<Tag>::key;
if (keyStorage+1 > __storage.size()){
__storage.resize(keyStorage + 1, nullptr);
}
__storage[keyStorage] = new AttachmentsContainerDefault<Data<Tag>>();
}
template<class Tag>
static void init(IAttachmentsContainer<Data<Tag>>* container){
unsigned int keyStorage = AttachmentsDict<Tag>::key;
if (keyStorage+1 > __storage.size()){
__storage.resize(keyStorage + 1, nullptr);
}
__storage[keyStorage] = container;
}
};
}
-#endif //_XREATE_ATTACHMENTS_H_
\ No newline at end of file
+#endif //_XREATE_ATTACHMENTS_H_
diff --git a/cpp/src/aux/serialization/expressionserializer.cpp b/cpp/src/aux/serialization/expressionserializer.cpp
index bf62ba2..481e813 100644
--- a/cpp/src/aux/serialization/expressionserializer.cpp
+++ b/cpp/src/aux/serialization/expressionserializer.cpp
@@ -1,318 +1,321 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* expressionserializer.cpp
*
* Created on: Jan 4, 2016
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*/
#include "aux/serialization/expressionserializer.h"
#include <boost/utility.hpp>
#include <boost/utility/in_place_factory.hpp>
#include <cmath>
using namespace std;
//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;
}
};
class ExpressionSerializerPrivate {
//boost::bimap<Index, multiset_of<size_t>> __registry;
struct {
map<Index,size_t> left;
} __registry;
map<unsigned char, size_t> __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::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(boost::in_place());
//move(PackedExpression())
strategy->pack(e, 0, result);
assert(result);
return move(*result);
}
OptionalPackedExpression
ExpressionSerializer::getIdOptional(const Expression& e) const{
OptionalPackedExpression result(boost::in_place());
//move(PackedExpression())
strategy->pack(e, 0, result);
return result;
}
ExpressionSerializerIntegral::ExpressionSerializerIntegral():serializer(*this){}
ExpressionSerializerIntegral::ExpressionSerializerIntegral(const std::vector<Expression>&& expressions)
: std::vector<Expression>(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 OptionalPackedExpression exprPacked = serializer.getIdOptional(e);
assert(exprPacked);
return __registry.at(*exprPacked);
}
boost::optional<size_t>
ExpressionSerializerIntegral::getIdOptional(const Expression& e) const{
const OptionalPackedExpression 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<size_t, size_t>& 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<size_t*>(__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<size_t*>(__storage + size- sizeSizeT);
(*tail) += id << (countRemainedBits - countSufficientBits);
countRemainedBits -= countSufficientBits;
return;
}
assert("Unreachable block");
}
#if BOOST_VERSION <= 105500
PackedExpression::PackedExpression(const PackedExpression& other){
__storage = other.__storage;
size = other.size;
countRemainedBits = other.countRemainedBits;
}
#endif
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/aux/serialization/expressionserializer.h b/cpp/src/aux/serialization/expressionserializer.h
index 52daba8..11b07f5 100644
--- a/cpp/src/aux/serialization/expressionserializer.h
+++ b/cpp/src/aux/serialization/expressionserializer.h
@@ -1,111 +1,114 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* expressionserializer.h
*
* Created on: Jan 4, 2016
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*/
#ifndef SRC_EXPRESSIONSERIALIZER_H_
#define SRC_EXPRESSIONSERIALIZER_H_
#include "ast.h"
#include <string>
#include <boost/optional.hpp>
#include <boost/version.hpp>
namespace xreate {
struct PackedExpression{
PackedExpression(){};
PackedExpression(PackedExpression&& other);
#if BOOST_VERSION <= 105500
PackedExpression (const PackedExpression&);
#else
PackedExpression (const PackedExpression&)=delete;
#endif
~PackedExpression();
void operator<< (const std::pair<size_t, size_t>& 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& operator=(const PackedExpression&)=delete;
PackedExpression& operator=(PackedExpression&&)=delete;
char* __storage = nullptr;
size_t size =0;
unsigned char countRemainedBits =0;
};
typedef boost::optional<PackedExpression> OptionalPackedExpression;
class ExpressionSerializerPrivate;
class ExpressionSerializer {
public:
template<class Container>
ExpressionSerializer(const Container& source): ExpressionSerializer(){
for (const Expression& e: source) {
registerExpression(e);
}
}
template<class Container, class Transformer>
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<Expression>{
typedef std::vector<Expression> PARENT;
public:
ExpressionSerializerIntegral();
ExpressionSerializerIntegral(const std::vector<Expression>&& expressions);
template<class Iterator>
ExpressionSerializerIntegral(Iterator first, Iterator last)
: ExpressionSerializerIntegral(std::vector<Expression>(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<size_t> 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<PackedExpression, size_t> __registry;
ExpressionSerializer serializer;
};
} /* namespace xreate */
-#endif /* SRC_EXPRESSIONSERIALIZER_H_ */
\ No newline at end of file
+#endif /* SRC_EXPRESSIONSERIALIZER_H_ */
diff --git a/cpp/src/aux/xreatemanager-decorators.cpp b/cpp/src/aux/xreatemanager-decorators.cpp
index ff3dc9c..dd20279 100644
--- a/cpp/src/aux/xreatemanager-decorators.cpp
+++ b/cpp/src/aux/xreatemanager-decorators.cpp
@@ -1,67 +1,70 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* xreatemanager-decorators.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on July 16, 2017, 4:40 PM
*/
#include "aux/xreatemanager-decorators.h"
#include "main/Parser.h"
#include "pass/compilepass.h"
#include "pass/adhocpass.h"
#include "pass/cfapass.h"
#include "pass/dfapass.h"
#include "pass/interpretationpass.h"
#include "pass/versionspass.h"
namespace xreate {
void
XreateManagerDecoratorBase::prepareCode(std::string&& code){
grammar::main::Scanner scanner(reinterpret_cast<const unsigned char*>(code.c_str()), code.size());
grammar::main::Parser parser(&scanner);
parser.Parse();
assert(!parser.errors->count && "Parser errors");
PassManager::prepare(parser.root->finalize());
}
void
XreateManagerDecoratorBase::prepareCode(FILE* code){
grammar::main::Scanner scanner(code);
grammar::main::Parser parser(&scanner);
parser.Parse();
assert(!parser.errors->count && "Parser errors");
PassManager::prepare(parser.root->finalize());
}
void
XreateManagerDecoratorBase::analyse(){
CompilePass::prepareQueries(clasp);
clasp->run();
}
void
XreateManagerDecoratorFull::initPasses(){
cfa::CFAPass* passCFG = new cfa::CFAPass(this);
//TODO is it really DFGPass needs CFGpass?
registerPass(new dfa::DFAPass(this), PassId::DFGPass, passCFG);
registerPass(passCFG, PassId::CFGPass);
this->registerPass(new adhoc::AdhocPass(this), PassId::AdhocPass);
this->registerPass(new interpretation::InterpretationPass(this), PassId::InterpretationPass);
this->registerPass(new versions::VersionsPass(this), PassId::VersionsPass);
}
void*
XreateManagerDecoratorFull::run() {
std::unique_ptr<CompilePass> compiler(new compilation::CompilePassCustomDecorators<>(this));
compiler->run();
llvm->print();
llvm->initJit();
return llvm->getFunctionPointer(compiler->getEntryFunction());
}
} //namespace xreate
diff --git a/cpp/src/aux/xreatemanager-decorators.h b/cpp/src/aux/xreatemanager-decorators.h
index 942f23b..9dd7a3f 100644
--- a/cpp/src/aux/xreatemanager-decorators.h
+++ b/cpp/src/aux/xreatemanager-decorators.h
@@ -1,33 +1,36 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* File: xreatemanager-decorators.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on July 16, 2017, 4:37 PM
*/
#ifndef XREATEMANAGER_DECORATORS_H
#define XREATEMANAGER_DECORATORS_H
#include "xreatemanager.h"
namespace xreate {
class XreateManagerDecoratorBase: public details::tier2::XreateManager{
public:
void analyse();
public:
virtual void prepareCode(std::string&& code);
virtual void prepareCode(FILE* code);
};
class XreateManagerDecoratorFull: public XreateManagerDecoratorBase {
public:
void initPasses() override;
void* run();
};
}
#endif /* XREATEMANAGER_DECORATORS_H */
diff --git a/cpp/src/aux/xreatemanager-modules.h b/cpp/src/aux/xreatemanager-modules.h
index 27688d9..ab15bc2 100644
--- a/cpp/src/aux/xreatemanager-modules.h
+++ b/cpp/src/aux/xreatemanager-modules.h
@@ -1,110 +1,113 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* File: PassManagerModular.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on June 22, 2017, 5:32 PM
*/
#ifndef PASSMANAGERMODULAR_H
#define PASSMANAGERMODULAR_H
#include "ast.h"
#include "modules.h"
#include "modules/Parser.h"
#include "main/Parser.h"
namespace xreate{namespace modules {
template<class Parent>
class XreateManagerDecoratorModules: public Parent{
public:
XreateManagerDecoratorModules(): __registry(new ModulesRegistry()){}
void prepareCode(std::string&& code) override {
Scanner scannerModules(reinterpret_cast<const unsigned char*>(code.c_str()), code.size());
std::list<std::string> listIncludedFiles;
parseModulesGrammar(scannerModules, listIncludedFiles);
grammar::main::Scanner scannerMain(reinterpret_cast<const unsigned char*>(code.c_str()), code.size());
parseMainGrammar(scannerMain, listIncludedFiles);
}
void prepareCode(FILE* code) override {
Scanner scannerModules(code);
std::list<std::string> listIncludedFiles;
parseModulesGrammar(scannerModules, listIncludedFiles);
grammar::main::Scanner scannerMain(code);
parseMainGrammar(scannerMain, listIncludedFiles);
}
private:
ModulesRegistry* __registry;
void parseModulesGrammar(Scanner& scanner, std::list<std::string>& listIncludedFiles){
ModulesSolver solver(__registry);
Parser parser(&scanner);
parser.Parse();
parser.module.__path = "";
solver.init("", parser.module);
std::list<std::string> modulesExternal = solver.run(parser.module);
std::string programBase = solver.__program.str();
for (const std::string module: modulesExternal){
parseModulesGrammar(module, programBase, listIncludedFiles);
}
}
void parseModulesGrammar(const std::string& path, std::string base, std::list<std::string>& listIncludedFiles){
FILE* input = fopen(path.c_str(), "r");
assert(input != nullptr);
Scanner scanner(input);
Parser parser(&scanner);
parser.Parse();
parser.module.__path = path;
fclose(input);
ModulesSolver solver(__registry);
solver.init(base, parser.module);
std::list<std::string>&& modulesExternal = solver.run(parser.module);
std::string programBase = solver.__program.str();
for (const std::string module: modulesExternal){
parseModulesGrammar(module, programBase, listIncludedFiles);
}
listIncludedFiles.push_back(path);
}
void parseMainGrammar(grammar::main::Scanner& scanner, std::list<std::string>& listIncludedFiles){
details::incomplete::AST* ast = new AST;
grammar::main::Parser parser(&scanner);
parser.root = ast;
parser.Parse();
assert(!parser.errors->count && "Parser errors");
for (auto file: listIncludedFiles){
FILE* fileContent = fopen(file.c_str(), "r");
grammar::main::Scanner scanner(fileContent);
grammar::main::Parser parser(&scanner);
parser.root = ast;
parser.Parse();
fclose(fileContent);
assert(!parser.errors->count && "Parser errors");
}
PassManager::prepare(ast->finalize());
}
};
}} //end namespace xreate::modules
#endif /* PASSMANAGERMODULAR_H */
diff --git a/cpp/src/clasplayer.cpp b/cpp/src/clasplayer.cpp
index 519f176..6bf8895 100644
--- a/cpp/src/clasplayer.cpp
+++ b/cpp/src/clasplayer.cpp
@@ -1,275 +1,283 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ * File: clasplayer.cpp
+ */
+
#include "clasplayer.h"
#include <iostream>
#include "utils.h"
#include <boost/format.hpp>
#include <boost/algorithm/string/join.hpp>
#include <gringo/scripts.hh>
#include "analysis/aux.h"
#include "analysis/DominatorsTreeAnalysisProvider.h"
#include "analysis/cfagraph.h"
#include "analysis/dfagraph.h"
using namespace std;
//TODO escape identifiers started with 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::Symbol params;
std::tie(warningId, params) = parse<unsigned int, Gringo::Symbol>(warning->second);
cout << "Warning: " << __warnings.at(warningId) << " ";
params.print(out);
out<<params;
}
}
bool
ClaspLayer::handleSolution(Gringo::Model const &model) {
std::list<std::string> 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::Symbol atom : model.atoms(clingo_show_type_atoms)) {
atom.print(cout);
cout <<" | "<< endl;
string atomName(atom.name().c_str());
if (atomName == atomBindVar || atomName == atomBindFunc || atomName == atomBindScope){
string name = std::get<1>(parse<Gringo::Symbol, Gringo::Symbol>(atom)).name().c_str();
__model.emplace(move(name), move(atom));
}
__model.emplace(atomName, move(atom));
}
return true;
}
void
ClaspLayer::setCFAData(xreate::cfa::CFAGraph* graph) {
dataCFA.reset(graph);
}
void
ClaspLayer::setDFAData(xreate::dfa::DFAGraph* graph){
dataDFA.reset(graph);
}
void
ClaspLayer::addRuleWarning(const RuleWarning &rule) {
//__partGeneral << rule << endl;
list<string> domains;
boost::format formatDef("%1%(%2%)");
std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(domains, domains.begin()),
[&formatDef](const std::pair<std::string, DomainAnnotation> &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<string> vars;
std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(vars, vars.begin()),
[](const std::pair<std::string, DomainAnnotation> &argument) {
return argument.first.c_str();
});
list<list<string>> guardsRaw;
std::transform(rule.__guards.begin(), rule.__guards.end(), std::inserter(guardsRaw, guardsRaw.begin()),
[this](const Expression &guard) {
return xreate::analysis::compile(guard);
});
const list<string>& guards = xreate::analysis::multiplyLists(std::move(guardsRaw));
list<string> &&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, ", "))
<<endl;
}
}
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){
__partGeneral << script;
}
void
ClaspLayer::run() {
involveImports();
if (this->dataDFA){
this->dataDFA->print(__partGeneral);
}
if (this->dataCFA){
this->dataCFA->print(__partGeneral);
}
dominators::DominatorsTreeAnalysisProvider providerDominators;
providerDominators.run(this);
providerDominators.print(__partGeneral);
ostringstream program;
program << __partTags.str() << __partGeneral.str();
cout << FYEL(program.str()) << endl;
std::vector<char const *> args{"clingo", nullptr};
DefaultGringoModule moduleDefault;
Gringo::Scripts scriptsDefault(moduleDefault);
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->handleSolution(model);
return true;
}, {});
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) {
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)
{
SymbolPacked result(symbol.identifier.id, symbol.identifier.version, pack(symbol.scope));
__indexSymbolNameHints.emplace(result, hintSymbolName);
return result;
}
Symbol
ClaspLayer::unpack(const SymbolPacked& symbol)
{
return Symbol{ScopedSymbol{symbol.identifier, symbol.version}, __registryScopes[symbol.scope]};
};
std::string
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) + ")";
}
}
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) {
return __queries.emplace(id, query).first->second;
}
IQuery*
ClaspLayer::getQuery(const QueryId& id){
assert(__queries.count(id) && "Undefined query");
return __queries.at(id);
}
-}
\ No newline at end of file
+}
diff --git a/cpp/src/clasplayer.h b/cpp/src/clasplayer.h
index 2a1a617..cbced8e 100644
--- a/cpp/src/clasplayer.h
+++ b/cpp/src/clasplayer.h
@@ -1,245 +1,253 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ * File: clasplayer.h
+ */
+
#ifndef CLASPLAYER_H
#define CLASPLAYER_H
#include "ast.h"
#include "contextrule.h"
#include <clingo/clingocontrol.hh>
#include <string>
#include <climits>
#include <boost/bimap.hpp>
#include <boost/bimap/multiset_of.hpp>
#include <boost/optional.hpp>
#include <boost/scoped_ptr.hpp>
#include <list>
namespace xreate {
typedef unsigned int ScopePacked;
struct SymbolPacked {
VNameId identifier;
versions::VariableVersion version;
ScopePacked scope;
bool categoryTransient;
SymbolPacked(): categoryTransient(false){}
SymbolPacked(ScopedSymbol i, ScopePacked s, bool isTransient = false): identifier(i.id), version(i.version), scope(s), categoryTransient(isTransient){}
SymbolPacked(VNameId symbolId, versions::VariableVersion symbolVersion, ScopePacked symbolScope, bool isTransient = false)
: identifier(symbolId), version(symbolVersion), scope(symbolScope), categoryTransient(isTransient){}
};
bool operator==(const SymbolPacked& s1, const SymbolPacked& s2);
bool operator<(const SymbolPacked& s1, const SymbolPacked& s2);
enum class DFGConnection {
STRONG, WEAK, PROTOTYPE
};
class IAnalysisData {
public:
void print(std::ostringstream& output) const;
virtual ~IAnalysisData(){};
};
class IQuery {
public:
virtual void init(ClaspLayer* clasp) = 0;
virtual ~IQuery() {}
};
enum class QueryId {
ContainersQuery,
ContextQuery,
PtrvalidQuery
};
namespace dfa{
class DFAGraph;
}
namespace cfa {
class CFAGraph;
}
class ClaspLayer {
friend class ContextRule;
//PROVIDERS:
public:
boost::scoped_ptr<xreate::dfa::DFAGraph> dataDFA;
void setDFAData(xreate::dfa::DFAGraph* graph);
boost::scoped_ptr<xreate::cfa::CFAGraph> dataCFA;
void setCFAData(xreate::cfa::CFAGraph* graph);
void addRawScript(std::string&& script);
private:
void involveImports();
//QUERIES
public:
IQuery* registerQuery(IQuery* query, const QueryId& id);
IQuery* getQuery(const QueryId& id);
template<class ...Types>
static std::tuple<Types...> parse(const Gringo::Symbol& atom);
typedef std::multimap<std::string, Gringo::Symbol>::const_iterator ModelIterator;
typedef boost::optional<std::pair<ClaspLayer::ModelIterator, ClaspLayer::ModelIterator>> ModelFragment;
ModelFragment query(const std::string& atom);
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);
private:
std::map<QueryId, IQuery*> __queries;
std::multimap<std::string, Gringo::Symbol> __model;
std::map<SymbolPacked, std::string> __indexSymbolNameHints;
std::unordered_map<const CodeScope*, unsigned int> __indexScopes;
std::vector<CodeScope*> __registryScopes;
//WARNINGS
//TODO move to separate provider/query
public:
void addRuleWarning(const RuleWarning &rule);
unsigned int registerWarning(std::string &&message);
private:
std::map<unsigned int, std::string> __warnings;
void printWarnings(std::ostream& out);
//DEFAULT
public:
AST *ast;
ClaspLayer();
void run();
private:
std::ostringstream __partTags;
std::ostringstream __partGeneral;
bool handleSolution(Gringo::Model const &model);
};
template<class typ>
struct ParseImplAtom {
static typ get(const Gringo::Symbol& atom) {
return atom.num();
}
};
template<>
struct ParseImplAtom<std::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<SymbolPacked> {
static SymbolPacked get(const Gringo::Symbol& atom) {
auto result = ClaspLayer::parse<unsigned int, unsigned int, unsigned int>(atom);
return SymbolPacked(std::get<0>(result), std::get<1>(result), std::get<2>(result));
}
};
template<>
struct ParseImplAtom<Gringo::Symbol> {
static Gringo::Symbol get(const Gringo::Symbol& atom) {
return atom;
}
};
template<>
struct ParseImplAtom<std::list<Gringo::Symbol>>{
static std::list<Gringo::Symbol> get(const Gringo::Symbol& atom) {
assert (atom.type() == Gringo::SymbolType::Fun);
std::list<Gringo::Symbol> result;
for (const Gringo::Symbol& arg: atom.args()) {
result.push_back(ParseImplAtom<Gringo::Symbol>::get(arg));
}
return result;
}
};
template<>
struct ParseImplAtom<Expression> {
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:
{
//FUNC
Expression result(Operator::CALL,{Expression(std::string(atom.name().c_str()))});
for (const Gringo::Symbol& arg : atom.args()) {
result.addArg(ParseImplAtom<Expression>::get(arg));
}
return result;
}
default:
{
assert(false);
}
}
}
};
template<class Tuple, size_t index>
struct Parse_Impl {
static void parse(Tuple& tup, Gringo::SymSpan::iterator arg) {
const size_t tupleSize = std::tuple_size<Tuple>::value;
typedef typename std::tuple_element < tupleSize - index, Tuple>::type ElType;
ElType& el = std::get < tupleSize - index > (tup);
Gringo::Symbol atom = *arg;
el = ParseImplAtom<ElType>::get(atom);
Parse_Impl<Tuple, index - 1 > ::parse(tup, ++arg);
}
};
template<class Tuple>
struct Parse_Impl<Tuple, 0> {
static void parse(Tuple& tup, Gringo::SymSpan::iterator arg) {
}
};
template<class ...Types>
std::tuple<Types...>
ClaspLayer::parse(const Gringo::Symbol& atom) {
typedef std::tuple < Types...> Tuple;
Tuple tup;
Parse_Impl<Tuple, std::tuple_size<Tuple>::value>::parse(tup, atom.args().first);
return tup;
}
}
-#endif
\ No newline at end of file
+#endif
diff --git a/cpp/src/compilation/adhocfunctiondecorator.h b/cpp/src/compilation/adhocfunctiondecorator.h
index 44a2dbf..a26dce8 100644
--- a/cpp/src/compilation/adhocfunctiondecorator.h
+++ b/cpp/src/compilation/adhocfunctiondecorator.h
@@ -1,46 +1,49 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* File: adhocfunctiondecorator.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on July 29, 2017, 12:26 PM
*/
#ifndef ADHOCFUNCTIONDECORATOR_H
#define ADHOCFUNCTIONDECORATOR_H
#include "ast.h"
#include "llvmlayer.h"
using namespace xreate::compilation;
namespace xreate{ namespace adhoc{
template<class Parent>
class AdhocFunctionDecorator: public Parent{
public:
AdhocFunctionDecorator(ManagedFnPtr f, CompilePass* p)
: Parent(f, p) {}
protected:
llvm::Type* prepareResult(){
PassManager* man = Parent::pass->man;
CodeScope* entry = Parent::function->__entry;
LLVMLayer* llvm = Parent::pass->man->llvm;
AST* ast = Parent::pass->man->root;
adhoc::AdhocPass* adhocpass = reinterpret_cast<AdhocPass*>(man->getPassById(PassId::AdhocPass));
if (! Parent::function->isPrefunction){
return Parent::prepareResult();
}
adhocImplementation = adhocpass->findAssotiatedScheme(entry);
return llvm->toLLVMType(ast->expandType(adhocImplementation->getResultType()));
}
public:
AdhocScheme* adhocImplementation=nullptr;
};
}} //end of namespace xreate::adhoc
#endif /* ADHOCFUNCTIONDECORATOR_H */
diff --git a/cpp/src/compilation/advanced.cpp b/cpp/src/compilation/advanced.cpp
index e4f787c..85490f4 100644
--- a/cpp/src/compilation/advanced.cpp
+++ b/cpp/src/compilation/advanced.cpp
@@ -1,401 +1,404 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* File: InstructionsAdvanced.cpp
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*
* Created on June 26, 2016, 6:00 PM
*/
//#include <compilation/transformations.h>
#include "compilation/advanced.h"
#include "compilation/containers.h"
#include "compilation/transformersaturation.h"
#include "query/context.h"
#include "query/containers.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::ICodeScopeUnit* scope = context.scope; \
compilation::IFunctionUnit* function = context.function;
Advanced::Advanced(compilation::Context ctx)
: context(ctx), tyNum(static_cast<llvm::IntegerType*> (ctx.pass->man->llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::Num))))) {
}
llvm::Value*
Advanced::compileMapSolidOutput(const Expression &expr, const std::string hintRetVar) {
EXPAND_CONTEXT
UNUSED(scope);
//initialization
Symbol symbolIn = Attachments::get<Symbol>(expr.getOperands()[0]);
ImplementationRec<SOLID> implIn = containers::Query::queryImplementation(symbolIn).extract<SOLID>(); // impl of input list
size_t size = implIn.size;
CodeScope* scopeLoop = expr.blocks.front();
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::ICodeScopeUnit* scopeLoopUnit = function->getScopeUnit(scopeLoop);
scopeLoopUnit->bindArg(elIn, move(varEl));
Value* elOut = scopeLoopUnit->compile();
Value *pElOut = builder.CreateGEP(dataOut, ArrayRef<Value *>(std::vector<Value*>{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, builder.GetInsertBlock());
//next iteration checks:
Value* condAfter = builder.CreateICmpSLE(stateLoopNext, rangeTo);
builder.CreateCondBr(condAfter, blockLoop, blockAfterLoop);
//finalization:
builder.SetInsertPoint(blockAfterLoop);
return dataOut;
}
Value*
Advanced::compileArrayIndex(llvm::Value* aggregate, std::vector<llvm::Value *> indexes, std::string hintRetVar) {
EXPAND_CONTEXT
UNUSED(function);
UNUSED(scope);
indexes.insert(indexes.begin(), llvm::ConstantInt::get(tyNum, 0));
llvm::Value *pEl = llvm->builder.CreateGEP(aggregate, llvm::ArrayRef<llvm::Value *>(indexes));
return llvm->builder.CreateLoad(pEl, NAME("el"));
}
Value*
Advanced::compileStructIndex(llvm::Value* aggregate, const ExpandedType& t, const std::string& idx) {
EXPAND_CONTEXT
UNUSED(scope);
UNUSED(function);
TypeUtils types(llvm);
std::vector<std::string>&& fields = types.getStructFields(t);
for (unsigned i = 0, size = fields.size(); i < size; ++i) {
if (fields.at(i) == idx) {
//TODO DISABLEDFEATURE validptr
// TODO review safety check: validPtr for `aggregate`
// SECTIONTAG validptr exception
// std::vector<llvm::Value*> refs;
// llvm::BasicBlock *blockSafe = llvm::BasicBlock::Create(llvm::getGlobalContext(), "safe", function->raw);
// PointerType* tyAggr = dyn_cast<PointerType>(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->builder.SetInsertPoint(blockSafe);
//dereference pointer
if (types.isPointer(t)) {
llvm::Value* addr = llvm->builder.CreateConstGEP2_32(nullptr, aggregate, 0, i);
return llvm->builder.CreateLoad(addr);
}
aggregate->getType()->dump();
return llvm->builder.CreateExtractValue(aggregate, llvm::ArrayRef<unsigned>{i});
}
}
assert(false && "not found required struct field");
return nullptr;
}
llvm::Value*
Advanced::compileFold(const Expression& fold, const std::string& hintRetVar) {
EXPAND_CONTEXT
assert(fold.op == Operator::FOLD);
//initialization:
Symbol varInSymbol = Attachments::get<Symbol>(fold.getOperands()[0]);
Implementation info = Query::queryImplementation(varInSymbol);
Iterator* it = Iterator::create(context, varInSymbol);
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::BasicBlock *blockBeforeLoop = llvm->builder.GetInsertBlock();
std::unique_ptr<TransformerSaturation> transformerSaturation(new TransformerSaturation(blockBeforeLoop, context.pass->managerTransformations));
llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold", function->raw);
llvm::BasicBlock *blockLoopBody = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold_body", function->raw);
llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold_after", function->raw);
llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold_next", function->raw);
llvm->builder.CreateBr(blockLoop);
// * create phi
llvm->builder.SetInsertPoint(blockLoop);
llvm::PHINode *accum = llvm->builder.CreatePHI(accumInit->getType(), 2, varAccum);
accum->addIncoming(accumInit, blockBeforeLoop);
llvm::PHINode *itLoop = llvm->builder.CreatePHI(rangeBegin->getType(), 2, "foldIt");
itLoop->addIncoming(rangeBegin, blockBeforeLoop);
// * loop checks
Value* condRange = llvm->builder.CreateICmpNE(itLoop, rangeEnd);
llvm->builder.CreateCondBr(condRange, blockLoopBody, blockAfterLoop);
// * loop body
llvm->builder.SetInsertPoint(blockLoopBody);
CodeScope* scopeLoop = fold.blocks.front();
compilation::ICodeScopeUnit* loopUnit = function->getScopeUnit(scopeLoop);
Value* elIn = it->get(itLoop);
loopUnit->bindArg(accum, move(varAccum));
loopUnit->bindArg(elIn, move(varEl));
Value* accumNext = loopUnit->compile();
// * Loop saturation checks
bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockNext, blockAfterLoop, context);
llvm::BasicBlock* blockSaturation = llvm->builder.GetInsertBlock();
if (!flagSaturationTriggered){
llvm->builder.CreateBr(blockNext);
}
// * computing next iteration state
llvm->builder.SetInsertPoint(blockNext);
Value *itLoopNext = it->advance(itLoop);
accum->addIncoming(accumNext, llvm->builder.GetInsertBlock());
itLoop->addIncoming(itLoopNext, llvm->builder.GetInsertBlock());
llvm->builder.CreateBr(blockLoop);
// * finalization:
llvm->builder.SetInsertPoint(blockAfterLoop);
if (!flagSaturationTriggered){
return accum;
}
llvm::PHINode* result = llvm->builder.CreatePHI(accumInit->getType(), 2);
result->addIncoming(accum, blockLoop);
result->addIncoming(accumNext, blockSaturation);
return result;
}
llvm::Value*
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(), "foldinf", function->raw);
llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm::getGlobalContext(), "foldinf_next", function->raw);
llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "foldinf_post", function->raw);
std::unique_ptr<TransformerSaturation> transformerSaturation(new TransformerSaturation(blockBeforeLoop, context.pass->managerTransformations));
llvm->builder.CreateBr(blockLoop);
// * create phi
llvm->builder.SetInsertPoint(blockLoop);
llvm::PHINode *accum = llvm->builder.CreatePHI(accumInit->getType(), 2, accumName);
accum->addIncoming(accumInit, blockBeforeLoop);
// * loop body
CodeScope* scopeLoop = fold.blocks.front();
compilation::ICodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop);
unitLoop->bindArg(accum, move(accumName));
Value* accumNext = unitLoop->compile();
// * Loop saturation checks
bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockNext, blockAfterLoop, context);
assert(flagSaturationTriggered);
// * computing next iteration state
llvm->builder.SetInsertPoint(blockNext);
accum->addIncoming(accumNext, llvm->builder.GetInsertBlock());
llvm->builder.CreateBr(blockLoop);
// finalization:
llvm->builder.SetInsertPoint(blockAfterLoop);
return accumNext;
}
llvm::Value*
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();
blockTrue = builder.GetInsertBlock();
builder.CreateBr(blockAfter);
builder.SetInsertPoint(blockFalse);
CodeScope* scopeFalse = exprIf.blocks.back();
llvm::Value* resultFalse = function->getScopeUnit(scopeFalse)->compile();
blockFalse = builder.GetInsertBlock();
builder.CreateBr(blockAfter);
builder.SetInsertPoint(blockAfter);
llvm::PHINode *ret = builder.CreatePHI(resultTrue->getType(), 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*
Advanced::compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar) {
EXPAND_CONTEXT
AST* root = context.pass->man->root;
UNUSED(function);
assert(exprSwitch.operands.size() >= 2);
assert(exprSwitch.operands[1].op == Operator::CASE_DEFAULT && "No default case in Switch Statement");
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(root->getType(exprSwitch));
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; i < size; ++i) {
llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm::getGlobalContext(), "case" + std::to_string(i), function->raw);
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<llvm::ConstantInt>(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;
}
//TODO recognize cases to make const arrays/stored in global mem/stack alloced.
llvm::Value*
Advanced::compileListAsSolidArray(const Expression &expr, const std::string& hintRetVar) {
EXPAND_CONTEXT
UNUSED(scope);
UNUSED(function);
AST* root = context.pass->man->root;
const size_t& length = expr.getOperands().size();
const Expression& expression = expr;
llvm::Value* zero = ConstantInt::get(tyNum, 0);
llvm::Value* one = ConstantInt::get(tyNum, 1);
ExpandedType typAggrExpanded = root->getType(expression);
assert(typAggrExpanded->__operator == TypeOperator::ARRAY);
llvm::Type* typEl = llvm->toLLVMType(ExpandedType(typAggrExpanded->__operands[0]));
ArrayType* typAggr = (ArrayType*) llvm::ArrayType::get(typEl, length);
llvm::Value* list = llvm->builder.CreateAlloca(typAggr, ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), length, false), hintRetVar);
const std::vector<Expression>& operands = expression.getOperands();
llvm::Value* addrOperand = llvm->builder.CreateGEP(typAggr, list, ArrayRef<Value *>(std::vector<Value*>{zero, zero}));
llvm->builder.CreateStore(scope->process(operands.front()), addrOperand) ;
for (auto i=++operands.begin(); i!=operands.end(); ++i){
addrOperand = llvm->builder.CreateGEP(typEl, addrOperand, ArrayRef<Value *>(std::vector<Value*>{one}));
llvm->builder.CreateStore(scope->process(*i), addrOperand) ;
}
return list;
// Value* listDest = l.builder.CreateAlloca(typList, ConstantInt::get(typI32, __size), *hintRetVar);
// l.buil1der.CreateMemCpy(listDest, listSource, __size, 16);
}
llvm::Value*
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<Constant *> 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);
}
diff --git a/cpp/src/compilation/advanced.h b/cpp/src/compilation/advanced.h
index 5bef2ef..76f4c4f 100644
--- a/cpp/src/compilation/advanced.h
+++ b/cpp/src/compilation/advanced.h
@@ -1,49 +1,52 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* File: InstructionsAdvanced.h
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*
* 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 <vector>
namespace xreate {
namespace compilation {
class Advanced {
public:
Advanced(compilation::Context ctx);
llvm::Value* compileArrayIndex(llvm::Value* aggregate, std::vector<llvm::Value *> 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* compileMapSolidOutput(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="");
//DISABLEDFEATURE Context Loop
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* compileListAsSolidArray(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
index b1d8c49..c4c8049 100644
--- a/cpp/src/compilation/containers.cpp
+++ b/cpp/src/compilation/containers.cpp
@@ -1,195 +1,203 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * File: containers.cpp
+ * Author: pgess <v.melnychenko@xreate.org>
+ */
+
#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<ON_THE_FLY>(context, var, data.extract<ON_THE_FLY>());
case SOLID:
return new IteratorForward<SOLID>(context, var, data.extract<SOLID>());
default: assert(true);
}
assert(false && "Unknown declaration");
return nullptr;
}
llvm::Value*
IteratorForward<ON_THE_FLY>::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*
IteratorForward<ON_THE_FLY>::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*
IteratorForward<ON_THE_FLY>::get(Value* index,const std::string& hintRetVar){
const Expression& currentDecl = CodeScope::getDeclaration(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->processSymbol(current);
return xreate::compilation::Advanced(context).compileArrayIndex(currentValue, std::vector<Value *>{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();
std::string varEl = currentDecl.bindings[0];
const Symbol& symbIn = Attachments::get<Symbol>(currentDecl.getOperands()[0]);
auto it = std::unique_ptr<Iterator>(Iterator::create(context, symbIn));
Value* elIn = it->get(index, varEl);
compilation::ICodeScopeUnit* 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 = Attachments::get<Symbol>(currentDecl);
auto it = std::unique_ptr<Iterator>(Iterator::create(context, symbIn));
return it->get(index);
};
default: break;
}
if (linkedlist){
return index;
}
assert(false && "Unknown declaration");
return nullptr;
}
llvm::Value*
IteratorForward<ON_THE_FLY>::advance(Value* index, const std::string& hintRetVar){
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->getType(CodeScope::getDeclaration(source));
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;
}
//const ImplementationRec<ON_THE_FLY>& implementation
IteratorForward<SOLID>::IteratorForward(const compilation::Context& ctx, const xreate::Symbol& symbolContainer, const ImplementationRec<SOLID>& implementation)
: Iterator(), __length(implementation.size), llvm(ctx.pass->man->llvm)
{
__container = ctx.function->getScopeUnit(symbolContainer.scope)->processSymbol(symbolContainer);
}
llvm::Value*
IteratorForward<SOLID>::begin(){
//0
return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 0);
}
llvm::Value*
IteratorForward<SOLID>::end(){
//length
return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), __length);
}
llvm::Value*
IteratorForward<SOLID>::get(llvm::Value* index,const std::string& hintRetVar){
//GEP[index]]
llvm::Type* tyNum = llvm::Type::getInt32Ty(llvm::getGlobalContext());
llvm::Value* pResult = llvm->builder.CreateGEP(__container, ArrayRef<Value *>(std::vector<Value*>{ConstantInt::get(tyNum, 0), index}));
return llvm->builder.CreateLoad(pResult, hintRetVar);
}
llvm::Value*
IteratorForward<SOLID>::advance(llvm::Value* index, const std::string& hintRetVar){
//index + 1
llvm::Type* tyNum = llvm::Type::getInt32Ty(llvm::getGlobalContext());
return llvm->builder.CreateAdd(index, llvm::ConstantInt::get(tyNum, 1), hintRetVar);
}
diff --git a/cpp/src/compilation/containers.h b/cpp/src/compilation/containers.h
index 89969b8..148deb5 100644
--- a/cpp/src/compilation/containers.h
+++ b/cpp/src/compilation/containers.h
@@ -1,80 +1,88 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * File: containers.h
+ * Author: pgess <v.melnychenko@xreate.org>
+ */
+
#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"
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<ImplementationType I>
class IteratorForward;
template<>
class IteratorForward<ON_THE_FLY> : public Iterator {
private:
LLVMLayer* llvm;
const xreate::Symbol current;
const Symbol source;
const ImplementationLinkedList linkedlist;
CodeScope* const sourceScope;
//TODO initialize and mark as const (three fields)
compilation::ICodeScopeUnit* sourceUnit;
compilation::IFunctionUnit* function; //TODO is used somewhere?
const Expression& sourceDecl;
compilation::Context context;
llvm::Type* sourceRawType =nullptr;
public:
IteratorForward(const compilation::Context& ctx, const xreate::Symbol& s, const ImplementationRec<ON_THE_FLY>& implementation)
: llvm(ctx.pass->man->llvm),
current(s),
source(implementation.source),
linkedlist(source),
sourceScope(source.scope),
sourceUnit(ctx.function->getScopeUnit(source.scope)),
sourceDecl(CodeScope::getDeclaration(source)),
context(ctx)
{}
llvm::Value* begin() override;
llvm::Value* end() override;
llvm::Value* get(llvm::Value* index,const std::string& hintRetVar="") override;
llvm::Value* advance(llvm::Value* index, const std::string& hintRetVar="") override;
};
template<>
class IteratorForward<SOLID>: public Iterator{
size_t __length;
llvm::Value* __container;
LLVMLayer* llvm;
public:
IteratorForward(const compilation::Context& ctx, const xreate::Symbol& symbolContainer, const ImplementationRec<SOLID>& implementation);
llvm::Value* begin() override;
llvm::Value* end() override;
llvm::Value* get(llvm::Value* index,const std::string& hintRetVar="") override;
llvm::Value* advance(llvm::Value* index, const std::string& hintRetVar="") override;
};
}}
#endif //CODEINSTRUCTIONS_H
diff --git a/cpp/src/compilation/latecontextcompiler2.cpp b/cpp/src/compilation/latecontextcompiler2.cpp
index 02f3cf4..1468036 100644
--- a/cpp/src/compilation/latecontextcompiler2.cpp
+++ b/cpp/src/compilation/latecontextcompiler2.cpp
@@ -1,195 +1,198 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* LateContextCompiler2.cpp
*
- * Created on: 10 февр. 2016
- * Author: pgess
+ * Created on: 02/10, 2016
+ * Author: pgess <v.melnychenko@xreate.org>
*/
//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 <iostream>
using namespace std;
namespace xreate {namespace context{
const string topicSpecializationAtom = "specialization";
const string topicDependencyAtom = "dependency";
typedef ExpressionSerialization<RequirementIntegralCode>::Code DomainId;
typedef ExpressionSerialization<RequirementIntegralCode>::Serializer Domain;
//TODO implement variantDefault;
llvm::Value* compileDecisionSelector(llvm::IRBuilder<>& builder, llvm::Value* selector, std::vector<llvm::Value*> vectorVariants, llvm::Value* variantDefault=nullptr){
assert(vectorVariants.size()>0);
llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext());
llvm::Type* tyElement = vectorVariants[0]->getType();
llvm::Type* tyVariants = llvm::VectorType::get(tyElement, vectorVariants.size());
llvm::Value* vectorRaw = llvm::ConstantVector::getNullValue(tyVariants);
for(DomainId i=0; i<vectorVariants.size(); ++i){
vectorRaw = builder.CreateInsertElement(vectorRaw, vectorVariants[i], llvm::ConstantInt::get(ty32, i));
}
return builder.CreateExtractElement(vectorRaw, selector);
}
LateContextCompiler2::LateContextCompiler2(compilation::IFunctionUnit* f, CompilePass* p)
: function(f), pass(p){
ContextQuery* context = pass->queryContext;
__sizeOfDemand = context->getFunctionDemand(function->function->getName()).size();
}
llvm::Value*
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<ManagedFnPtr>& specializations = pass->man->root->getFunctionVariants(calleeName);
//independent decision:
Expression topic(Operator::CALL, {(Atom<Identifier_t>(string(topicSpecializationAtom))),
Expression(Operator::CALL, {Atom<Identifier_t>(string(calleeName))}),
Atom<Number_t>(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>{(unsigned) topicId});
const Domain& specializationsDomain= context->getTopicDomain(topic);
std::vector<llvm::Function*> 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 compileDecisionSelectorAsSwitch(topicDecisionRaw, vectorVariants, specializationDefault);
}
llvm::Value*
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(); i<size; ++i){
const Expression& topic = demandCallee.left.at(i);
llvm::Value* decisionRaw;
if (demandSelf.right.count(topic)){
//TOTEST decision propagation
//propagate decision
const size_t& topicId = demandSelf.right.at(topic);
decisionRaw = builder.CreateExtractValue(this->rawContextArgument, llvm::ArrayRef<unsigned>{(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>{(unsigned) i});
}
return res;
}
llvm::Value*
LateContextCompiler2::compileDependentDecision(const Expression& topic, ScopePacked scopeCaller){
const string& functionName = function->function->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<Identifier_t>(string(topicDependencyAtom)), topic, Atom<Number_t>(scopeCaller)});
const Domain& demandOfTopic = context->getTopicDomain(topic);
const Domain& domainOfTopicDependency = context->getTopicDomain(topicDependency);
//dependent decision
vector<llvm::Value*> vectorDecisions(domainOfTopicDependency.size(), llvm::UndefValue::get(ty32));
for (const std::pair<Expression, Expression>& 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>{(unsigned) topicDependencyId});
auto result = compileDecisionSelector(pass->man->llvm->builder, decisionRaw, vectorDecisions);
return result;
}
llvm::Value*
LateContextCompiler2::compileDecisionSelectorAsSwitch(llvm::Value* selector, std::vector<llvm::Function*> vectorVariants, llvm::Function* 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; i<vectorVariants.size(); ++i){
llvm::BasicBlock* blockCase = llvm::BasicBlock::Create(llvm::getGlobalContext(), "", this->function->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 {
return __sizeOfDemand;
}
}} /* namespace xreate::context */
diff --git a/cpp/src/compilation/latecontextcompiler2.h b/cpp/src/compilation/latecontextcompiler2.h
index f4d91ab..b895641 100644
--- a/cpp/src/compilation/latecontextcompiler2.h
+++ b/cpp/src/compilation/latecontextcompiler2.h
@@ -1,51 +1,54 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* LateContextCompiler2.h
*
- * Created on: 10 февр. 2016
- * Author: pgess
+ * Created on: 02/10, 2016
+ * Author: pgess <v.melnychenko@xreate.org>
*/
//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 IFunctionUnit;
}}
namespace xreate {namespace context{
typedef unsigned int ScopePacked;
class LateContextCompiler2 {
public:
llvm::Value* rawContextArgument = nullptr;
LateContextCompiler2(compilation::IFunctionUnit* f, CompilePass* p);
llvm::Value* findFunction(const std::string& calleeName, llvm::Function* specializationDefault, ScopePacked scopeCaller);
llvm::Value* compileContextArgument(const std::string& callee, ScopePacked scopeCaller);
size_t getFunctionDemandSize() const;
private:
//boost::bimap<size_t, std::string> __decisions;
//std::vector<Domain> __scheme;
compilation::IFunctionUnit* function;
CompilePass* pass;
size_t __sizeOfDemand;
llvm::Value* compileDependentDecision(const Expression& topic, ScopePacked scopeCaller);
llvm::Value* compileDecisionSelectorAsSwitch(llvm::Value* selector, std::vector<llvm::Function*> vectorVariants, llvm::Function* variantDefault);
};
}} /* namespace xreate::context */
-#endif /* LATECONTEXTCOMPILER2_H_ */
\ No newline at end of file
+#endif /* LATECONTEXTCOMPILER2_H_ */
diff --git a/cpp/src/compilation/operators.cpp b/cpp/src/compilation/operators.cpp
index 14266cf..bef5747 100644
--- a/cpp/src/compilation/operators.cpp
+++ b/cpp/src/compilation/operators.cpp
@@ -1,67 +1,70 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* operators.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on April 8, 2017, 1:35 PM
*/
#include "operators.h"
#include "llvmlayer.h"
#include "ExternLayer.h"
#include <vector>
using namespace llvm;
using namespace std;
namespace xreate {
namespace pointerarithmetic {
llvm::Value*
PointerArithmetic::add(llvm::Value *left, llvm::Value *right, compilation::Context context, const std::string& hintVarDecl){
LLVMLayer* llvm = context.pass->man->llvm;
if (left->getType()->isPointerTy() && right->getType()->isIntegerTy()){
std::vector<llvm::Value*> indexes{right};
//{llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 0)};
//indexes.push_back(right);
return llvm->builder.CreateGEP(left, llvm::ArrayRef<llvm::Value*>(indexes), hintVarDecl);
}
return nullptr;
}
}//end of pointgerarithmetic namespace
llvm::Value*
StructUpdate::add(const Expression& left, llvm::Value *leftRaw, const Expression& right, compilation::Context context, const std::string& hintVarDecl){\
if (!(right.__state == Expression::COMPOUND && right.op == Operator::LIST_NAMED)){
return nullptr;
}
PassManager* man = context.pass->man;
ExpandedType tyOperandLeft = man->root->getType(left);
const std::vector<string> fieldsFormal = (tyOperandLeft.get().__operator == TypeOperator::CUSTOM)?
man->llvm->layerExtern->getStructFields(man->llvm->layerExtern->lookupType(tyOperandLeft.get().__valueCustom))
: tyOperandLeft.get().fields;
std::map<std::string, size_t> indexFields;
for(size_t i=0, size = fieldsFormal.size(); i<size; ++i){
indexFields.emplace(fieldsFormal[i], i);
}
llvm::Value* result = leftRaw;
for (size_t i=0; i<right.operands.size(); ++i){
const Expression& value = right.operands.at(i);
llvm::Value* valueRaw = context.scope->process(value, right.bindings.at(i));
unsigned int fieldId = indexFields.at(right.bindings.at(i));
result = man->llvm->builder.CreateInsertValue(result, valueRaw, llvm::ArrayRef<unsigned>({fieldId}));
}
return result;
}
-} //end of xreate namespace
\ No newline at end of file
+} //end of xreate namespace
diff --git a/cpp/src/compilation/operators.h b/cpp/src/compilation/operators.h
index 10437b7..d465944 100644
--- a/cpp/src/compilation/operators.h
+++ b/cpp/src/compilation/operators.h
@@ -1,33 +1,36 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* File: operators.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on April 8, 2017, 1:33 PM
*/
#ifndef OPERATORS_H
#define OPERATORS_H
#include "pass/compilepass.h"
namespace llvm {
class Value;
}
namespace xreate {
namespace pointerarithmetic {
class PointerArithmetic {
public:
static llvm::Value* add(llvm::Value *left, llvm::Value *right, compilation::Context context, const std::string& hintVarDecl);
};
} //end of pointerarithmetic namespace
class StructUpdate {
public:
static llvm::Value* add(const Expression& left, llvm::Value *leftRaw, const Expression& right, compilation::Context context, const std::string& hintVarDecl);
};
} //namespace xreate
#endif /* OPERATORS_H */
diff --git a/cpp/src/compilation/scopedecorators.h b/cpp/src/compilation/scopedecorators.h
index 8c3146f..5671bcb 100644
--- a/cpp/src/compilation/scopedecorators.h
+++ b/cpp/src/compilation/scopedecorators.h
@@ -1,129 +1,132 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* File: scopedecorators.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on February 24, 2017, 11:35 AM
*/
#ifndef SCOPEDECORATORS_H
#define SCOPEDECORATORS_H
#include "ast.h"
#include "compilation/targetinterpretation.h"
#include "compilation/versions.h"
#include "compilation/transformations.h"
namespace xreate {
class CompilePass;
namespace compilation {
class ICodeScopeUnit;
class IFunctionUnit;
template<class Parent>
class CachedScopeDecorator: public Parent{
typedef CachedScopeDecorator<Parent> SELF;
public:
CachedScopeDecorator(CodeScope* codeScope, IFunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){}
void bindArg(llvm::Value* value, std::string&& alias)
{
//ensure existence of an alias
assert(Parent::scope->__identifiers.count(alias));
//memorize new value for an alias
ScopedSymbol id{Parent::scope->__identifiers.at(alias), versions::VERSION_NONE};
__rawVars[id] = value;
}
void bindArg(llvm::Value* value, const ScopedSymbol& s) {
__rawVars[s] = value;
}
llvm::Value* compile(const std::string& hintBlockDecl="") override{
if (__rawVars.count(ScopedSymbol::RetSymbol)){
return __rawVars[ScopedSymbol::RetSymbol];
}
return Parent::compile(hintBlockDecl);
}
llvm::Value*
processSymbol(const Symbol& s, std::string hintRetVar) override{
CodeScope* scope = s.scope;
SELF* self = dynamic_cast<SELF*>(Parent::function->getScopeUnit(scope));
if (self->__rawVars.count(s.identifier)){
return self->__rawVars[s.identifier];
}
//Declaration could be overriden
Expression declaration = CodeScope::getDeclaration(s);
if (!declaration.isDefined()){
if (self->__declarationsOverriden.count(s.identifier)){
declaration = self->__declarationsOverriden[s.identifier];
} else {
assert(false); //in case of binding there should be raws provided.
}
}
return self->__rawVars[s.identifier] = Parent::processSymbol(s, hintRetVar);
}
void
overrideDeclaration(const Symbol binding, Expression&& declaration){
SELF* self = dynamic_cast<SELF*>(Parent::function->getScopeUnit(binding.scope));
self->__declarationsOverriden.emplace(binding.identifier, std::move(declaration));
}
void registerChildScope(std::shared_ptr<ICodeScopeUnit> scope){
__childScopes.push_back(scope);
}
void reset(){
__rawVars.clear();
__declarationsOverriden.clear();
__childScopes.clear();
}
private:
std::unordered_map<ScopedSymbol, Expression> __declarationsOverriden;
std::unordered_map<ScopedSymbol,llvm::Value*> __rawVars;
std::list<std::shared_ptr<ICodeScopeUnit>> __childScopes;
};
typedef CachedScopeDecorator<
compilation::TransformationsScopeDecorator<
interpretation::InterpretationScopeDecorator<
versions::VersionsScopeDecorator<compilation::BasicCodeScopeUnit>>>>
DefaultCodeScopeUnit;
} //end of compilation namespace
struct CachedScopeDecoratorTag;
struct VersionsScopeDecoratorTag;
template<>
struct DecoratorsDict<CachedScopeDecoratorTag>{
typedef compilation::CachedScopeDecorator<
compilation::TransformationsScopeDecorator<
interpretation::InterpretationScopeDecorator<
versions::VersionsScopeDecorator<compilation::BasicCodeScopeUnit>>>> result;
};
template<>
struct DecoratorsDict<VersionsScopeDecoratorTag>{
typedef versions::VersionsScopeDecorator<
compilation::BasicCodeScopeUnit> result;
};
} //end of xreate
#endif /* SCOPEDECORATORS_H */
diff --git a/cpp/src/compilation/targetinterpretation.cpp b/cpp/src/compilation/targetinterpretation.cpp
index 702f5d0..33cbd3f 100644
--- a/cpp/src/compilation/targetinterpretation.cpp
+++ b/cpp/src/compilation/targetinterpretation.cpp
@@ -1,494 +1,497 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* File: targetinterpretation.cpp
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*
* Created on June 29, 2016, 6:45 PM
*/
#include "compilation/targetinterpretation.h"
#include "pass/interpretationpass.h"
#include "analysis/typeinference.h"
#include "llvmlayer.h"
#include "compilation/scopedecorators.h"
#include <boost/scoped_ptr.hpp>
#include <iostream>
#include <clang/AST/DeclBase.h>
using namespace std;
using namespace xreate::compilation;
namespace xreate{ namespace interpretation{
const Expression EXPRESSION_FALSE = Expression(Atom<Number_t>(0));
const Expression EXPRESSION_TRUE = Expression(Atom<Number_t>(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; i<size; ++i){
const Expression& exprCase = process(expression.operands[i]);
if (function->getScope(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;
}
CodeScope*
InterpretationScope::processOperatorSwitchVariant(const Expression& expression){
const Expression& condition = process(expression.operands.at(0));
assert(condition.op == Operator::VARIANT);
const string identCondition = expression.bindings.front();
Expression opExpected(Atom<Number_t>(condition.getValueDouble()));
auto itFoundValue = std::find(++expression.operands.begin(), expression.operands.end(), opExpected);
assert(itFoundValue != expression.operands.end());
int indexBlock = itFoundValue - expression.operands.begin() -1;
auto blockFound = expression.blocks.begin();
std::advance(blockFound, indexBlock);
InterpretationScope* scopeI12n = function->getScope(*blockFound);
if (condition.operands.size()) {
const Expression& value = condition.operands.at(0);
scopeI12n->overrideBinding(value, identCondition);
}
return *blockFound;
}
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 SWITCH_VARIANT: {
CodeScope* scopeResult = processOperatorSwitchVariant(expression);
const Expression& condition = process(expression.operands.at(0));
const string identCondition = expression.bindings.front();
auto scopeCompilation = Decorators<CachedScopeDecoratorTag>::getInterface(context.function->getScopeUnit(scopeResult));
if(condition.operands.size()){
//override value
Symbol symbCondition{ScopedSymbol{scopeResult->__identifiers.at(identCondition), versions::VERSION_NONE}, scopeResult};
scopeCompilation->overrideDeclaration(symbCondition, Expression(condition.operands.at(0)));
//set correct type for binding:
TypeAnnotation typeVariant = typeinference::getType(condition, *function->man->ast);
int conditionIndex = condition.getValueDouble();
ScopedSymbol symbolInternal = scopeResult->getSymbol(identCondition);
scopeResult->__declarations[symbolInternal].bindType(typeVariant.__operands.at(conditionIndex));
}
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];
Symbol symbEl{ScopedSymbol{scopeBody->__identifiers.at(nameEl), versions::VERSION_NONE}, scopeBody};
const std::string& idAccum = expression.bindings[1];
llvm::Value* rawAccum = context.scope->process(expression.getOperands()[1]);
InterpretationScope* intrBody = function->getScope(scopeBody);
auto unitBody = Decorators<CachedScopeDecoratorTag>::getInterface(context.function->getScopeUnit(scopeBody));
const std::vector<Expression> elementsInput= exprInput.getOperands();
for (size_t i=0; i<elementsInput.size(); ++i){
intrBody->reset();
unitBody->reset();
Expression exprElement = elementsInput[i];
intrBody->overrideBinding(exprElement, nameEl);
unitBody->overrideDeclaration(symbEl, move(exprElement));
unitBody->bindArg(rawAccum, string(idAccum));
rawAccum = unitBody->compile();
}
return rawAccum;
}
/*
case FOLD_INF_INTERPRET_INOUT{
}
*/
case CALL_INTERPRET_PARTIAL: {
const std::string &calleeName = expression.getValueString();
ICodeScopeUnit* scopeUnitSelf = context.scope;
ManagedFnPtr callee = this->function->man->ast->findFunction(calleeName);
const FunctionInterpretationData& calleeData = FunctionInterpretationHelper::getSignature(callee);
std::vector<llvm::Value *> argsActual;
PIFSignature sig;
sig.declaration = callee;
for(size_t no=0, size = expression.operands.size(); no < size; ++no){
const Expression& op = expression.operands[no];
if (calleeData.signature.at(no) == INTR_ONLY){
sig.bindings.push_back(process(op));
continue;
}
argsActual.push_back(scopeUnitSelf->process(op));
}
TargetInterpretation* man = dynamic_cast<TargetInterpretation*>(this->function->man);
PIFunction* pifunction = man->getFunction(move(sig));
llvm::Function* raw = pifunction->compile();
boost::scoped_ptr<CallStatementRaw> statement(new CallStatementRaw(raw, man->pass->man->llvm));
return (*statement)(move(argsActual));
}
default: break;
}
assert(false&& "Unknown hybrid operator");
return nullptr;
}
llvm::Value*
InterpretationScope::compile(const Expression& expression, const Context& context){
const InterpretationData& data = Attachments::get<InterpretationData>(expression);
if (data.op != InterpretationOperator::NONE){
return compileHybrid(data.op, expression, context);
}
Expression result = process(expression);
return context.scope->process(result);
}
Expression
InterpretationScope::process(const Expression& expression){
switch (expression.__state){
case Expression::INVALID:
assert(false);
case Expression::NUMBER:
case Expression::STRING:
return expression;
case Expression::IDENT:{
Symbol s = Attachments::get<Symbol>(expression);
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);
InterpretationFunction* fnUnit = this->function->man->getFunction(fnAst);
vector<Expression> args;
args.reserve(expression.getOperands().size());
for(size_t i=0, size = expression.getOperands().size(); i<size; ++i) {
args.push_back(process(expression.getOperands()[i]));
}
return fnUnit->process(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::SWITCH_VARIANT: {
CodeScope* scopeResult = processOperatorSwitchVariant(expression);
return function->getScope(scopeResult)->processScope();
}
case Operator::INDEX: {
const Expression& exprKey = process(expression.operands[1]);
const Expression& exprData = process(expression.operands[0]);
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; i<size; ++i){
body->overrideBinding(exprInput.getOperands()[i], argEl);
body->overrideBinding(accum, argAccum);
accum = body->processScope();
}
return accum;
}
// case Operator::MAP: {
// break;
// }
default: break;
}
return expression;
}
InterpretationFunction*
TargetInterpretation::getFunction(IFunctionUnit* unit){
if (__dictFunctionsByUnit.count(unit)) {
return __dictFunctionsByUnit.at(unit);
}
InterpretationFunction* f = new InterpretationFunction(unit->function, this);
__dictFunctionsByUnit.emplace(unit, f);
assert(__functions.emplace(unit->function.id(), f).second);
return f;
}
PIFunction*
TargetInterpretation::getFunction(PIFSignature&& sig){
auto f = __pifunctions.find(sig);
if (f != __pifunctions.end()){
return f->second;
}
PIFunction* result = new PIFunction(PIFSignature(sig), __pifunctions.size(), this);
__pifunctions.emplace(move(sig), result);
assert(__dictFunctionsByUnit.emplace(result->functionUnit, result).second);
return result;
}
InterpretationScope*
TargetInterpretation::transformContext(const Context& c){
return this->getFunction(c.function)->getScope(c.scope->scope);
}
llvm::Value*
TargetInterpretation::compile(const Expression& expression, const Context& ctx){
return transformContext(ctx)->compile(expression, ctx);
}
InterpretationFunction::InterpretationFunction(const ManagedFnPtr& function, Target<TargetInterpretation>* target)
: Function<TargetInterpretation>(function, target)
{}
Expression
InterpretationFunction::process(const std::vector<Expression>& args){
InterpretationScope* body = getScope(__function->__entry);
for(size_t i=0, size = args.size(); i<size; ++i) {
body->overrideBinding(args.at(i), string(body->scope->__bindings.at(i)));
}
return body->processScope();
}
// Partial function interpretation
typedef BasicFunctionUnit PIFunctionUnitParent;
class PIFunctionUnit: public PIFunctionUnitParent{
public:
PIFunctionUnit(ManagedFnPtr f, std::set<size_t>&& arguments, size_t id, CompilePass* p)
: PIFunctionUnitParent(f, p), argumentsActual(move(arguments)), __id(id)
{}
protected:
std::vector<llvm::Type*> prepareArguments(){
LLVMLayer* llvm = PIFunctionUnitParent::pass->man->llvm;
AST* ast = PIFunctionUnitParent::pass->man->root;
CodeScope* entry = PIFunctionUnitParent::function->__entry;
std::vector<llvm::Type*> signature;
for(size_t no: argumentsActual){
VNameId argId = entry->__identifiers.at(entry->__bindings.at(no));
ScopedSymbol arg{argId, versions::VERSION_NONE};
signature.push_back(llvm->toLLVMType(ast->expandType(entry->__declarations.at(arg).type)));
}
return signature;
}
llvm::Function::arg_iterator prepareBindings(){
CodeScope* entry = PIFunctionUnitParent::function->__entry;
ICodeScopeUnit* entryCompilation = PIFunctionUnitParent::getScopeUnit(entry);
llvm::Function::arg_iterator fargsI = PIFunctionUnitParent::raw->arg_begin();
for(size_t no: argumentsActual){
ScopedSymbol arg{entry->__identifiers.at(entry->__bindings.at(no)), versions::VERSION_NONE};
entryCompilation->bindArg(&*fargsI, arg);
fargsI->setName(entry->__bindings.at(no));
++fargsI;
}
return fargsI;
}
virtual std::string prepareName(){
return PIFunctionUnitParent::prepareName() + "_" + std::to_string(__id);
}
private:
std::set<size_t> argumentsActual;
size_t __id;
};
PIFunction::PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target)
: InterpretationFunction(sig.declaration, target), signatureInstance(move(sig))
{
const FunctionInterpretationData& functionData = FunctionInterpretationHelper::getSignature(signatureInstance.declaration);
std::set<size_t> argumentsActual;
for (size_t no=0, size=functionData.signature.size(); no < size; ++no){
if (functionData.signature.at(no) != INTR_ONLY){
argumentsActual.insert(no);
}
}
functionUnit = new PIFunctionUnit(signatureInstance.declaration, move(argumentsActual), id, target->pass);
CodeScope* entry = signatureInstance.declaration->__entry;
auto entryUnit = Decorators<CachedScopeDecoratorTag>::getInterface<>(functionUnit->getEntry());
InterpretationScope* entryIntrp = InterpretationFunction::getScope(entry);
for(size_t no=0, sigNo=0, size = entry->__bindings.size(); no < size; ++no){
if (functionData.signature.at(no) == INTR_ONLY){
entryIntrp->overrideBinding(signatureInstance.bindings[sigNo], entry->__bindings[no]);
VNameId argId = entry->__identifiers.at(entry->__bindings[no]);
Symbol argSymbol{ScopedSymbol{argId, versions::VERSION_NONE}, entry};
entryUnit->overrideDeclaration(argSymbol, Expression(signatureInstance.bindings[sigNo]));
++sigNo;
}
}
}
llvm::Function*
PIFunction::compile(){
llvm::Function* raw = functionUnit->compile();
return raw;
}
bool operator<(const PIFSignature& lhs, const PIFSignature& rhs){
if (lhs.declaration.id() != rhs.declaration.id()) {
return lhs.declaration.id() < rhs.declaration.id();
}
return lhs.bindings < rhs.bindings;
}
bool operator<(const PIFSignature& lhs, PIFunction* const rhs){
return lhs < rhs->signatureInstance;
}
bool operator<(PIFunction* const lhs, const PIFSignature& rhs){
return lhs->signatureInstance < rhs;
}
}}
diff --git a/cpp/src/compilation/targetinterpretation.h b/cpp/src/compilation/targetinterpretation.h
index 5223763..07a7c6c 100644
--- a/cpp/src/compilation/targetinterpretation.h
+++ b/cpp/src/compilation/targetinterpretation.h
@@ -1,131 +1,128 @@
-/*
- * 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.
- */
-
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* File: targetstatic.h
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*
* Created on July 2, 2016, 1:25 PM
*/
#ifndef TARGETSTATIC_H
#define TARGETSTATIC_H
#include "ast.h"
#include "pass/compilepass.h"
#include "compilation/targets.h"
#include "pass/interpretationpass.h"
namespace xreate{ namespace interpretation{
class TargetInterpretation;
class InterpretationScope;
class InterpretationFunction;
}}
namespace xreate{ namespace compilation{
template <>
struct TargetInfo<interpretation::TargetInterpretation> {
typedef Expression Result;
typedef interpretation::InterpretationScope Scope;
typedef interpretation::InterpretationFunction Function;
};
}}
namespace xreate{ namespace interpretation{
class InterpretationScope: public compilation::Scope<TargetInterpretation>{
typedef Scope<TargetInterpretation> Parent;
public:
InterpretationScope(CodeScope* scope, compilation::Function<TargetInterpretation>* f): Parent(scope, f) {}
Expression process(const Expression& expression) override;
llvm::Value* compile(const Expression& expression, const compilation::Context& context);
private:
llvm::Value* compileHybrid(const InterpretationOperator& op, const Expression& expression, const compilation::Context& context);
//llvm::Value* compilePartialFnCall(const Expression& expression, const Context& context);
CodeScope* processOperatorIf(const Expression& expression);
CodeScope* processOperatorSwitch(const Expression& expression);
CodeScope* processOperatorSwitchVariant(const Expression& expression);
};
class InterpretationFunction: public compilation::Function<TargetInterpretation>{
public:
InterpretationFunction(const ManagedFnPtr& function, compilation::Target<TargetInterpretation>* target);
Expression process(const std::vector<Expression>& args);
};
/*
* Partially interpreted function signature
*/
struct PIFSignature{
ManagedFnPtr declaration;
std::vector<Expression> bindings;
};
class PIFunctionUnit;
class PIFunction: public InterpretationFunction{
public:
PIFunctionUnit* functionUnit;
PIFSignature signatureInstance;
PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target);
llvm::Function* compile();
};
bool operator<(const PIFSignature& lhs, PIFunction* const rhs);
bool operator<(PIFunction* const lhs, const PIFSignature& rhs);
class TargetInterpretation: public compilation::Target<TargetInterpretation>{
public:
TargetInterpretation(AST* root, CompilePass* passCompilation): Target<TargetInterpretation>(root), pass(passCompilation){}
//target:
public:
InterpretationFunction* getFunction(compilation::IFunctionUnit* unit);
PIFunction* getFunction(PIFSignature&& sig);
private:
std::map<PIFSignature, PIFunction*> __pifunctions;
std::map<compilation::IFunctionUnit*, InterpretationFunction*> __dictFunctionsByUnit;
//self:
public:
CompilePass* pass;
llvm::Value* compile(const Expression& expression, const compilation::Context& ctx);
private:
InterpretationScope* transformContext(const compilation::Context& c);
};
template<class Parent>
class InterpretationScopeDecorator: public Parent{
public:
InterpretationScopeDecorator(CodeScope* codeScope, compilation::IFunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){}
virtual llvm::Value* process(const Expression& expr, const std::string& hintVarDecl){
const InterpretationData& data = Attachments::get<InterpretationData>(expr, {ANY, NONE});
bool flagInterpretationEligible = (data.resolution == INTR_ONLY || data.op != InterpretationOperator::NONE);
if (flagInterpretationEligible){
compilation::Context ctx{this, this->function, this->pass};
return Parent::pass->targetInterpretation->compile(expr, ctx);
}
return Parent::process(expr, hintVarDecl);
}
};
}} //end of xreate:: interpretation
#endif /* TARGETSTATIC_H */
//transformers:
// template<>
// struct TransformerInfo<TargetInterpretation> {
// static const int id = 1;
-// };
\ No newline at end of file
+// };
diff --git a/cpp/src/compilation/targets.h b/cpp/src/compilation/targets.h
index b7247cd..19bfa24 100644
--- a/cpp/src/compilation/targets.h
+++ b/cpp/src/compilation/targets.h
@@ -1,191 +1,194 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* File: targetabstract.h
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*
* Created on July 2, 2016, 1:25 PM
*/
#ifndef TARGETABSTRACT_H
#define TARGETABSTRACT_H
#include "ast.h"
#include <boost/optional.hpp>
#include <map>
namespace xreate{ namespace compilation {
template <typename ConcreteTarget>
struct TargetInfo{
//typedef Result
//typedef Function
//typedef Scope
};
template<typename ConcreteTarget>
class Function;
template<typename ConcreteTarget>
class Target;
template<typename ConcreteTarget>
class Scope{
typedef typename TargetInfo<ConcreteTarget>::Scope Self;
public:
CodeScope* scope;
typename TargetInfo<ConcreteTarget>::Result
processSymbol(const Symbol& s){
CodeScope* scope = s.scope;
Self* self = function->getScope(scope);
if (self->__bindings.count(s.identifier)) {
return self->__bindings[s.identifier];
}
const Expression& declaration = CodeScope::getDeclaration(s);
if (!declaration.isDefined()){
assert(false); //for bindings there should be result already
}
return self->__bindings[s.identifier] = self->process(declaration);
}
typename TargetInfo<ConcreteTarget>::Result
processScope() {
if (raw) return *raw;
raw = process(scope->getBody());
return *raw;
}
// typename TargetInfo<ConcreteTarget>::Result
// processFunction(typename TargetInfo<ConcreteTarget>::Function* fnRemote, const std::vector<typename TargetInfo<ConcreteTarget>::Result>& args){
// Scope<ConcreteTarget> scopeRemote = fnRemote->getScope(fnRemote->__function->__entry);
//
// if (scopeRemote->raw){
// return scopeRemote->raw;
// }
//
// return fnRemote->process(args);
// }
virtual typename TargetInfo<ConcreteTarget>::Result
process(const Expression& expression)=0;
Scope(CodeScope* codeScope, Function<ConcreteTarget>* f)
: scope(codeScope), function(f) {}
virtual ~Scope(){}
void
overrideBinding(typename TargetInfo<ConcreteTarget>::Result arg, const std::string& name){
assert(scope->__identifiers.count(name));
ScopedSymbol id{scope->__identifiers.at(name), versions::VERSION_NONE};
__bindings[id] = arg;
//reset the result if any:
raw.reset();
}
void registerChildScope(std::shared_ptr<Self> scope){
__childScopes.push_back(scope);
}
void reset(){
__bindings.clear();
__childScopes.clear();
raw.reset();
}
protected:
Function<ConcreteTarget>* function=0;
std::map<ScopedSymbol, typename TargetInfo<ConcreteTarget>::Result> __bindings;
std::list<std::shared_ptr<Self>> __childScopes;
typename boost::optional<typename TargetInfo<ConcreteTarget>::Result> raw;
};
template<typename ConcreteTarget>
class Function{
typedef typename TargetInfo<ConcreteTarget>::Result Result;
typedef typename TargetInfo<ConcreteTarget>::Scope ConcreteScope;
public:
Function(const ManagedFnPtr& function, Target<ConcreteTarget>* target)
: man(target), __function(function) {}
virtual ~Function(){};
ConcreteScope*
getScope(CodeScope* scope){
if (__scopes.count(scope)) {
auto result = __scopes.at(scope).lock();
if (result){
return result.get();
}
}
std::shared_ptr<ConcreteScope> unit(new ConcreteScope(scope, this));
if (scope->__parent != nullptr){
getScope(scope->__parent)->registerChildScope(unit);
} else {
assert(!__entryScope);
__entryScope = unit;
}
if (!__scopes.emplace(scope, unit).second){
__scopes[scope] = unit;
}
return unit.get();
}
virtual Result
process(const std::vector<Result>& args)=0;
Target<ConcreteTarget>* man=0;
ManagedFnPtr __function;
protected:
std::map<CodeScope*, std::weak_ptr<ConcreteScope>> __scopes;
std::shared_ptr<ConcreteScope> __entryScope;
};
template<typename ConcreteTarget>
class Target {
typedef typename TargetInfo<ConcreteTarget>::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, unit);
return unit;
}
return __functions.at(id);
}
AST* ast;
virtual ~Target(){
for (const auto& entry: __functions){
delete entry.second;
}
}
protected:
std::map<unsigned int, ConcreteFunction*> __functions;
};
}}
#endif /* TARGETABSTRACT_H */
diff --git a/cpp/src/compilation/transformations.cpp b/cpp/src/compilation/transformations.cpp
index 1588af8..4b63fe4 100644
--- a/cpp/src/compilation/transformations.cpp
+++ b/cpp/src/compilation/transformations.cpp
@@ -1,29 +1,32 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* transformation.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on March 27, 2017, 4:04 PM
*/
#include "transformations.h"
namespace xreate { namespace compilation {
std::list<Transformer*>
TransformationsManager::getRelevantTransformers(const Expression& expression){
std::list<Transformer*> result;
for (auto tag: expression.tags) {
if (__subscriptions.count(tag.first)){
auto handlers = __subscriptions.equal_range(tag.first);
for (auto handler = handlers.first; handler != handlers.second; ++handler){
result.push_back(__transformers[handler->second]);
}
}
}
return result;
}
-} } //namespace xreate
\ No newline at end of file
+} } //namespace xreate
diff --git a/cpp/src/compilation/transformations.h b/cpp/src/compilation/transformations.h
index 5455411..2fd4473 100644
--- a/cpp/src/compilation/transformations.h
+++ b/cpp/src/compilation/transformations.h
@@ -1,110 +1,113 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* File: transformations.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on March 25, 2017, 9:04 PM
*/
#ifndef TRANSFORMATIONS_H
#define TRANSFORMATIONS_H
#include "pass/compilepass.h"
namespace xreate { namespace compilation {
template <class TransformerType>
struct TransformerInfo {
//static const unsigned int id = 1; (current vacant id)
};
class Transformer{
public:
virtual llvm::Value* transform(const Expression& expression, llvm::Value* raw, const Context& ctx)=0;
virtual ~Transformer(){};
};
class TransformationsManager {
public:
std::list<Transformer*> getRelevantTransformers(const Expression& expression);
template<class TransformerType>
void registerTransformer(const std::string& annotation, TransformerType* t){
const int id = TransformerInfo<TransformerType>::id;
assert(!__transformers.count(id));
__transformers[id] = t;
__subscriptions.emplace(annotation, id);
}
template<class TransformerType>
void unregisterTransformer(const std::string& annotation, TransformerType* t){
const unsigned int id = TransformerInfo<TransformerType>::id;
auto range = __subscriptions.equal_range(annotation);
const auto entry = make_pair(annotation, id);
__subscriptions.erase(std::find_if(range.first, range.second, [id](const auto& el){return el.second == id;}));
__transformers.erase(id);
}
template<class TransformerType>
TransformerType* update(TransformerType* newInstance){
const int id = TransformerInfo<TransformerType>::id;
Transformer* oldInstance = __transformers[id];
__transformers[id] = newInstance;
return static_cast<TransformerType*>(oldInstance);
}
template<class TransformerType>
bool exists(){
const int id = TransformerInfo<TransformerType>::id;
return __transformers.count(id);
}
template <class TransformerType>
TransformerType* get(){
const int id = TransformerInfo<TransformerType>::id;
return static_cast<TransformerType*>(__transformers.at(id));
}
private:
std::map<unsigned int, Transformer*> __transformers;
std::multimap<std::string, unsigned int> __subscriptions;
};
template <class Parent>
class TransformationsScopeDecorator: public Transformer, public Parent {
// SCOPE DECORATOR PART
public:
TransformationsScopeDecorator(CodeScope* codeScope, IFunctionUnit* f, CompilePass* compilePass)
: Parent(codeScope, f, compilePass){}
virtual llvm::Value*
process(const Expression& expr, const std::string& hintVarDecl=""){
llvm::Value* result = Parent::process(expr, hintVarDecl);
return transform(expr, result, Context{this, Parent::function, Parent::pass});
}
// TRANSFORMER PART
public:
virtual llvm::Value*
transform(const Expression& expression, llvm::Value* raw, const Context& ctx) {
llvm::Value* result = raw;
TransformationsManager* man = Parent::pass->managerTransformations;
if (expression.tags.size())
for (Transformer* handler: man->getRelevantTransformers(expression)){
result = handler->transform(expression, result, ctx);
}
return result;
}
};
} }
#endif /* TRANSFORMATIONS_H */
diff --git a/cpp/src/compilation/transformersaturation.cpp b/cpp/src/compilation/transformersaturation.cpp
index 4ea90d0..7f91e8c 100644
--- a/cpp/src/compilation/transformersaturation.cpp
+++ b/cpp/src/compilation/transformersaturation.cpp
@@ -1,77 +1,80 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* transformersaturation.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on March 25, 2017, 10:06 PM
*/
#include "transformersaturation.h"
#include "llvmlayer.h"
using namespace llvm;
namespace xreate { namespace compilation {
TransformerSaturation::TransformerSaturation(llvm::BasicBlock* allocationBlock, TransformationsManager* manager)
: man(manager), blockAllocation(allocationBlock){
llvm::Type* tyInt1 = llvm::Type::getInt1Ty(llvm::getGlobalContext());
constTrue = llvm::ConstantInt::get(tyInt1, 1);
constFalse = llvm::ConstantInt::get(tyInt1, 0);
if (man->exists<TransformerSaturation>()){
oldInstance = man->update(this);
} else {
man->registerTransformer("break", this);
}
}
TransformerSaturation::~TransformerSaturation(){
if (oldInstance) {
man->update(oldInstance);
} else {
man->unregisterTransformer("break", this);
}
}
llvm::Value*
TransformerSaturation::transform(const Expression& expression, llvm::Value* raw, const Context& ctx){
processBreak(ctx);
return raw;
}
void
TransformerSaturation::processBreak(const Context& ctx){
allocateFlag(ctx);
//show the saturation flag
llvm::IRBuilder<>& builder = ctx.pass->man->llvm->builder;
builder.CreateStore(constTrue, flagSaturation, true);
}
void
TransformerSaturation::allocateFlag(const Context& ctx){
//allocation of saturation flag
llvm::Type* tyInt1 = llvm::Type::getInt1Ty(llvm::getGlobalContext());
IRBuilder<> builder(blockAllocation, blockAllocation->getFirstInsertionPt());
flagSaturation = builder.CreateAlloca(tyInt1, constTrue, "flagSaturation");
builder.CreateStore(constFalse, flagSaturation, true);
}
bool
TransformerSaturation::insertSaturationChecks(llvm::BasicBlock* blockContinue, llvm::BasicBlock* blockExit, const Context& ctx){
if (!flagSaturation) return false;
llvm::IRBuilder<>& builder = ctx.pass->man->llvm->builder;
builder.CreateCondBr(builder.CreateLoad(flagSaturation), blockExit, blockContinue);
return true;
}
-} }
\ No newline at end of file
+} }
diff --git a/cpp/src/compilation/transformersaturation.h b/cpp/src/compilation/transformersaturation.h
index b4e368a..c1a0075 100644
--- a/cpp/src/compilation/transformersaturation.h
+++ b/cpp/src/compilation/transformersaturation.h
@@ -1,46 +1,49 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* File: transformersaturation.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on March 25, 2017, 9:59 PM
*/
#ifndef TRANSFORMERSATURATION_H
#define TRANSFORMERSATURATION_H
#include "transformations.h"
namespace xreate { namespace compilation {
class TransformerSaturation: public Transformer{
public:
TransformerSaturation(llvm::BasicBlock* allocationBlock, TransformationsManager* manager);
~TransformerSaturation();
llvm::Value* transform(const Expression& expression, llvm::Value* raw, const Context& ctx) override;
void processBreak(const Context& ctx);
void allocateFlag(const Context& ctx);
bool insertSaturationChecks(llvm::BasicBlock* blockContinue, llvm::BasicBlock* blockExit, const Context& ctx);
private:
TransformationsManager* man;
TransformerSaturation* oldInstance = nullptr;
llvm::BasicBlock* blockAllocation;
llvm::Value* constTrue;
llvm::Value* constFalse;
llvm::Value* flagSaturation = nullptr;
};
template <>
struct TransformerInfo<TransformerSaturation> {
static const unsigned int id = 0;
};
} }
#endif /* TRANSFORMERSATURATION_H */
diff --git a/cpp/src/compilation/versions.h b/cpp/src/compilation/versions.h
index 82ca3fc..ec9006b 100644
--- a/cpp/src/compilation/versions.h
+++ b/cpp/src/compilation/versions.h
@@ -1,126 +1,128 @@
-
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* versions.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on January 21, 2017, 1:24 PM
*/
#include "pass/versionspass.h"
#include "pass/compilepass.h"
#include "llvmlayer.h"
namespace xreate {
class CompilePass;
namespace compilation {
class ICodeScopeUnit;
class IFunctionUnit;
}
namespace versions{
template<class Parent>
class VersionsScopeDecorator: public Parent{
typedef VersionsScopeDecorator<Parent> SELF;
public:
VersionsScopeDecorator(CodeScope* codeScope, compilation::IFunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){}
virtual llvm::Value* processSymbol(const Symbol& s, std::string hintSymbol=""){
if (Attachments::exists<VersionImposedDependency>(s)){
const std::list<Symbol> dependencies = Attachments::get<VersionImposedDependency>(s);
for(const Symbol& symbolDependent: dependencies){
processSymbol(symbolDependent);
}
}
llvm::Value* result = Parent::processSymbol(s, hintSymbol);
if (s.identifier.version == VERSION_INIT){
llvm::Value* storage = SELF::processIntrinsicInit(result->getType(), hintSymbol);
setSymbolStorage(s, storage);
processIntrinsicCopy(result, storage);
return compilation::ICodeScopeUnit::pass->man->llvm->builder.CreateLoad(storage);
} else if (s.identifier.version != VERSION_NONE){
Symbol symbolInitVersion = getSymbolInitVersion(s);
llvm::Value* storage = getSymbolStorage(symbolInitVersion);
processIntrinsicCopy(result, storage);
return compilation::ICodeScopeUnit::pass->man->llvm->builder.CreateLoad(storage);
}
return result;
}
llvm::Value*
processIntrinsicInit(llvm::Type* typeStorage, const std::string& hintVarDecl=""){
llvm::IntegerType* tyInt = llvm::Type::getInt32Ty(llvm::getGlobalContext());
llvm::ConstantInt* constOne = llvm::ConstantInt::get(tyInt, 1, false);
return compilation::ICodeScopeUnit::pass->man->llvm->builder.CreateAlloca(typeStorage, constOne, hintVarDecl);
}
void
processIntrinsicCopy(llvm::Value* value, llvm::Value* storage){
compilation::ICodeScopeUnit::pass->man->llvm->builder.CreateStore(value, storage);
}
private:
std::map<Symbol, llvm::Value*> __symbolStorage;
static Symbol
getSymbolInitVersion(const Symbol& s){
return Symbol{ScopedSymbol{s.identifier.id, VERSION_INIT}, s.scope};
}
llvm::Value*
getSymbolStorage(const Symbol& s){
return __symbolStorage.at(s);
}
void setSymbolStorage(const Symbol& s, llvm::Value* storage){
__symbolStorage[s] = storage;
}
};
} } //end of namespace xreate::versions
// llvm::Value*
// processIntrinsicInitAndCopy(){
//
// }
//llvm::Value*
//process(const Expression& expr, const std::string& hintVarDecl){
// case Operator::CALL_INTRINSIC: {
// enum INRINSIC{INIT, COPY};
//
// const ExpandedType& typSymbol = pass->man->root->expandType(expr.type);
//
// INTRINSIC op = (INTRINSIC) expr.getValueDouble();
//
// switch (op){
// case INIT: {
// llvm::Type* typSymbolRaw = l.toLLVMType(typSymbol);
//
//
// return storage;
// }
//
// case COPY: {
// llvm::Type* typSymbolRaw = l.toLLVMType(typSymbol);
// llvm::value* valueOriginal = process(expr.getOperands()[0], hintVarDecl);
// llvm::Value* storage = l.builder.CreateAlloca(typSymbolRaw, constOne, hintVarDecl);
// llvm::Value* valueCopy = l.builder.CreateStore(valueOriginal, storage);
//
// return valueCopy;
// }
// }
// return;
// }
//}
-//};
\ No newline at end of file
+//};
diff --git a/cpp/src/contextrule.cpp b/cpp/src/contextrule.cpp
index af3c84e..5904649 100644
--- a/cpp/src/contextrule.cpp
+++ b/cpp/src/contextrule.cpp
@@ -1,53 +1,56 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* contextrule.cpp
*
* Created on: Jan 2, 2016
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*/
#include "contextrule.h"
#include "clasplayer.h"
#include "analysis/aux.h"
#include <boost/format.hpp>
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";
list<string>repHead_ = xreate::analysis::compile(head);
assert(repHead_.size() == 1);
list<string>repGuards_ = xreate::analysis::compile(guards);
assert(repGuards_.size() == 1);
list<string>repBody_ = 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%, 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/contextrule.h b/cpp/src/contextrule.h
index 7d06e3b..2c70f8e 100644
--- a/cpp/src/contextrule.h
+++ b/cpp/src/contextrule.h
@@ -1,30 +1,34 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* contextrule.h
*
* Created on: Jan 2, 2016
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*/
+
#ifndef SRC_CONTEXTRULE_H_
#define SRC_CONTEXTRULE_H_
#include "ast.h"
#include <string>
namespace xreate {
typedef unsigned int ScopePacked;
class ContextRule {
public:
ContextRule(const Expression& rule);
std::string compile(const ScopePacked& scopeId) const;
private:
Expression head;
Expression guards;
Expression body;
};
}
#endif /* SRC_CONTEXTRULE_H_ */
diff --git a/cpp/src/llvmlayer.cpp b/cpp/src/llvmlayer.cpp
index e031be7..2f404cf 100644
--- a/cpp/src/llvmlayer.cpp
+++ b/cpp/src/llvmlayer.cpp
@@ -1,257 +1,266 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * llvmlayer.cpp
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ */
+
#include "ast.h"
#include "llvmlayer.h"
#include "ExternLayer.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/Support/TargetSelect.h"
#include <iostream>
#include <cmath>
using namespace llvm;
using namespace xreate;
using namespace std;
LLVMLayer::LLVMLayer(AST* root)
: ast(root), builder(getGlobalContext()) {
module = new llvm::Module(root->getModuleName(), llvm::getGlobalContext());
layerExtern = new ExternLayer(this);
layerExtern->init(root);
}
void*
LLVMLayer::getFunctionPointer(llvm::Function* function){
uint64_t entryAddr = jit->getFunctionAddress(function->getName().str());
return (void*) entryAddr;
}
void
LLVMLayer::initJit(){
std::string ErrStr;
LLVMInitializeNativeTarget();
llvm::InitializeNativeTargetAsmPrinter();
llvm::EngineBuilder builder((std::unique_ptr<llvm::Module>(module)));
jit = builder
.setEngineKind(llvm::EngineKind::JIT)
.setErrorStr(&ErrStr)
.setVerifyModules(true)
.create();
}
void
LLVMLayer::print(){
llvm::PassManager<llvm::Module> PM;
PM.addPass(llvm::PrintModulePass(llvm::outs(), "banner"));
PM.run(*module);
}
llvm::BasicBlock*
LLVMLayer::initExceptionBlock(llvm::BasicBlock* blockException){
initExceptionsSupport();
PointerType* tyInt8P = PointerType::getInt8PtrTy(llvm::getGlobalContext());
Value* nullInt8P = llvm::ConstantPointerNull::get(tyInt8P);
builder.SetInsertPoint(blockException);
llvm::Function* fAllocate = module->getFunction("__cxa_allocate_exception");
llvm::Function* fThrow = module->getFunction("__cxa_throw");
auto exception = builder.CreateCall(fAllocate, ConstantInt::get(IntegerType::getInt64Ty(getGlobalContext()), 4));
vector<Value*> throwParams{exception, nullInt8P, nullInt8P};
builder.CreateCall(fThrow, ArrayRef<Value*>(throwParams));
builder.CreateUnreachable();
return blockException;
}
void
LLVMLayer::moveToGarbage(void *o)
{
__garbage.push_back(o);
}
llvm::Type*
LLVMLayer::
toLLVMType(const ExpandedType& ty) const {
std::map<int, llvm::StructType*> empty;
return toLLVMType(ty, empty);
}
llvm::Type*
LLVMLayer::
toLLVMType(const ExpandedType& ty, std::map<int, llvm::StructType*>& conjuctions) const
{
TypeAnnotation t = ty;
switch (t.__operator)
{
case TypeOperator::ARRAY:
{
assert(t.__operands.size()==1);
TypeAnnotation elTy = t.__operands.at(0);
return llvm::ArrayType::get(toLLVMType(ExpandedType(move(elTy)), conjuctions), t.__size);
}
case TypeOperator::STRUCT:
{
assert(t.__operands.size());
std::vector<llvm::Type*> pack_;
pack_.reserve(t.__operands.size());
std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(pack_, pack_.end()),
[this, &conjuctions](const TypeAnnotation& t){
return toLLVMType(ExpandedType(TypeAnnotation(t)), conjuctions);
});
llvm::ArrayRef<llvm::Type*> pack(pack_);
//process recursive types:
if (conjuctions.count(t.conjuctionId)) {
auto result = conjuctions[t.conjuctionId];
result->setBody(pack, false);
return result;
}
return llvm::StructType::get(llvm::getGlobalContext(), pack, false);
};
case TypeOperator::LINK: {
llvm::StructType* conjuction = llvm::StructType::create(llvm::getGlobalContext());
int id = t.conjuctionId;
conjuctions.emplace(id, conjuction);
return conjuction;
};
case TypeOperator::CALL:
{
assert(false);
};
case TypeOperator::CUSTOM:
{
//Look in extern types
clang::QualType qt = layerExtern->lookupType(t.__valueCustom);
return layerExtern->toLLVMType(qt);
};
case TypeOperator::VARIANT: {
int size = t.fields.size();
assert(size);
int bitcount = ceil(log2(size));
return llvm::Type::getIntNTy(llvm::getGlobalContext(), bitcount);
}
case TypeOperator::NONE: {
switch (t.__value) {
case TypePrimitive::I32:
case TypePrimitive::Int:
case TypePrimitive::Num:
return llvm::Type::getInt32Ty(llvm::getGlobalContext());
case TypePrimitive::Bool:
return llvm::Type::getInt1Ty(llvm::getGlobalContext());
case TypePrimitive::I8:
return llvm::Type::getInt8Ty(llvm::getGlobalContext());
case TypePrimitive::I64:
return llvm::Type::getInt64Ty(llvm::getGlobalContext());
case TypePrimitive::Float:
return llvm::Type::getDoubleTy(llvm::getGlobalContext());
case TypePrimitive::String:
return llvm::Type::getInt8PtrTy(llvm::getGlobalContext());
default:
assert(false);
}
}
default:
assert(false);
}
assert(false);
return nullptr;
}
void
LLVMLayer::initExceptionsSupport(){
Type* typInt8Ptr = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
if (!module->getFunction("__cxa_throw")) {
std::vector<Type*> fThrowSignature{typInt8Ptr, typInt8Ptr, typInt8Ptr};
FunctionType* tyFThrow = FunctionType::get(
/*Result=*/Type::getVoidTy(module->getContext()),
/*Params=*/fThrowSignature,
/*isVarArg=*/false);
llvm::Function::Create(
/*Type=*/tyFThrow,
/*Linkage=*/GlobalValue::ExternalLinkage,
/*Name=*/"__cxa_throw", module); // (external, no body)
}
if (!module->getFunction("__cxa_allocate_exception")) {
std::vector<Type*>fAllocateSignature{IntegerType::get(module->getContext(), 64)};
FunctionType* tyFAllocate = FunctionType::get(
/*Result=*/typInt8Ptr,
/*Params=*/fAllocateSignature,
/*isVarArg=*/false);
llvm::Function::Create(
/*Type=*/tyFAllocate,
/*Linkage=*/GlobalValue::ExternalLinkage,
/*Name=*/"__cxa_allocate_exception", module); // (external, no body)
}
}
bool TypeUtils::isStruct(const ExpandedType& ty){
const TypeAnnotation& t = ty.get();
if (t.__operator==TypeOperator::STRUCT) {
return true;
}
if (t.__operator != TypeOperator::CUSTOM) {
return false;
}
clang::QualType tqual = llvm->layerExtern->lookupType(t.__valueCustom);
const clang::Type * raw = tqual.getTypePtr();
// TODO skip ALL the pointers until non-pointer type found
if (raw->isStructureType()) return true;
if (!raw->isAnyPointerType()) return false;
clang::QualType pointee = raw->getPointeeType();
return pointee->isStructureType();
}
bool TypeUtils::isPointer(const ExpandedType &ty) {
if (ty.get().__operator != TypeOperator::CUSTOM) return false;
clang::QualType qt = llvm->layerExtern->lookupType(ty.get().__valueCustom);
return llvm->layerExtern->isPointer(qt);
}
std::vector<std::string>
TypeUtils::getStructFields(const ExpandedType &t) {
return (t.get().__operator == TypeOperator::STRUCT)
? t.get().fields
: llvm->layerExtern->getStructFields(
llvm->layerExtern->lookupType(t.get().__valueCustom));
}
diff --git a/cpp/src/llvmlayer.h b/cpp/src/llvmlayer.h
index fbbc823..04a1093 100644
--- a/cpp/src/llvmlayer.h
+++ b/cpp/src/llvmlayer.h
@@ -1,58 +1,67 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * llvmlayer.h
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ */
+
#ifndef LLVMLAYER_H
#define LLVMLAYER_H
#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "utils.h"
namespace xreate {
class AST;
class ExternLayer;
class TypeAnnotation;
class LLVMLayer {
public:
LLVMLayer(AST* rootAST);
AST *ast = 0;
ExternLayer *layerExtern =0;
llvm::Module *module = 0;
llvm::ExecutionEngine* jit= 0;
llvm::IRBuilder<> builder;
void moveToGarbage(void *o);
llvm::Type* toLLVMType(const Expanded<TypeAnnotation>& ty) const;
void print();
void* getFunctionPointer(llvm::Function* function);
void initJit();
llvm::BasicBlock* initExceptionBlock(llvm::BasicBlock* block);
private:
void initExceptionsSupport();
llvm::Type* toLLVMType(const Expanded<TypeAnnotation>& ty, std::map<int, llvm::StructType*>& conjunctions) const;
std::vector<void *> __garbage;
};
struct TypeUtils {
bool isStruct(const Expanded<TypeAnnotation>& ty);
bool isPointer(const Expanded<TypeAnnotation>& ty);
std::vector<std::string> getStructFields(const Expanded<TypeAnnotation>& t);
TypeUtils(LLVMLayer*llvmlayer)
: llvm(llvmlayer){}
private:
LLVMLayer* llvm;
};
}
#endif // LLVMLAYER_H
diff --git a/cpp/src/modules.cpp b/cpp/src/modules.cpp
index 421ec5d..cb5d497 100644
--- a/cpp/src/modules.cpp
+++ b/cpp/src/modules.cpp
@@ -1,175 +1,178 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* modules.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on July 22, 2017, 5:13 PM
*/
#include "modules.h"
#include "modules/Parser.h"
#include "analysis/aux.h"
#include <clingo/clingocontrol.hh>
#include <boost/format.hpp>
#include <regex>
#include <boost/filesystem.hpp>
#include <fstream>
namespace fs = boost::filesystem;
namespace xreate { namespace modules{
void
ModuleRecord::addModuleQuery(const Expression& query){
__queries.push_back(query);
}
void
ModuleRecord::addControllerPath(const std::string& path){
__controllers.push_back(path);
}
void
ModuleRecord::addDiscoveryPath(const std::string& path){
__discoveries.push_back(path);
}
void
ModuleRecord::addProperty(const Expression& prop){
__properties.push_back(prop);
}
void
ModulesSolver::loadControllers(const ModuleRecord& module){
for (const std::string& pathController: module.__controllers){
std::fstream fileContent(pathController);
__program << fileContent.rdbuf();
}
}
void
ModulesSolver::extractProperties(const ModuleRecord& module){
unsigned int moduleId = __registry->getModuleHash(module.__path);
const std::string atomProperty = "bind_module";
boost::format formatProperty(atomProperty + "(%1%, %2%).");
for (const Expression& property: module.__properties){
std::list<std::string> reprProp = xreate::analysis::compile(property);
assert(reprProp.size()== 1);
__program << (formatProperty % moduleId % reprProp.front())
<< std::endl;
}
}
void
ModulesSolver::discoverModules(const ModuleRecord& moduleClient){
std::regex extXreate("\\.xreate$", std::regex::basic);
for(const std::string& path: moduleClient.__discoveries){
for(fs::directory_entry e: fs::recursive_directory_iterator(path)) {
if (fs::is_regular_file(e.status())){
if (!std::regex_search(e.path().string(), extXreate)) continue;
FILE* script = fopen(e.path().c_str(), "r");
Scanner scanner(script);
Parser parser(&scanner);
parser.Parse();
assert(!parser.errors->count && "Discovery errors");
parser.module.__path = e.path().c_str();
extractProperties(parser.module);
fclose(script);
}
}
}
}
void
ModulesSolver::extractRequirements(const ModuleRecord& module){
const std::string atomQuery = "module_require";
boost::format formatProperty(atomQuery + "(%1%, %2%).");
unsigned int moduleId = __registry->getModuleHash(module.__path);
for (const Expression& query: module.__queries){
std::list<std::string> reprQuery = xreate::analysis::compile(query);
assert(reprQuery.size()== 1);
__program << (formatProperty % moduleId % reprQuery.front())
<< std::endl;
}
}
void
ModulesSolver::add(const std::string& base){
__program << base;
}
void
ModulesSolver::init(const std::string& programBase, const ModuleRecord& module){
add(programBase);
extractRequirements(module);
extractProperties(module);
loadControllers(module);
discoverModules(module);
std::cout << __program.str() << std::endl;
}
std::list<std::string>
ModulesSolver::run(const ModuleRecord& module){
const std::string atomDecision = "module_include";
unsigned int moduleId = __registry->getModuleHash(module.__path);
std::list<std::string> result;
std::vector<char const *> args{"clingo", nullptr};
DefaultGringoModule moduleDefault;
Gringo::Scripts scriptsDefault(moduleDefault);
ClingoLib ctl(scriptsDefault, 0, args.data(), {}, 0);
ctl.add("base", {}, __program.str());
ctl.ground({{"base", {}}}, nullptr);
ctl.solve([&atomDecision, this, &result, moduleId](Gringo::Model const &model) {
for (Gringo::Symbol atom : model.atoms(clingo_show_type_atoms)) {
std::cout << atom << std::endl;
if (std::strcmp(atom.name().c_str(), atomDecision.c_str())==0){
auto rowDecision = ClaspLayer::parse<unsigned int, Gringo::Symbol>(atom);
unsigned int moduleIdActual = std::get<0>(rowDecision);
if (moduleIdActual == moduleId){
Gringo::Symbol moduleDecided = std::get<1>(rowDecision);
switch (moduleDecided.type()) {
case Gringo::SymbolType::Str:
result.push_back(moduleDecided.string().c_str());
break;
case Gringo::SymbolType::Num:
result.push_back(__registry->getModuleNameByHash(moduleDecided.num()));
break;
default: assert(false && "Inappropriate symbol type");
}
}
}
}
return true;
}, {});
return result;
}
const std::string&
ModulesRegistry::getModuleNameByHash(unsigned int hash){
auto result = __registry.right.find(hash);
assert(result != __registry.right.end());
return result->second;
}
unsigned int
ModulesRegistry::getModuleHash(const std::string& moduleName){
auto result = __registry.left.insert(Hash::left_value_type(moduleName, __registry.size()));
return result.first->second;
}
}} //namespace xreate::modules
diff --git a/cpp/src/modules.h b/cpp/src/modules.h
index 0e2d150..31a57db 100644
--- a/cpp/src/modules.h
+++ b/cpp/src/modules.h
@@ -1,76 +1,79 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* File: modules.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on July 22, 2017, 5:11 PM
*/
#ifndef MODULES_H
#define MODULES_H
#include "ast.h"
#include <boost/bimap.hpp>
#ifndef FRIENDS_MODULES_TESTS
#define FRIENDS_MODULES_TESTS
#endif
namespace xreate { namespace modules{
class ModulesRegistry{
public:
const std::string& getModuleNameByHash(unsigned int hash);
unsigned int getModuleHash(const std::string& moduleName);
private:
typedef boost::bimap<std::string, unsigned int> Hash;
Hash __registry;
};
class ModulesSolver;
class ModuleRecord {
FRIENDS_MODULES_TESTS
friend class ModulesSolver;
public:
void addModuleQuery(const Expression& query);
void addControllerPath(const std::string& path);
void addDiscoveryPath(const std::string& path);
void addProperty(const Expression& prop);
private:
std::list<Expression> __queries;
std::list<std::string> __controllers;
std::list<std::string> __discoveries;
std::list<Expression> __properties;
public:
std::string __path;
};
class ModulesSolver{
FRIENDS_MODULES_TESTS
public:
ModulesSolver(ModulesRegistry *registry): __registry(registry) {}
void loadControllers(const ModuleRecord& module);
void discoverModules(const ModuleRecord& moduleClient);
void extractProperties(const ModuleRecord& module);
void extractRequirements(const ModuleRecord& module);
void add(const std::string& base);
void init(const std::string& programBase, const ModuleRecord& module);
std::list<std::string> run(const ModuleRecord& module);
private:
ModulesRegistry* __registry;
public:
std::ostringstream __program;
};
}} //end namespace xreate::modules
-#endif /* MODULES_H */
\ No newline at end of file
+#endif /* MODULES_H */
diff --git a/cpp/src/pass/abstractpass.cpp b/cpp/src/pass/abstractpass.cpp
index 18a7ed9..64d2e50 100644
--- a/cpp/src/pass/abstractpass.cpp
+++ b/cpp/src/pass/abstractpass.cpp
@@ -1,58 +1,65 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ */
+
#include "abstractpass.h"
#include "attachments.h"
#include "xreatemanager.h"
using namespace std;
namespace xreate {
template<>
void defaultValue<void>(){}
void AbstractPassBase::finish(){}
AbstractPassBase::AbstractPassBase(PassManager *manager)
: man(manager) {
}
template<>
void
AbstractPass<void>::processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol)
{
if (__visitedSymbols.isCached(symbol))
return;
__visitedSymbols.setCachedValue(symbol);
const Expression& declaration = CodeScope::getDeclaration(symbol);
if (declaration.isDefined()){
PassContext context2 = context.updateScope(symbol.scope);
process(declaration, context2, hintSymbol);
}
}
template<>
void
AbstractPass<void>::process(const Expression& expression, PassContext context, const std::string& varDecl){
if (expression.__state == Expression::COMPOUND){
for (const Expression &op: expression.getOperands()) {
process(op, context);
}
for (CodeScope* scope: expression.blocks) {
process(scope, context);
}
if (expression.op == Operator::CALL){
processExpressionCall(expression, context);
}
return;
}
if (expression.__state == Expression::IDENT){
assert(context.scope);
processSymbol(Attachments::get<Symbol>(expression), context, expression.getValueString());
}
}
}
diff --git a/cpp/src/pass/abstractpass.h b/cpp/src/pass/abstractpass.h
index 39c28de..59bca6b 100644
--- a/cpp/src/pass/abstractpass.h
+++ b/cpp/src/pass/abstractpass.h
@@ -1,194 +1,201 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ */
+
#ifndef ABSTRACTPASS_H
#define ABSTRACTPASS_H
#include "ast.h"
#include "xreatemanager.h"
#include<iostream>
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 context2;
}
~PassContext(){}
};
class AbstractPassBase {
public:
AbstractPassBase(PassManager* manager);
virtual void run()=0;
virtual void finish();
PassManager* man;
};
template<class Output>
Output defaultValue();
template<>
void defaultValue<void>();
template<class Output>
class SymbolCache: private std::map<Symbol, Output>{
public:
bool isCached(const Symbol& symbol){
return this->count(symbol);
}
Output setCachedValue(const Symbol& symbol, Output&& value){
(*this)[symbol] = value;
return value;
}
Output getCachedValue(const Symbol& symbol){
assert(this->count(symbol));
return this->at(symbol);
}
};
template<>
class SymbolCache<void>: private std::set<Symbol>{
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 Output>
class AbstractPass: public AbstractPassBase {
SymbolCache<Output> __visitedSymbols;
protected:
virtual Output processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol=""){
if (__visitedSymbols.isCached(symbol))
return __visitedSymbols.getCachedValue(symbol);
const Expression& declaration = CodeScope::getDeclaration(symbol);
if (declaration.isDefined()){
PassContext context2 = context.updateScope(symbol.scope);
Output&& result = process(declaration, context2, hintSymbol);
return __visitedSymbols.setCachedValue(symbol, std::move(result));
}
return defaultValue<Output>();
}
Output processExpressionCall(const Expression& expression, PassContext context){
const std::string &calleeName = expression.getValueString();
std::list<ManagedFnPtr> callees = man->root->getFunctionVariants(calleeName);
if (callees.size() == 1 && callees.front()){
return processFnCall(callees.front(), context);
} else {
for (const ManagedFnPtr& callee: callees){
processFnCallUncertain(callee, context);
}
return defaultValue<Output>();
}
}
SymbolCache<Output>& getSymbolCache(){
return __visitedSymbols;
}
public:
AbstractPass(PassManager* manager)
: AbstractPassBase(manager){}
virtual Output processFnCall(ManagedFnPtr function, PassContext context){
return defaultValue<Output>();
}
virtual void processFnCallUncertain(ManagedFnPtr function, PassContext context)
{}
virtual void process(ManagedRulePtr rule)
{}
virtual Output process(ManagedFnPtr function)
{
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 processSymbol(Symbol{ScopedSymbol::RetSymbol, scope}, context);
}
virtual Output process(const Expression& expression, PassContext context, const std::string& varDecl=""){
if (expression.__state == Expression::IDENT){
assert(context.scope);
return processSymbol(Attachments::get<Symbol>(expression), context, expression.getValueString());
}
assert(false);
return defaultValue<Output>();
}
void run() {
ManagedRulePtr rule = man->root->begin<MetaRuleAbstract>();
while (rule.isValid()) {
process(rule);
++rule;
}
ManagedFnPtr f = man->root->begin<Function>();
while (f.isValid()) {
process(f);
++f;
}
}
};
template<>
void
AbstractPass<void>::processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol);
template<>
void
AbstractPass<void>::process(const Expression& expression, PassContext context, const std::string& hintSymbol);
}
#endif
//PROCESS FUNCTION:
// const Symbol& symbolFunction{0, function->getEntryScope()};
//
// if (__visitedSymbols.isCached(symbolFunction))
// return __visitedSymbols.getCachedValue(symbolFunction);
//
// PassContext context;
// context.function = function;
//
// Output&& result = process(function->getEntryScope(), context);
// return __visitedSymbols.setCachedValue(symbolFunction, std::move(result));
diff --git a/cpp/src/pass/adhocpass.cpp b/cpp/src/pass/adhocpass.cpp
index ee71b28..af8aea0 100644
--- a/cpp/src/pass/adhocpass.cpp
+++ b/cpp/src/pass/adhocpass.cpp
@@ -1,96 +1,99 @@
-/*
- * adhoc.cpp
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * adhocpass.cpp
*
* Created on: Nov 28, 2015
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*/
#include "pass/adhocpass.h"
#include "query/context.h"
//TODO use ADT/templated types rather than adhocs. remove adhocs.
namespace xreate { namespace adhoc {
AdhocExpression::AdhocExpression(): Expression(Operator::ADHOC, {})
{}
AdhocExpression::AdhocExpression(const Expression& base): Expression(base)
{}
void
AdhocExpression::setCommand(const Expression& comm){
this->addTags({Expression(Operator::CALL, {Atom<Identifier_t>("adhoc"), comm})});
}
Expression
AdhocExpression::getCommand() const{
assert(this->tags.count("adhoc"));
return this->tags.at("adhoc").getOperands().at(0);
}
AdhocScheme*
AdhocPass::findAssotiatedScheme(CodeScope* entry){
const ScopePacked scopeId = man->clasp->pack(entry);
const context::Domain& domain = queryContext->getContext(scopeId);
AdhocScheme* scheme = nullptr;
for (const Expression& context: domain){
if (!(context.__state == Expression::COMPOUND && context.op == Operator::CALL)) continue;
if (__schemes.count(context.getValueString())){
assert(!scheme && "Can't determine relevant scheme, ambiguous context");
scheme = __schemes.at(context.getValueString());
}
}
assert(scheme && "Context doesn't define any ad hoc scheme");
return scheme;
}
const TypeAnnotation&
AdhocScheme::getResultType(){
return __resultType;
}
CodeScope*
AdhocScheme::getCommandImplementation(const Expression& comm) {
assert(comm.__state == Expression::COMPOUND && comm.op == Operator::CALL && comm.operands.size() == 0);
const std::string commSerialized = comm.getValueString();
assert(__commands.count(commSerialized) && "Command isn't defined for a selected scheme");
return __commands.at(commSerialized);
}
AdhocScheme::AdhocScheme(const Expression& scheme):
__resultType(scheme.type), __name(scheme.getValueString()) {
Expression exprCasesList = scheme.getOperands()[0];
for (const Expression& exprSingleCase: exprCasesList.getOperands()){
std::string command = exprSingleCase.tags.begin()->second.getValueString();
CodeScope* blockImpl = *(exprSingleCase.blocks.begin());
__commands.emplace(command, blockImpl);
}
}
const std::string&
AdhocScheme::getName(){
return __name;
}
void
AdhocPass::run(){
queryContext = reinterpret_cast<context::ContextQuery*>(man->clasp->registerQuery(new context::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->getName(), scheme);
}
}
}} //end of namespace xreate::adhoc
diff --git a/cpp/src/pass/adhocpass.h b/cpp/src/pass/adhocpass.h
index 0508f52..6cada0d 100644
--- a/cpp/src/pass/adhocpass.h
+++ b/cpp/src/pass/adhocpass.h
@@ -1,58 +1,62 @@
-/*
- * adhoc.h
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * adhocpass.h
*
* Created on: Nov 28, 2015
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*/
+
//SECTIONTAG adhoc pass
#ifndef SRC_INSTRUCTIONS_ADHOC_H_
#define SRC_INSTRUCTIONS_ADHOC_H_
#include "abstractpass.h"
#ifndef FRIENDS_ADHOC
#define FRIENDS_ADHOC
#endif
namespace xreate { namespace context {
class ContextQuery;
}}
namespace xreate{ namespace adhoc{
class AdhocScheme {
public:
AdhocScheme(const Expression& scheme);
CodeScope* getCommandImplementation(const Expression& comm);
const TypeAnnotation& getResultType();
const std::string& getName();
private:
TypeAnnotation __resultType;
std::string __name;
std::map<std::string, CodeScope*> __commands;
};
class AdhocExpression: public Expression{
public:
AdhocExpression();
AdhocExpression(const Expression& base);
void setCommand(const Expression& comm);
Expression getCommand() const;
};
class AdhocPass: public AbstractPass<void> {
FRIENDS_ADHOC
public:
AdhocPass(PassManager* manager): AbstractPass(manager) {}
void run() override;
AdhocScheme* findAssotiatedScheme(CodeScope* entry);
private:
std::map<std::string, AdhocScheme*> __schemes;
context::ContextQuery* queryContext;
};
}} //end of namespace xreate::adhoc
#endif /* SRC_INSTRUCTIONS_ADHOC_H_ */
diff --git a/cpp/src/pass/cfapass.cpp b/cpp/src/pass/cfapass.cpp
index da51821..72cdbfa 100644
--- a/cpp/src/pass/cfapass.cpp
+++ b/cpp/src/pass/cfapass.cpp
@@ -1,100 +1,109 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * cfapass.cpp
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ */
+
#include "cfapass.h"
#include "analysis/cfagraph.h"
#include <boost/range/iterator_range_core.hpp>
using namespace std;
using namespace xreate::cfa;
void
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 CFAPass::run(){
initSignatures();
return AbstractPass::run();
}
void
CFAPass::finish()
{
man->clasp->setCFAData(move(__context.graph));
return AbstractPass::finish();
}
void
CFAPass::processFnCall(ManagedFnPtr function, PassContext context)
{
ClaspLayer* clasp = man->clasp;
__context.graph->addCallConnection(clasp->pack(context.scope), function->getName());
return AbstractPass::processFnCall(function, context);
}
void
CFAPass::processFnCallUncertain(ManagedFnPtr function, PassContext context){
ClaspLayer* clasp = man->clasp;
__context.graph->addCallConnection(clasp->pack(context.scope), function->getName());
return AbstractPass::processFnCallUncertain(function, context);
}
void
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));
} else {
__context.graph->addParentConnection(scopeId, context.function->getName());
}
//TOTEST scope annotations
//SECTIONTAG context gather scope annotations
__context.graph->addScopeAnnotations(scopeId, scope->tags);
__context.graph->addContextRules(scopeId, scope->contextRules);
return AbstractPass::process(scope, context, hintBlockDecl);
}
//TOTEST scope annotations via scheme
void
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());
}
}
}
return AbstractPass::process(expression, context, varDecl);
}
void
CFAPass::process(ManagedFnPtr function)
{
__context.graph->addFunctionAnnotations(function->getName(), function->getTags());
return AbstractPass::process(function);
}
CFAPass::CFAPass(PassManager* manager)
: AbstractPass(manager)
, __context{new CFAGraph(manager->clasp)}
{}
diff --git a/cpp/src/pass/cfapass.h b/cpp/src/pass/cfapass.h
index be27a1e..8704523 100644
--- a/cpp/src/pass/cfapass.h
+++ b/cpp/src/pass/cfapass.h
@@ -1,39 +1,48 @@
-// Control Flow Graph determination pass
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ *
+ * cfapass.cpp
+ * Control Flow Graph building pass
+ */
+
#ifndef CFGPASS_H
#define CFGPASS_H
#include "xreatemanager.h"
#include "clasplayer.h"
#include "abstractpass.h"
namespace xreate{namespace cfa {
class CFAGraph;
class CFAPass : public AbstractPass<void>
{
public:
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;
CFAPass(PassManager* manager);
void finish() override;
void run() override;
private:
struct {
CFAGraph* graph;
} __context;
std::multimap<Operator, Expression> __signatures; //CFA data for particular operators
void initSignatures();
};
}} //end of namespace xreate::cfa
#endif // CFGPASS_H
diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp
index 4f49948..ebda44d 100644
--- a/cpp/src/pass/compilepass.cpp
+++ b/cpp/src/pass/compilepass.cpp
@@ -1,791 +1,800 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ *
+ * compilepass.cpp
+ */
+
#include "compilepass.h"
#include "clasplayer.h"
#include <ast.h>
#include "llvmlayer.h"
#include "query/containers.h"
#include "query/context.h"
#include "compilation/containers.h"
#include "compilation/latecontextcompiler2.h"
#include "ExternLayer.h"
#include "pass/adhocpass.h"
#include "compilation/targetinterpretation.h"
#include "pass/versionspass.h"
#include "compilation/scopedecorators.h"
#include "compilation/adhocfunctiondecorator.h"
#include "compilation/operators.h"
#include "analysis/typeinference.h"
#include <boost/optional.hpp>
#include <memory>
#include <iostream>
using namespace std;
using namespace llvm;
//TODO use Scope<TargetLlvm>
//SECTIONTAG late-context FunctionDecorator
namespace xreate{namespace context{
template<class Parent>
class LateContextFunctionDecorator : public Parent {
public:
LateContextFunctionDecorator(ManagedFnPtr f, CompilePass* p)
: Parent(f, p), contextCompiler(this, p) {
}
protected:
std::vector<llvm::Type*> prepareArguments() {
std::vector<llvm::Type*>&& 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;
}
llvm::Function::arg_iterator prepareBindings() {
llvm::Function::arg_iterator fargsI = Parent::prepareBindings();
size_t sizeLateContextDemand = contextCompiler.getFunctionDemandSize();
if (sizeLateContextDemand) {
fargsI->setName("latecontext");
contextCompiler.rawContextArgument = &*fargsI;
++fargsI;
}
return fargsI;
}
public:
context::LateContextCompiler2 contextCompiler;
};
}} //end of namespace xreate::context
namespace xreate { namespace compilation{
std::string
BasicFunctionUnit::prepareName(){
AST* ast = IFunctionUnit::pass->man->root;
string name = ast->getFunctionVariants(IFunctionUnit::function->__name).size() > 1 ?
IFunctionUnit::function->__name + std::to_string(IFunctionUnit::function.id()) :
IFunctionUnit::function->__name;
return name;
}
std::vector<llvm::Type*>
BasicFunctionUnit::prepareArguments() {
LLVMLayer* llvm = IFunctionUnit::pass->man->llvm;
AST* ast = IFunctionUnit::pass->man->root;
CodeScope* entry = IFunctionUnit::function->__entry;
std::vector<llvm::Type*> signature;
std::transform(entry->__bindings.begin(), entry->__bindings.end(), std::inserter(signature, signature.end()),
[llvm, ast, entry](const std::string & arg)->llvm::Type* {
assert(entry->__identifiers.count(arg));
ScopedSymbol argid{entry->__identifiers.at(arg), versions::VERSION_NONE};
return llvm->toLLVMType(ast->expandType(entry->__declarations.at(argid).type));
});
return signature;
}
llvm::Type*
BasicFunctionUnit::prepareResult() {
LLVMLayer* llvm = IFunctionUnit::pass->man->llvm;
AST* ast = IFunctionUnit::pass->man->root;
CodeScope* entry = IFunctionUnit::function->__entry;
return llvm->toLLVMType(ast->expandType(entry->__declarations.at(ScopedSymbol::RetSymbol).type));
}
llvm::Function::arg_iterator
BasicFunctionUnit::prepareBindings() {
CodeScope* entry = IFunctionUnit::function->__entry;
ICodeScopeUnit* entryCompilation = IFunctionUnit::getScopeUnit(entry);
llvm::Function::arg_iterator fargsI = IFunctionUnit::raw->arg_begin();
for (std::string &arg : entry->__bindings) {
ScopedSymbol argid{entry->__identifiers[arg], versions::VERSION_NONE};
entryCompilation->bindArg(&*fargsI, argid);
fargsI->setName(arg);
++fargsI;
}
return fargsI;
}
//DEBT compiler rigidly depends on exact definition of DefaultFunctionUnit
typedef context::LateContextFunctionDecorator<
adhoc::AdhocFunctionDecorator<
BasicFunctionUnit>> DefaultFunctionUnit;
ICodeScopeUnit::ICodeScopeUnit(CodeScope* codeScope, IFunctionUnit* f, CompilePass* compilePass)
: pass(compilePass), function(f), scope(codeScope) {
}
llvm::Value*
CallStatementRaw::operator()(std::vector<llvm::Value *>&& args, const std::string& hintDecl) {
llvm::Function* calleeInfo = dyn_cast<llvm::Function>(__callee);
if (calleeInfo) {
auto argsFormal = calleeInfo->args();
int pos = 0;
//SECTIONTAG types/convert function ret value
for (auto argFormal = argsFormal.begin(); argFormal != argsFormal.end(); ++argFormal, ++pos) {
args[pos] = typeinference::doAutomaticTypeConversion(args[pos], argFormal->getType(), llvm->builder);
}
}
return llvm->builder.CreateCall(__calleeTy, __callee, args, hintDecl);
}
//DESABLEDFEATURE implement inlining
class CallStatementInline : public CallStatement {
public:
CallStatementInline(IFunctionUnit* caller, IFunctionUnit* callee, LLVMLayer* l)
: __caller(caller), __callee(callee), llvm(l) {
}
llvm::Value* operator()(std::vector<llvm::Value *>&& args, const std::string& hintDecl) {
//TOTEST inlining
// CodeScopeUnit* entryCompilation = outer->getScopeUnit(function->__entry);
// for(int i=0, size = args.size(); i<size; ++i) {
// entryCompilation->bindArg(args.at(i), string(entryCompilation->scope->__bindings.at(i)));
// }
//
//
// return entryCompilation->compile();
return nullptr;
}
private:
IFunctionUnit* __caller;
IFunctionUnit* __callee;
LLVMLayer* llvm;
bool isInline() {
// Symbol ret = Symbol{0, function->__entry};
// bool flagOnTheFly = SymbolAttachments::get<IsImplementationOnTheFly>(ret, false);
//TODO consider inlining
return false;
}
};
BasicCodeScopeUnit::BasicCodeScopeUnit(CodeScope* codeScope, IFunctionUnit* f, CompilePass* compilePass)
: ICodeScopeUnit(codeScope, f, compilePass) {
}
llvm::Value*
BasicCodeScopeUnit::processSymbol(const Symbol& s, std::string hintRetVar) {
Expression declaration = CodeScope::getDeclaration(s);
CodeScope* scope = s.scope;
ICodeScopeUnit* self = ICodeScopeUnit::function->getScopeUnit(scope);
return self->process(declaration, hintRetVar);
}
//SECTIONTAG late-context find callee function
//TOTEST static late context decisions
//TOTEST dynamic late context decisions
CallStatement*
BasicCodeScopeUnit::findFunction(const std::string& calleeName) {
LLVMLayer* llvm = pass->man->llvm;
ClaspLayer* clasp = pass->man->clasp;
DefaultFunctionUnit* function = dynamic_cast<DefaultFunctionUnit*> (this->function);
context::ContextQuery* queryContext = pass->queryContext;
const std::list<ManagedFnPtr>& specializations = pass->man->root->getFunctionVariants(calleeName);
//if no specializations registered - check external function
if (specializations.size() == 0) {
llvm::Function* external = llvm->layerExtern->lookupFunction(calleeName);
llvm::outs() << "Debug/External function: " << calleeName;
external->getType()->print(llvm::outs(), true);
llvm::outs() << "\n";
return new CallStatementRaw(external, llvm);
}
//no decisions required
if (specializations.size() == 1) {
if (!specializations.front()->guardContext.isValid()) {
return new CallStatementRaw(pass->getFunctionUnit(specializations.front())->compile(), llvm);
}
}
//TODO move dictSpecialization over to a separate function in order to perform cache, etc.
//prepare specializations dictionary
std::map<Expression, ManagedFnPtr> dictSpecializations;
boost::optional<ManagedFnPtr> variantDefault;
boost::optional<ManagedFnPtr> variant;
for (const ManagedFnPtr& f : specializations) {
const Expression& guard = f->guardContext;
//default case:
if (!guard.isValid()) {
variantDefault = f;
continue;
}
assert(dictSpecializations.emplace(guard, f).second && "Found several identical specializations");
}
//check static context
ScopePacked scopeCaller = clasp->pack(this->scope);
const string atomSpecialization = "specialization";
const Expression topicSpecialization(Operator::CALL,{(Atom<Identifier_t>(string(atomSpecialization))),
Expression(Operator::CALL,
{Atom<Identifier_t>(string(calleeName))}),
Atom<Number_t>(scopeCaller)});
const context::Decisions& decisions = queryContext->getFinalDecisions(scopeCaller);
if (decisions.count(topicSpecialization)) {
variant = dictSpecializations.at(decisions.at(topicSpecialization));
}
//TODO check only demand for this particular topic.
size_t sizeDemand = function->contextCompiler.getFunctionDemandSize();
//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) {
IFunctionUnit* calleeUnit = pass->getFunctionUnit(variant ? *variant : *variantDefault);
//inlining possible based on static decision only
// if (calleeUnit->isInline()) {
// return new CallStatementInline(function, calleeUnit);
// }
return new CallStatementRaw(calleeUnit->compile(), llvm);
}
//require default variant if no static decision made
assert(variantDefault);
llvm::Function* functionVariantDefault = this->pass->getFunctionUnit(*variantDefault)->compile();
llvm::Value* resultFn = function->contextCompiler.findFunction(calleeName, functionVariantDefault, scopeCaller);
llvm::PointerType *resultPTy = cast<llvm::PointerType>(resultFn->getType());
llvm::FunctionType *resultFTy = cast<llvm::FunctionType>(resultPTy->getElementType());
return new CallStatementRaw(resultFn, resultFTy, llvm);
}
//DISABLEDFEATURE transformations
// if (pass->transformations->isAcceptable(expr)){
// return pass->transformations->transform(expr, result, ctx);
// }
llvm::Value*
BasicCodeScopeUnit::process(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;
xreate::compilation::Advanced instructions = xreate::compilation::Advanced({this, function, pass});
switch (expr.op) {
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 = typeinference::doAutomaticTypeConversion(right, left->getType(), l.builder);
break;
default:;
}
switch (expr.op) {
case Operator::ADD:
{
left = process(expr.operands[0]);
Context context{this, function, pass};
llvm::Value* resultSU = StructUpdate::add(expr.operands[0], left, expr.operands[1], context, DEFAULT("tmp_add"));
if (resultSU) return resultSU;
right = process(expr.operands[1]);
llvm::Value* resultAddPA = pointerarithmetic::PointerArithmetic::add(left, right, context, DEFAULT("tmp_add"));
if (resultAddPA) {
return resultAddPA;
}
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:
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();
shared_ptr<CallStatement> callee(findFunction(nameCallee));
//prepare arguments
std::vector<llvm::Value *> 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);
//TASK a) refactor CALL/ADHOC/find function
//SECTIONTAG late-context propagation arg
size_t calleeDemandSize = pass->queryContext->getFunctionDemand(nameCallee).size();
if (calleeDemandSize) {
DefaultFunctionUnit* function = dynamic_cast<DefaultFunctionUnit*> (this->function);
llvm::Value* argLateContext = function->contextCompiler.compileContextArgument(nameCallee, outerScopeId);
args.push_back(argLateContext);
}
return (*callee)(move(args), DEFAULT("res_" + nameCallee));
}
case Operator::IF:
{
return instructions.compileIf(expr, DEFAULT("tmp_if"));
}
case Operator::SWITCH:
{
return instructions.compileSwitch(expr, DEFAULT("tmp_switch"));
}
case Operator::LOOP_CONTEXT:
{
assert(false);
return nullptr;
//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.compileListAsSolidArray(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<TypeAnnotation> ExpandedType;
ExpandedType tyStructLiteral = l.ast->getType(expr);
const std::vector<string> fieldsFormal = (tyStructLiteral.get().__operator == TypeOperator::CUSTOM) ?
l.layerExtern->getStructFields(l.layerExtern->lookupType(tyStructLiteral.get().__valueCustom))
: tyStructLiteral.get().fields;
std::map<std::string, size_t> indexFields;
for (size_t i = 0, size = fieldsFormal.size(); i < size; ++i) {
indexFields.emplace(fieldsFormal[i], i);
}
llvm::StructType* tyLiteralRaw = llvm::cast<llvm::StructType>(l.toLLVMType(tyStructLiteral));
llvm::Value* record = llvm::UndefValue::get(tyLiteralRaw);
for (size_t i = 0; i < expr.operands.size(); ++i) {
const Expression& operand = expr.operands.at(i);
unsigned int fieldId = indexFields.at(expr.bindings.at(i));
llvm::Value* result = 0;
//TODO Null ad hoc llvm implementation (related code: operators/StructUpdate/add)
// if (operand.isNone()){
// llvm::Type* tyNullField = tyRecord->getElementType(fieldId);
// result = llvm::UndefValue::get(tyNullField);
//
// } else {
result = process(operand);
// }
assert(result);
record = l.builder.CreateInsertValue(record, result, llvm::ArrayRef<unsigned>({fieldId}));
}
return record;
};
case Operator::MAP:
{
assert(expr.blocks.size());
return instructions.compileMapSolidOutput(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() == 2);
assert(expr.operands[0].__state == Expression::IDENT);
const std::string& hintIdent = expr.operands[0].getValueString();
Symbol s = Attachments::get<Symbol>(expr.operands[0]);
const ExpandedType& t2 = pass->man->root->getType(expr.operands[0]);
llvm::Value* aggr = processSymbol(s, hintIdent);
switch (t2.get().__operator) {
case TypeOperator::STRUCT: case TypeOperator::CUSTOM:
{
std::string idxField;
const Expression& idx = expr.operands.at(1);
switch (idx.__state) {
//named struct field
case Expression::STRING:
idxField = idx.getValueString();
break;
//anonymous struct field
case Expression::NUMBER:
idxField = to_string((int) idx.getValueDouble());
break;
default:
assert(false && "Wrong index for a struct");
}
return instructions.compileStructIndex(aggr, t2, idxField);
};
case TypeOperator::ARRAY:
{
std::vector<llvm::Value*> indexes;
std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()),
[this] (const Expression & op) {
return process(op);
}
);
return instructions.compileArrayIndex(aggr, indexes, DEFAULT(string("el_") + hintIdent));
};
default:
assert(false);
}
};
//SECTIONTAG adhoc actual compilation
//TODO a) make sure that it's correct: function->adhocImplementation built for Entry scope and used in another scope
case Operator::ADHOC:
{
DefaultFunctionUnit* function = dynamic_cast<DefaultFunctionUnit*> (this->function);
assert(function->adhocImplementation && "Adhoc implementation not found");
const Expression& comm = adhoc::AdhocExpression(expr).getCommand();
CodeScope* scope = function->adhocImplementation->getCommandImplementation(comm);
ICodeScopeUnit* unitScope = function->getScopeUnit(scope);
//SECTIONTAG types/convert ADHOC ret convertation
llvm::Type* resultTy = l.toLLVMType(pass->man->root->expandType(function->adhocImplementation->getResultType()));
return typeinference::doAutomaticTypeConversion(unitScope->compile(), resultTy, l.builder);
};
case Operator::CALL_INTRINSIC:
{
const std::string op = expr.getValueString();
if (op == "copy") {
llvm::Value* result = process(expr.getOperands().at(0));
auto decoratorVersions = Decorators<VersionsScopeDecoratorTag>::getInterface(this);
llvm::Value* storage = decoratorVersions->processIntrinsicInit(result->getType());
decoratorVersions->processIntrinsicCopy(result, storage);
return l.builder.CreateLoad(storage, hintVarDecl);
}
assert(false && "undefined intrinsic");
}
case Operator::VARIANT:
{
//TASK Variant compilation to implement
assert(false&& "Variant compilation not implemented yet");
return nullptr;
// const ExpandedType& typVariant = pass->man->root->getType(expr);
// llvm::Type* typRaw = l.toLLVMType(typVariant);
// int value = expr.getValueDouble();
// return llvm::ConstantInt::get(typRaw, value);
}
case Operator::NONE:
assert(expr.__state != Expression::COMPOUND);
switch (expr.__state) {
case Expression::IDENT:
{
Symbol s = Attachments::get<Symbol>(expr);
return processSymbol(s, expr.getValueString());
}
case Expression::NUMBER:
{
llvm::Type* typConst;
if (expr.type.isValid()) {
typConst = l.toLLVMType(pass->man->root->getType(expr));
} else {
typConst = llvm::Type::getInt32Ty(llvm::getGlobalContext());
}
int literal = expr.getValueDouble();
return llvm::ConstantInt::get(typConst, literal);
}
case Expression::STRING:
{
return instructions.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str"));
};
default:
{
break;
}
};
break;
default: break;
}
assert(false && "Can't compile expression");
return 0;
}
llvm::Value*
BasicCodeScopeUnit::compile(const std::string& hintBlockDecl) {
if (!hintBlockDecl.empty()) {
llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm::getGlobalContext(), hintBlockDecl, function->raw);
pass->man->llvm->builder.SetInsertPoint(block);
}
Symbol symbScope = Symbol{ScopedSymbol::RetSymbol, scope};
return processSymbol(symbScope);
}
ICodeScopeUnit::~ICodeScopeUnit() {
}
IFunctionUnit::~IFunctionUnit() {
}
llvm::Function*
IFunctionUnit::compile() {
if (raw != nullptr) return raw;
LLVMLayer* llvm = pass->man->llvm;
llvm::IRBuilder<>& builder = llvm->builder;
string&& functionName = prepareName();
std::vector<llvm::Type*>&& types = prepareArguments();
llvm::Type* expectedResultType = prepareResult();
llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false);
raw = llvm::cast<llvm::Function>(llvm->module->getOrInsertFunction(functionName, ft));
prepareBindings();
const std::string&blockName = "entry";
llvm::BasicBlock* blockCurrent = builder.GetInsertBlock();
llvm::Value* result = getScopeUnit(function->__entry)->compile(blockName);
assert(result);
//SECTIONTAG types/convert function ret value
builder.CreateRet(typeinference::doAutomaticTypeConversion(result, expectedResultType, llvm->builder));
if (blockCurrent) {
builder.SetInsertPoint(blockCurrent);
}
llvm->moveToGarbage(ft);
return raw;
}
ICodeScopeUnit*
IFunctionUnit::getScopeUnit(CodeScope* scope) {
if (__scopes.count(scope)) {
auto result = __scopes.at(scope).lock();
if (result) {
return result.get();
}
}
std::shared_ptr<ICodeScopeUnit> unit(pass->buildCodeScopeUnit(scope, this));
if (scope->__parent != nullptr) {
auto parentUnit = Decorators<CachedScopeDecoratorTag>::getInterface(getScopeUnit(scope->__parent));
parentUnit->registerChildScope(unit);
} else {
__orphanedScopes.push_back(unit);
}
if (!__scopes.emplace(scope, unit).second) {
__scopes[scope] = unit;
}
return unit.get();
}
ICodeScopeUnit*
IFunctionUnit::getScopeUnit(ManagedScpPtr scope) {
return getScopeUnit(&*scope);
}
ICodeScopeUnit*
IFunctionUnit::getEntry() {
return getScopeUnit(function->getEntryScope());
}
template<>
compilation::IFunctionUnit*
CompilePassCustomDecorators<void, void>::buildFunctionUnit(const ManagedFnPtr& function){
return new DefaultFunctionUnit(function, this);
}
template<>
compilation::ICodeScopeUnit*
CompilePassCustomDecorators<void, void>::buildCodeScopeUnit(CodeScope* scope, IFunctionUnit* function){
return new DefaultCodeScopeUnit(scope, function, this);
}
} // emf of compilation
IFunctionUnit*
CompilePass::getFunctionUnit(const ManagedFnPtr& function) {
unsigned int id = function.id();
if (!functions.count(id)) {
IFunctionUnit* unit = buildFunctionUnit(function);
functions.emplace(id, unit);
return unit;
}
return functions.at(id);
}
void
CompilePass::run() {
managerTransformations = new TransformationsManager();
targetInterpretation = new interpretation::TargetInterpretation(this->man->root, this);
queryContext = reinterpret_cast<context::ContextQuery*> (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<std::string>(model->first->second));
IFunctionUnit* 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 context::ContextQuery(), QueryId::ContextQuery);
}
} //end of namespace xreate
diff --git a/cpp/src/pass/compilepass.h b/cpp/src/pass/compilepass.h
index 0649df6..08112b7 100644
--- a/cpp/src/pass/compilepass.h
+++ b/cpp/src/pass/compilepass.h
@@ -1,183 +1,192 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ *
+ * compilepass.h
+ */
+
#ifndef COMPILEPASS_H
#define COMPILEPASS_H
#include "abstractpass.h"
#include "llvm/IR/Function.h"
namespace xreate {
class ClaspLayer;
class CompilePass;
class LLVMLayer;
namespace adhoc{
class AdhocScheme;
}
namespace context{
class ContextQuery;
class LateContextCompiler2;
}
namespace interpretation{
class TargetInterpretation;
}
}
namespace xreate { namespace compilation {
class ICodeScopeUnit;
class IFunctionUnit;
class TransformationsManager;
struct Context{
ICodeScopeUnit* scope;
IFunctionUnit* function;
CompilePass* pass;
};
class CallStatement {
public:
virtual llvm::Value* operator() (std::vector<llvm::Value *>&& args, const std::string& hintDecl="") = 0;
};
class CallStatementRaw: public CallStatement{
public:
CallStatementRaw(llvm::Function* callee, LLVMLayer* l)
: __callee(callee), __calleeTy(callee->getFunctionType()), llvm(l) {}
CallStatementRaw(llvm::Value* callee, llvm::FunctionType* ty, LLVMLayer* l)
: __callee(callee), __calleeTy(ty), llvm(l) {}
llvm::Value* operator() (std::vector<llvm::Value *>&& args, const std::string& hintDecl="");
private:
llvm::Value* __callee;
llvm::FunctionType* __calleeTy;
LLVMLayer* llvm;
};
class ICodeScopeUnit{
public:
CompilePass* const pass;
IFunctionUnit* const function;
CodeScope* const scope;
ICodeScopeUnit(CodeScope* codeScope, IFunctionUnit* f, CompilePass* compilePass);
virtual ~ICodeScopeUnit();
virtual llvm::Value* compile(const std::string& hintBlockDecl="")=0;
virtual llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar="")=0;
virtual llvm::Value* process(const Expression& expr, const std::string& hintVarDecl="")=0;
virtual void bindArg(llvm::Value* value, std::string&& alias)=0;
virtual void bindArg(llvm::Value* value, const ScopedSymbol& s)=0;
protected:
virtual CallStatement* findFunction(const std::string& callee)=0;
};
class BasicCodeScopeUnit: public ICodeScopeUnit{
public:
BasicCodeScopeUnit(CodeScope* codeScope, IFunctionUnit* f, CompilePass* compilePass);
llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar="") override;
llvm::Value* process(const Expression& expr, const std::string& hintVarDecl="") override;
llvm::Value* compile(const std::string& hintBlockDecl="") override;
protected:
CallStatement* findFunction(const std::string& callee) override;
};
class IFunctionUnit{
public:
IFunctionUnit(ManagedFnPtr f, CompilePass* p): function(f), pass(p) {}
virtual ~IFunctionUnit();
llvm::Function* compile();
ICodeScopeUnit* getEntry();
ICodeScopeUnit* getScopeUnit(CodeScope* scope);
ICodeScopeUnit* getScopeUnit(ManagedScpPtr scope);
ManagedFnPtr function;
llvm::Function* raw = nullptr;
protected:
CompilePass* pass=nullptr;
virtual std::string prepareName() = 0;
virtual std::vector<llvm::Type*> prepareArguments() = 0;
virtual llvm::Type* prepareResult() = 0;
virtual llvm::Function::arg_iterator prepareBindings() = 0;
private:
std::map<CodeScope*, std::weak_ptr<ICodeScopeUnit>> __scopes;
std::list<std::shared_ptr<ICodeScopeUnit>> __orphanedScopes;
};
class BasicFunctionUnit: public IFunctionUnit{
public:
BasicFunctionUnit(ManagedFnPtr f, CompilePass* p)
: IFunctionUnit(f, p) {}
protected:
std::string prepareName() override;
virtual std::vector<llvm::Type*> prepareArguments() override;
virtual llvm::Type* prepareResult() override;
virtual llvm::Function::arg_iterator prepareBindings() override;
};
} // end of namespace compilation
class CompilePass : public AbstractPass<void> {
friend class context::LateContextCompiler2;
friend class compilation::BasicCodeScopeUnit;
friend class compilation::IFunctionUnit;
public:
compilation::TransformationsManager* managerTransformations;
interpretation::TargetInterpretation* targetInterpretation;
CompilePass(PassManager* manager): AbstractPass<void>(manager) {}
compilation::IFunctionUnit* getFunctionUnit(const ManagedFnPtr& function);
void run() override;
llvm::Function* getEntryFunction();
static void prepareQueries(ClaspLayer* clasp);
public:
virtual compilation::IFunctionUnit* buildFunctionUnit(const ManagedFnPtr& function)=0;
virtual compilation::ICodeScopeUnit* buildCodeScopeUnit(CodeScope* scope, compilation::IFunctionUnit* function)=0;
private:
//TODO free `functions` in destructor
std::map<unsigned int, compilation::IFunctionUnit*> functions;
llvm::Function* entry = 0;
context::ContextQuery* queryContext;
};
namespace compilation{
template<class FUNCTION_DECORATOR=void, class SCOPE_DECORATOR=void>
class CompilePassCustomDecorators: public ::xreate::CompilePass{
public:
CompilePassCustomDecorators(PassManager* manager): ::xreate::CompilePass(manager) {}
virtual compilation::IFunctionUnit* buildFunctionUnit(const ManagedFnPtr& function) override{
return new FUNCTION_DECORATOR(function, this);
}
virtual compilation::ICodeScopeUnit* buildCodeScopeUnit(CodeScope* scope, IFunctionUnit* function) override{
return new SCOPE_DECORATOR(scope, function, this);
}
};
template<>
compilation::IFunctionUnit*
CompilePassCustomDecorators<void, void>::buildFunctionUnit(const ManagedFnPtr& function);
template<>
compilation::ICodeScopeUnit*
CompilePassCustomDecorators<void, void>::buildCodeScopeUnit(CodeScope* scope, IFunctionUnit* function);
}} //end of namespace xreate::compilation
#endif // COMPILEPASS_H
diff --git a/cpp/src/pass/dfapass.cpp b/cpp/src/pass/dfapass.cpp
index 47f2ec0..749ec9a 100644
--- a/cpp/src/pass/dfapass.cpp
+++ b/cpp/src/pass/dfapass.cpp
@@ -1,262 +1,271 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ *
+ * dfapass.cpp
+ */
+
#include "pass/dfapass.h"
#include "analysis/dfagraph.h"
#include "xreatemanager.h"
#include "clasplayer.h"
#include <boost/format.hpp>
using namespace std;
namespace xreate { namespace dfa {
class DfaExpressionProcessor {
std::vector<SymbolNode> operands;
std::vector<SymbolPacked> blocks;
const Expression expression;
SymbolNode result;
DFAPass * const pass;
const PassContext context;
public:
DfaExpressionProcessor(const Expression& expr, SymbolNode resInitial, DFAPass * const p, const PassContext c)
: expression(expr), result(resInitial), pass(p), context(c) {
operands.reserve(expression.getOperands().size());
for (const Expression &op : expression.getOperands()) {
SymbolAnonymous symbOp(op.id);
operands.push_back(DfaExpressionProcessor(op, symbOp, pass, context).process());
}
blocks.reserve(expression.blocks.size());
for (CodeScope* scope : expression.blocks) {
blocks.push_back(pass->process(scope, context));
}
}
SymbolNode
process() {
if (expression.__state == Expression::COMPOUND) {
processCompoundOp();
} else {
processElementaryOp();
}
applySignatureAnnotations();
applyInPlaceAnnotations();
return result;
}
private:
void
processElementaryOp() {
switch (expression.__state) {
case Expression::IDENT:
{
SymbolPacked symbFrom = pass->processSymbol(Attachments::get<Symbol>(expression), context, expression.getValueString());
SymbolPacked* symbTo = boost::get<SymbolPacked>(&result);
if (symbTo) {
pass->__context.graph->addConnection(*symbTo, SymbolNode(symbFrom), DFGConnection::STRONG);
} else {
result = SymbolNode(symbFrom);
}
break;
}
default: break;
}
}
void
processCompoundOp() {
switch (expression.op) {
//DEBT provide CALL processing
// case Operator::CALL: {
// const string &nameCalleeFunction = expression.getValueString();
//
// //TODO implement processFnCall/Uncertain
// list<ManagedFnPtr> variantsCalleeFunction = man->root->getFunctionVariants(nameCalleeFunction);
// if (variantsCalleeFunction.size()!=1) return;
// ManagedFnPtr function= variantsCalleeFunction.front();
//
// // set calling relations:
// CodeScope *scopeRemote = function->getEntryScope();
// std::vector<SymbolNode>::iterator nodeActual = cache.operands.begin();
// for (const std::string &identFormal: scopeRemote->__bindings){
// const ScopedSymbol symbolFormal{scopeRemote->__identifiers.at(identFormal), versions::VERSION_NONE};
//
// __context.graph->addConnection(clasp->pack(Symbol{symbolFormal, scopeRemote}, nameCalleeFunction + ":" + identFormal), *nodeActual, DFGConnection::WEAK);
// ++nodeActual;
// }
//
// //TODO add RET connection
// break;
// }
//MAP processing: apply PROTOTYPE relation
case Operator::MAP:
{
SymbolNode nodeFrom = operands.front();
SymbolPacked* nodeTo = boost::get<SymbolPacked>(&result);
assert(nodeTo);
pass->__context.graph->addConnection(*nodeTo, nodeFrom, DFGConnection::PROTOTYPE);
break;
}
default: break;
}
}
void
applySignatureAnnotations() {
if (pass->__signatures.count(expression.op)) {
const Expression &scheme = pass->__signatures.at(expression.op);
std::vector<SymbolNode>::iterator arg = operands.begin();
std::vector<Expression>::const_iterator tag = scheme.getOperands().begin();
//Assign scheme RET annotation
Expression retTag = *scheme.getOperands().begin();
if (retTag.__state != Expression::INVALID) {
pass->__context.graph->addAnnotation(result, move(retTag));
}
++tag;
while (tag != scheme.getOperands().end()) {
if (tag->__state != Expression::INVALID) {
pass->__context.graph->addAnnotation(*arg, Expression(*tag));
}
++arg;
++tag;
}
// TODO add possibility to have specific 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, ""));
// }
}
}
void
applyInPlaceAnnotations() {
// write down in-place expression tags:
for (pair<std::string, Expression> tag : expression.tags) {
pass->__context.graph->addAnnotation(result, Expression(tag.second));
}
}
};
DFAPass::DFAPass(PassManager* manager)
: AbstractPass(manager)
, __context{new DFAGraph(manager->clasp)}
, clasp(manager->clasp)
{}
SymbolPacked
DFAPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl) {
const SymbolPacked& symbRet = AbstractPass::process(scope, context, hintBlockDecl);
return symbRet;
}
SymbolPacked
DFAPass::processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol) {
const Expression& declaration = CodeScope::getDeclaration(symbol);
const SymbolPacked& symbPacked = clasp->pack(symbol, hintSymbol);
DfaExpressionProcessor(declaration, symbPacked, this, context).process();
return symbPacked;
}
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() {
clasp->setDFAData(move(__context.graph));
}
} //end of namespace dfa
template<>
SymbolPacked defaultValue(){
assert(false);
}
} //xreate namespace
//DEBT represent VersionaPass in declarative form using applyDependencies
// applyDependencies(expression, context, cache, decl);
//DEBT prepare static annotations and represent InterpretationPass in declarative form
// applyStaticAnnotations(expression, context, cache, decl);
//TODO Null ad hoc DFG implementation/None symbol
//DISABLEDFEATURE None value
// if (expression.isNone()){
// return SymbolTransient{{Atom<Identifier_t>(Config::get("clasp.nonevalue"))}};
// }
// non initialized(SymbolInvalid) value
//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: {
// SymbolNode identSymbol = clasp->pack(Attachments::get<Symbol>(expression), context.function->getName() + ":" + expression.getValueString());
// __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<Identifier_t>("static")));
// break;
//
// default: break;
// }
//}
diff --git a/cpp/src/pass/dfapass.h b/cpp/src/pass/dfapass.h
index 5572eaa..926e9f3 100644
--- a/cpp/src/pass/dfapass.h
+++ b/cpp/src/pass/dfapass.h
@@ -1,41 +1,49 @@
-// Data Flow Graph determination pass
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ *
+ * dfapass.h
+ * Data Flow Graph building pass
+ */
#ifndef DFGPASS_H
#define DFGPASS_H
#include "abstractpass.h"
#include "analysis/dfagraph.h"
namespace xreate {
class ClaspLayer;
}
namespace xreate { namespace dfa {
class DfaExpressionProcessor;
class DFAPass: public AbstractPass<SymbolPacked> {
friend class DfaExpressionProcessor;
public:
DFAPass(PassManager* manager);
SymbolPacked processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol="") override;
SymbolPacked process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl="") override;
void init();
void run() override;
void finish() override;
private:
struct
{
DFAGraph* graph;
} __context;
std::map<Operator, Expression> __signatures; //DFA data for particular operators
ClaspLayer* clasp;
};
}} //end of xreate::dfa namespace
#endif
diff --git a/cpp/src/pass/interpretationpass.cpp b/cpp/src/pass/interpretationpass.cpp
index 6fd6cfd..f9a4858 100644
--- a/cpp/src/pass/interpretationpass.cpp
+++ b/cpp/src/pass/interpretationpass.cpp
@@ -1,448 +1,451 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* File: interpretationpass.cpp
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*
* Created on July 5, 2016, 5:21 PM
*/
#include "pass/interpretationpass.h"
//#include "compilation/transformations.h"
#include <compilation/targetinterpretation.h>
#include <bits/stl_vector.h>
#include "ast.h"
//DEBT implement InterpretationPass purely in clasp
//DEBT represent InterpretationPass as general type inference
using namespace std;
namespace xreate{
template<>
interpretation::InterpretationResolution
defaultValue<interpretation::InterpretationResolution>(){
return interpretation::CMPL_ONLY;
}
namespace interpretation{
enum InterpretationQuery{QUERY_INTR_ONLY, QUERY_CMPL_ONLY};
namespace details {
template<InterpretationQuery FLAG_REQUIRED>
bool checkConstraints(InterpretationResolution flag) {
return ( (flag==INTR_ONLY && FLAG_REQUIRED == QUERY_INTR_ONLY)
|| (flag==CMPL_ONLY && FLAG_REQUIRED == QUERY_CMPL_ONLY));
}
InterpretationResolution
recognizeTags(const map<std::string, Expression>& tags){
auto i = tags.find("interpretation");
if (i== tags.end()){
return ANY;
}
assert(i->second.op == Operator::CALL);
const string& cmd = i->second.operands.at(0).getValueString();
//TODO make consistent names of annotation and resolution
if (cmd == "force"){
return INTR_ONLY;
} else if (cmd == "suppress"){
return CMPL_ONLY;
}
return ANY;
}
}
InterpretationResolution
unify(InterpretationResolution flag) {
return flag;
}
template<typename FLAG_A, typename FLAG_B, typename... FLAGS>
InterpretationResolution
unify(FLAG_A flagA, FLAG_B flagB, FLAGS... flags) {
if (flagA== ANY){
return unify(flagB, flags...);
}
if (flagB == ANY) {
return unify(flagA, flags...);
}
assert(flagA == flagB);
return flagA;
}
template<InterpretationQuery FLAG_REQUIRED>
bool checkConstraints(std::vector<InterpretationResolution>&& flags) {
assert(flags.size());
InterpretationResolution flag = flags.front();
return details::checkConstraints<FLAG_REQUIRED>(flag);
}
template<InterpretationQuery FLAG_REQUIRED_A, InterpretationQuery FLAG_REQUIRED_B, InterpretationQuery... FLAGS>
bool checkConstraints(std::vector<InterpretationResolution>&& flags) {
assert(flags.size());
InterpretationResolution flag = flags.front();
flags.pop_back();
if (details::checkConstraints<FLAG_REQUIRED_A>(flag)){
return checkConstraints<FLAG_REQUIRED_B, FLAGS...>(move(flags));
}
return false;
}
bool
InterpretationData::isDefault() const{
return (resolution == ANY && op == NONE);
}
void
recognizeTags(const Expression& e){
InterpretationData tag{details::recognizeTags(e.tags), NONE};
if (!tag.isDefault())
Attachments::put<InterpretationData>(e, tag);
}
InterpretationResolution
recognizeTags(const ManagedFnPtr& f){
return details::recognizeTags(f->getTags());
}
InterpretationPass::InterpretationPass(PassManager* manager)
: AbstractPass(manager) {
Attachments::init<FunctionInterpretationData>();
Attachments::init<InterpretationData>();
}
void InterpretationPass::run(){
ManagedFnPtr f = man->root->begin<Function>();
auto& visitedSymbols = getSymbolCache();
while (f.isValid()) {
const Symbol& symbolFunction{ScopedSymbol::RetSymbol, f->getEntryScope()};
if (!visitedSymbols.isCached(symbolFunction)){
visitedSymbols.setCachedValue(symbolFunction, process(f));
}
++f;
}
}
InterpretationResolution
InterpretationPass::process(const Expression& expression, PassContext context, const std::string& decl){
recognizeTags(expression);
InterpretationResolution resolution = ANY;
InterpretationOperator op = NONE;
switch (expression.__state){
case Expression::NUMBER:
case Expression::STRING: {
break;
}
case Expression::IDENT: {
resolution = Parent::processSymbol(Attachments::get<Symbol>(expression), context);
break;
}
case Expression::COMPOUND:
break;
default: { resolution = CMPL_ONLY; break;}
}
if (expression.__state == Expression::COMPOUND)
switch(expression.op){
case Operator::EQU:
case Operator::NE: {
InterpretationResolution left = process(expression.operands[0], context);
InterpretationResolution right = process(expression.operands[1], context);
resolution = unify(left, right);
break;
}
case Operator::LOGIC_AND: {
assert(expression.operands.size() == 1);
resolution = process (expression.operands[0], context);
break;
}
case Operator::CALL: {
//TODO cope with static/dynamic context
//TODO BUG here: if several variants they all are processed as CMPL careless of signature
list<ManagedFnPtr> callees = man->root->getFunctionVariants(expression.getValueString());
if (callees.size()!=1){
resolution = CMPL_ONLY;
break;
}
ManagedFnPtr callee = callees.front();
const Symbol& symbCalleeFunc{ScopedSymbol::RetSymbol, callee->getEntryScope()};
//recursion-aware processing:
// - skip self recursion
const Symbol& symbSelfFunc{ScopedSymbol::RetSymbol, context.function->getEntryScope()};
if (!(symbSelfFunc == symbCalleeFunc)){
InterpretationResolution resCallee = processFnCall(callee, context);
assert(resCallee != FUNC_POSTPONED && "Indirect recursion detected: can't decide on interpretation resolution");
resolution = unify(resolution, resCallee);
}
//check arguments compatibility
const FunctionInterpretationData& calleeSignature = FunctionInterpretationHelper::getSignature(callee);
for (size_t op=0, size = expression.operands.size(); op < size; ++op){
const Expression &operand = expression.operands[op];
InterpretationResolution argActual = process(operand, context);
InterpretationResolution argExpected = calleeSignature.signature[op];
//TODO use args unification result to properly process function call
unify(argActual, argExpected);
}
if (FunctionInterpretationHelper::needPartialInterpretation(callee)){
op= CALL_INTERPRET_PARTIAL;
}
break;
}
case Operator::IF:{
InterpretationResolution flagCondition = process(expression.getOperands()[0], context);
InterpretationResolution flagScope1 = Parent::process(expression.blocks.front(), context);
InterpretationResolution flagScope2 = Parent::process(expression.blocks.back(), context);
//special case: IF_INTERPRET_CONDITION
if (checkConstraints<QUERY_INTR_ONLY>({flagCondition})){
op= IF_INTERPRET_CONDITION;
flagCondition = ANY;
}
resolution = unify(flagCondition, flagScope1, flagScope2);
break;
}
case Operator::FOLD: {
InterpretationResolution flagInput = process(expression.getOperands()[0], context);
InterpretationResolution flagAccumInit = process(expression.getOperands()[1], context);
CodeScope* scopeBody = expression.blocks.front();
const std::string& nameEl = expression.bindings[0];
Symbol symbEl{ScopedSymbol{scopeBody->__identifiers.at(nameEl), versions::VERSION_NONE}, scopeBody};
getSymbolCache().setCachedValue(symbEl, InterpretationResolution(flagInput));
const std::string& nameAccum = expression.bindings[1];
Symbol symbAccum{ScopedSymbol{scopeBody->__identifiers.at(nameAccum), versions::VERSION_NONE}, scopeBody};
getSymbolCache().setCachedValue(symbAccum, InterpretationResolution(flagAccumInit));
InterpretationResolution flagBody = Parent::process(expression.blocks.front(), context);
//special case: FOLD_INTERPRET_INPUT
if (checkConstraints<QUERY_INTR_ONLY>({flagInput})){
op= FOLD_INTERPRET_INPUT;
flagInput = ANY;
}
resolution = unify(flagInput, flagAccumInit, flagBody);
break;
}
case Operator::INDEX: {
resolution = unify(
process(expression.operands[0], context),
process(expression.operands[1], context)
);
break;
}
case Operator::SWITCH: {
InterpretationResolution flagCondition = process(expression.operands[0], context);
bool hasDefaultCase = expression.operands[1].op == Operator::CASE_DEFAULT;
//determine conditions resolution
InterpretationResolution flagHeaders = flagCondition;
for (size_t size = expression.operands.size(), i= hasDefaultCase? 2: 1; i<size; ++i){
const Expression& exprCase = expression.operands[i];
flagHeaders = unify(flagHeaders, Parent::process(exprCase.blocks.front(), context));
}
if (checkConstraints<QUERY_INTR_ONLY>({flagHeaders})){
op= SWITCH_INTERPRET_CONDITION;
flagHeaders = ANY;
}
//determine body resolutions
resolution = flagHeaders;
for (size_t size = expression.operands.size(), i= 1; i<size; ++i){
const Expression& exprCase = expression.operands[i];
resolution = unify(resolution, Parent::process(exprCase.blocks.back(), context));
}
break;
}
case Operator::SWITCH_VARIANT: {
InterpretationResolution resolutionCondition = process(expression.operands.at(0), context);
resolution= resolutionCondition;
if (checkConstraints<QUERY_INTR_ONLY>({resolution})){
op= SWITCH_VARIANT;
resolution = ANY;
}
const string identCondition = expression.bindings.front();
for(auto scope: expression.blocks){
//set binding resolution
ScopedSymbol symbolInternal = scope->getSymbol(identCondition);
getSymbolCache().setCachedValue(Symbol{symbolInternal, scope}, InterpretationResolution(resolutionCondition));
resolution = unify(resolution, Parent::process(scope, context));
}
for(auto scope: expression.blocks){
resolution = unify(resolution, Parent::process(scope, context));
}
break;
}
case Operator::LIST:
case Operator::LIST_NAMED: {
for (const Expression &op: expression.getOperands()) {
resolution = unify(resolution, process(op, context));
}
break;
}
case Operator::VARIANT: {
if(expression.getOperands().size()){
resolution = process(expression.getOperands().front(), context);
} else {
resolution = ANY;
}
break;
}
default: {
resolution = CMPL_ONLY;
for (const Expression &op: expression.getOperands()) {
process(op, context);
}
for (CodeScope* scope: expression.blocks) {
Parent::process(scope, context);
}
break;
}
}
InterpretationResolution resolutionExpected =
Attachments::get<InterpretationData>(expression, {ANY, NONE}).resolution;
resolution = unify(resolution, resolutionExpected);
if (resolution != resolutionExpected && (op!=NONE || resolution == INTR_ONLY)){
Attachments::put<InterpretationData>(expression, {resolution, op});
}
return resolution;
}
InterpretationResolution
InterpretationPass::processFnCall(ManagedFnPtr function, PassContext context){
return process(function);
}
InterpretationResolution
InterpretationPass::process(ManagedFnPtr function){
CodeScope* entry = function->getEntryScope();
std::vector<std::string> arguments = entry->__bindings;
const Symbol& symbSelfFunc{ScopedSymbol::RetSymbol, function->getEntryScope()};
auto& cache = getSymbolCache();
if (cache.isCached(symbSelfFunc))
return cache.getCachedValue(symbSelfFunc);
const FunctionInterpretationData& fnSignature = FunctionInterpretationHelper::getSignature(function);
InterpretationResolution fnResolutionExpected = details::recognizeTags(function->getTags());
//mark preliminary function resolution as expected
if (fnResolutionExpected != ANY){
cache.setCachedValue(symbSelfFunc, move(fnResolutionExpected));
} else {
// - in order to recognize indirect recursion mark this function resolution as POSTPONED
cache.setCachedValue(symbSelfFunc, FUNC_POSTPONED);
}
//set resolution for function arguments as expected
for (int argNo = 0, size = arguments.size(); argNo< size; ++argNo){
Symbol symbArg{ScopedSymbol{entry->__identifiers.at(arguments[argNo]), versions::VERSION_NONE}, entry};
cache.setCachedValue(symbArg, InterpretationResolution(fnSignature.signature[argNo]));
}
PassContext context;
context.function = function;
context.scope = entry;
InterpretationResolution resActual = process(CodeScope::getDeclaration(symbSelfFunc), context);
resActual = unify(resActual, fnResolutionExpected);
return cache.setCachedValue(symbSelfFunc, move(resActual));
}
const FunctionInterpretationData
FunctionInterpretationHelper::getSignature(ManagedFnPtr function){
if (Attachments::exists<FunctionInterpretationData>(function)){
return Attachments::get<FunctionInterpretationData>(function);
}
FunctionInterpretationData&& data = recognizeSignature(function);
Attachments::put<FunctionInterpretationData>(function, data);
return data;
}
FunctionInterpretationData
FunctionInterpretationHelper::recognizeSignature(ManagedFnPtr function){
CodeScope* entry = function->__entry;
FunctionInterpretationData result;
result.signature.reserve(entry->__bindings.size());
bool flagPartialInterpretation = false;
for(size_t no=0, size=entry->__bindings.size(); no < size; ++no){
const std::string& argName = entry->__bindings[no];
Symbol symbArg{ScopedSymbol{entry->__identifiers.at(argName), versions::VERSION_NONE}, entry};
const Expression& arg = CodeScope::getDeclaration(symbArg);
InterpretationResolution argResolution = details::recognizeTags(arg.tags);
flagPartialInterpretation |= (argResolution == INTR_ONLY);
result.signature.push_back(argResolution);
}
result.flagPartialInterpretation = flagPartialInterpretation;
return result;
}
bool FunctionInterpretationHelper::needPartialInterpretation(ManagedFnPtr function){
const FunctionInterpretationData& data = getSignature(function);
return data.flagPartialInterpretation;
}
}} //end of namespace xreate::interpretation
diff --git a/cpp/src/pass/interpretationpass.h b/cpp/src/pass/interpretationpass.h
index 5a2b229..e2935fa 100644
--- a/cpp/src/pass/interpretationpass.h
+++ b/cpp/src/pass/interpretationpass.h
@@ -1,87 +1,90 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* File: interpretationpass.h
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*
* Created on July 5, 2016, 5:21 PM
*/
#ifndef INTERPRETATIONPASS_H
#define INTERPRETATIONPASS_H
#include "abstractpass.h"
#include <map>
#ifndef FRIENDS_INTERPRETATION_TESTS
#define FRIENDS_INTERPRETATION_TESTS
#endif
//TODO refactor interpretation. Get rid of InterpretationOperator, put only one operator - Hybrid.
namespace xreate{ namespace interpretation{
enum InterpretationResolution{ANY, INTR_ONLY, CMPL_ONLY, FUNC_POSTPONED};
enum InterpretationOperator{NONE, IF_INTERPRET_CONDITION, FOLD_INTERPRET_INPUT, SWITCH_INTERPRET_CONDITION, SWITCH_VARIANT, CALL_INTERPRET_PARTIAL};
struct InterpretationData{
InterpretationResolution resolution;
InterpretationOperator op;
bool isDefault() const;
};
struct FunctionInterpretationData{
typedef std::vector<InterpretationResolution> Signature;
Signature signature;
bool flagPartialInterpretation;
};
class FunctionInterpretationHelper {
public:
static const FunctionInterpretationData
getSignature(ManagedFnPtr function);
static bool needPartialInterpretation(ManagedFnPtr function);
private:
static FunctionInterpretationData recognizeSignature(ManagedFnPtr function);
};
class InterpretationPass: public AbstractPass<InterpretationResolution> {
typedef AbstractPass<InterpretationResolution> Parent;
public:
InterpretationResolution process(const Expression& expression, PassContext context, const std::string& varDecl="") override;
InterpretationResolution process(ManagedFnPtr function);
InterpretationResolution processFnCall(ManagedFnPtr function, PassContext context);
InterpretationPass(PassManager* manager);
void run();
};
namespace details {
InterpretationResolution recognizeTags(const std::map<std::string, Expression>& tags);
}
} //end of namespace interpretation
template<>
interpretation::InterpretationResolution
defaultValue<interpretation::InterpretationResolution>();
template<>
struct AttachmentsDict<interpretation::FunctionInterpretationData>
{
typedef interpretation::FunctionInterpretationData Data;
static const unsigned int key = 5;
};
template<>
struct AttachmentsDict<interpretation::InterpretationData>
{
typedef interpretation::InterpretationData Data;
static const unsigned int key = 3;
};
} //end of namespace xreate
#endif /* INTERPRETATIONPASS_H */
diff --git a/cpp/src/pass/versionspass.cpp b/cpp/src/pass/versionspass.cpp
index 734ee66..328922d 100644
--- a/cpp/src/pass/versionspass.cpp
+++ b/cpp/src/pass/versionspass.cpp
@@ -1,366 +1,369 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* versionspass.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on January 4, 2017, 3:13 PM
*/
#include <boost/optional/optional.hpp>
#include "pass/versionspass.h"
namespace std{
std::size_t
hash<xreate::versions::SymbolOrPlaceholder>::operator()(xreate::versions::SymbolOrPlaceholder const& s) const
{return std::hash<xreate::Symbol>()(s.symbol) + (s.flagEndOfLifePlaceholder? 9849 : 1);}
bool
equal_to<xreate::versions::SymbolOrPlaceholder>::operator()(const xreate::versions::SymbolOrPlaceholder& __x, const xreate::versions::SymbolOrPlaceholder& __y) const
{ return __x.flagEndOfLifePlaceholder == __y.flagEndOfLifePlaceholder && __x.symbol == __y.symbol; }
}
using namespace std;
namespace xreate{ namespace versions{
template<>
std::list<Symbol>
defaultValue<std::list<Symbol>>(){
return std::list<Symbol>();
};
inline std::string
printSymbol(const SymbolOrPlaceholder& s){
switch(s.flagEndOfLifePlaceholder){
case SYMBOL: return string("(") + std::to_string(s.symbol.identifier.id) + ", "+ std::to_string(s.symbol.identifier.version) + ")";
case PLACEHOLDER: return string("(") + std::to_string(s.symbol.identifier.id) + ", "+ std::to_string(s.symbol.identifier.version) + ")+";
}
return "";
}
void
VersionsGraph::__debug_print(std::ostream& output) const{
for(auto entry: __inferiors){
output << printSymbol(entry.second) << " <-" << printSymbol(entry.first) << "\n";
}
}
void
VersionsGraph::defineEndOfLife(const Symbol& symbol, const Symbol& symbolSuccessor){
if(__dictSuccessors.count(symbol)){
assert("No version branches allowed yet" && false);
}
const SymbolOrPlaceholder& placeholder = getEndOfLife(symbol);
auto inferiorsDeferred = __inferiors.equal_range(placeholder);
std::unordered_multimap<SymbolOrPlaceholder, SymbolOrPlaceholder> inferiorsReassigned;
for (const auto& inf: boost::make_iterator_range(inferiorsDeferred)){
inferiorsReassigned.emplace(SymbolOrPlaceholder{SYMBOL, symbolSuccessor}, inf.second);
}
__inferiors.erase(placeholder);
__inferiors.insert(inferiorsReassigned.begin(), inferiorsReassigned.end());
__inferiors.emplace(SymbolOrPlaceholder{SYMBOL, symbolSuccessor}, SymbolOrPlaceholder{SYMBOL, symbol});
__dictSuccessors.emplace(symbol, symbolSuccessor);
}
SymbolOrPlaceholder
VersionsGraph::getEndOfLife(const Symbol& s){
if (__dictSuccessors.count(s)){
return SymbolOrPlaceholder{SYMBOL, __dictSuccessors.at(s)}; }
return SymbolOrPlaceholder{PLACEHOLDER, s};
}
void
VersionsGraph::applyNatualDependencies(const Symbol& symbol, const std::list<Symbol>& dependencies){
for (const Symbol& right: dependencies){
__inferiorsNatural.emplace(symbol, right);
}
}
void
VersionsGraph::applyDependentEndOfLife(const SymbolOrPlaceholder& symbol, const list<Symbol>& dependencies){
for (const Symbol& right: dependencies){
auto rightEOF = getEndOfLife(right);
__inferiors.emplace(rightEOF, symbol);
}
}
bool
VersionsGraph::tryEliminateEofAliases(const std::list<SymbolOrPlaceholder>& aliases){
if (aliases.size()==1){
return true;
}
boost::optional<Symbol> symbolActualEoF;
for(const SymbolOrPlaceholder alias: aliases){
switch(alias.flagEndOfLifePlaceholder){
case SYMBOL:
if(symbolActualEoF){
return false;
}
symbolActualEoF = alias.symbol;
break;
case PLACEHOLDER:
continue;
}
}
if(!symbolActualEoF){
return false;
}
for(const SymbolOrPlaceholder alias: aliases){
switch(alias.flagEndOfLifePlaceholder){
case SYMBOL:
continue;
case PLACEHOLDER:
defineEndOfLife(alias.symbol, symbolActualEoF.get());
break;
}
}
return true;
}
std::list<SymbolOrPlaceholder>
VersionsGraph::extractCycle(const Path& path, const SymbolOrPlaceholder& symbolBeginning){
unsigned int posBeginning = path.at(symbolBeginning);
std::list<SymbolOrPlaceholder> result;
auto i=path.begin();
while(true){
i = std::find_if(i, path.end(), [&posBeginning](const auto& el){return el.second >=posBeginning;});
if (i!= path.end()){
result.push_back(i->first);
++i;
} else {break; }
}
return result;
}
bool
VersionsGraph::validateCycles(const SymbolOrPlaceholder& s,
std::unordered_multimap<SymbolOrPlaceholder, SymbolOrPlaceholder>& graph,
std::unordered_set<SymbolOrPlaceholder>& symbolsVisited,
Path& path)
{
if (symbolsVisited.count(s)) return true;
symbolsVisited.insert(s);
path.emplace(s, path.size());
if (graph.count(s)){
//iterate over imposed dependencies
auto candidates = graph.equal_range(s);
for (auto candidate = candidates.first; candidate != candidates.second; ++candidate){
if (path.count(candidate->second)) {
std::list<SymbolOrPlaceholder> cycle = extractCycle(path, candidate->second);
if (!tryEliminateEofAliases(cycle)) return false;
continue;
}
if(!validateCycles(candidate->second, graph, symbolsVisited, path)) return false;
}
}
//iterate over natural dependencies
if (s.flagEndOfLifePlaceholder == SYMBOL) {
auto candidates = __inferiorsNatural.equal_range(s.symbol);
for (auto candidate = candidates.first; candidate != candidates.second; ++candidate){
if (path.count(SymbolOrPlaceholder{SYMBOL, candidate->second})){
return false;
}
if(!validateCycles(SymbolOrPlaceholder{SYMBOL,candidate->second}, graph, symbolsVisited, path)) return false;
}
}
//check previous version
if (s.flagEndOfLifePlaceholder == PLACEHOLDER){
const Symbol& candidate = s.symbol;
if (path.count(SymbolOrPlaceholder{SYMBOL, candidate})){
std::list<SymbolOrPlaceholder> cycle = extractCycle(path, SymbolOrPlaceholder{SYMBOL, candidate});
if (!tryEliminateEofAliases(cycle)) return false;
}
if(!validateCycles(SymbolOrPlaceholder{SYMBOL,candidate}, graph, symbolsVisited, path)) return false;
}
path.erase(s);
return true;
}
bool
VersionsGraph::validateCycles(){
std::unordered_set<SymbolOrPlaceholder> symbolsVisited;
Path path;
std::unordered_multimap<SymbolOrPlaceholder, SymbolOrPlaceholder> graph(__inferiors);
std::unordered_multimap<SymbolOrPlaceholder, SymbolOrPlaceholder>::const_iterator s;
for (s = graph.begin(); s != graph.end(); ++s){
if(!validateCycles(s->first, graph, symbolsVisited, path)) return false;
}
return true;
}
bool
VersionsGraph::validate(){
return validateCycles();
}
std::list<Symbol>
VersionsGraph::expandPlaceholder(const SymbolOrPlaceholder& symbol, const Symbol& symbolPrev) const{
std::list<Symbol> result;
switch (symbol.flagEndOfLifePlaceholder){
case SYMBOL:
//skip self-loops
if (symbol.symbol == symbolPrev) return {};
return {symbol.symbol};
case PLACEHOLDER:
for (const auto& entry: boost::make_iterator_range(__inferiors.equal_range(symbol))){
list<Symbol>&& childResult = expandPlaceholder(entry.second, symbolPrev);
result.insert(result.end(), childResult.begin(), childResult.end());
}
if (__dictSuccessors.count(symbol.symbol)){
Symbol knownSuccessor = __dictSuccessors.at(symbol.symbol);
//skip alias loop
if (knownSuccessor == symbolPrev) return {};
for (const auto& entry: boost::make_iterator_range(__inferiors.equal_range(SymbolOrPlaceholder{SYMBOL, knownSuccessor}))){
list<Symbol>&& childResult = expandPlaceholder(entry.second, knownSuccessor);
result.insert(result.end(), childResult.begin(), childResult.end());
}
}
break;
}
return result;
}
AttachmentsContainerDefault<std::list<Symbol>>*
VersionsGraph::representAsAttachments() const {
AttachmentsContainerDefault<std::list<Symbol>>* container = new AttachmentsContainerDefault<std::list<Symbol>>();
std::map<Symbol, std::list<Symbol>> containerData;
for(const auto& entry: __inferiors){
if(entry.first.flagEndOfLifePlaceholder == PLACEHOLDER) continue;
list<Symbol>& infs = containerData[entry.first.symbol];
list<Symbol>&& infsExpanded = expandPlaceholder(entry.second, entry.first.symbol);
infs.insert(infs.begin(), infsExpanded.begin(), infsExpanded.end());
}
for(const auto& entry: containerData){
container->put(entry.first, entry.second);
}
return container;
}
std::list<Symbol>
VersionsPass::process(const Expression& expression, PassContext context, const std::string& hintSymbol){
if (expression.__state == Expression::COMPOUND){
std::list<Symbol> resultDependencies;
for (const Expression &op: expression.getOperands()) {
std::list<Symbol> deps = process(op, context);
resultDependencies.insert(resultDependencies.end(), deps.begin(), deps.end());
}
for (CodeScope* scope: expression.blocks) {
std::list<Symbol> deps = Parent::process(scope, context);
resultDependencies.insert(resultDependencies.end(), deps.begin(), deps.end());
}
return resultDependencies;
}
if (expression.__state == Expression::IDENT){
const Symbol symb = Attachments::get<Symbol>(expression);
return processSymbol(symb, context, expression.getValueString());
}
return {};
}
//TODO versions, check (declaration.isDefined()) before processing declaration
list<Symbol>
VersionsPass::processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol){
list<Symbol> result{symbol};
if (__symbolsVisited.exists(symbol)){
return result;
}
enum {MODE_ALIAS, MODE_COPY } mode = MODE_ALIAS;
const Expression& declaration = CodeScope::getDeclaration(symbol);
if (declaration.op == Operator::CALL_INTRINSIC){
if (declaration.getValueString() == "copy"){
mode = MODE_COPY;
}
}
if (symbol.identifier.version != VERSION_NONE){
mode = MODE_COPY;
if (symbol.identifier.version > 0){
Symbol versionPrev = Symbol{ScopedSymbol{symbol.identifier.id, symbol.identifier.version-1}, symbol.scope};
__graph.defineEndOfLife(versionPrev, symbol);
}
}
PassContext context2 = context.updateScope(symbol.scope);
std::list<Symbol> dependencies = process(declaration, context2, hintSymbol);
switch (mode) {
case MODE_COPY: __graph.applyDependentEndOfLife(SymbolOrPlaceholder{SYMBOL, symbol}, dependencies); break;
case MODE_ALIAS: __graph.applyDependentEndOfLife(__graph.getEndOfLife(symbol), dependencies); break;
}
__graph.applyNatualDependencies(symbol, dependencies);
__symbolsVisited.put(symbol, true);
return list<Symbol>{symbol};
}
VersionsGraph&
VersionsPass::getResultGraph(){
return __graph;
}
void
VersionsPass::finish(){
assert(__graph.validate() && "Can't validate versions graph");
Attachments::init<VersionImposedDependency>(__graph.representAsAttachments());
}
-}} //end of namespace xreate::versions
\ No newline at end of file
+}} //end of namespace xreate::versions
diff --git a/cpp/src/pass/versionspass.h b/cpp/src/pass/versionspass.h
index e60b2de..6397451 100644
--- a/cpp/src/pass/versionspass.h
+++ b/cpp/src/pass/versionspass.h
@@ -1,107 +1,110 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* File: versionspass.h
* Author: v.melnychenko@xreate.org
*
* Created on January 4, 2017, 3:09 PM
*/
#ifndef VERSIONSPASS_H
#define VERSIONSPASS_H
#include "pass/abstractpass.h"
#include <list>
#include <functional>
namespace xreate { namespace versions {
struct SymbolOrPlaceholder;
}}
namespace std {
template<>
struct hash<xreate::versions::SymbolOrPlaceholder>{
std::size_t operator()(xreate::versions::SymbolOrPlaceholder const& s) const;
};
template<>
struct equal_to<xreate::versions::SymbolOrPlaceholder>{
bool operator()(const xreate::versions::SymbolOrPlaceholder& __x, const xreate::versions::SymbolOrPlaceholder& __y) const;
};
}
namespace xreate { namespace versions {
enum PlaceholderFlag {SYMBOL, PLACEHOLDER};
struct SymbolOrPlaceholder {
PlaceholderFlag flagEndOfLifePlaceholder;
Symbol symbol;
};
struct VersionImposedDependency{};
class VersionsGraph{
public:
//processing API:
void applyNatualDependencies(const Symbol& symbol, const std::list<Symbol>& dependencies);
void applyDependentEndOfLife(const SymbolOrPlaceholder& symbol, const std::list<Symbol>& dependencies);
void defineEndOfLife(const Symbol& symbol, const Symbol& symbolSuccessor);
SymbolOrPlaceholder getEndOfLife(const Symbol& s);
bool validate();
//examination API:
AttachmentsContainerDefault<std::list<Symbol>>* representAsAttachments() const;
void __debug_print(std::ostream& output) const;
private:
typedef std::unordered_map<SymbolOrPlaceholder, unsigned int> Path;
std::unordered_multimap<Symbol, Symbol> __inferiorsNatural;
std::unordered_multimap<SymbolOrPlaceholder, SymbolOrPlaceholder> __inferiors;
std::unordered_map<Symbol, Symbol> __dictSuccessors;
std::list<Symbol> expandPlaceholder(const SymbolOrPlaceholder& symbol, const Symbol& symbolPrev) const;
std::list<SymbolOrPlaceholder> extractCycle(const Path& path, const SymbolOrPlaceholder& symbolBeginning);
bool tryEliminateEofAliases(const std::list<SymbolOrPlaceholder>& aliases);
bool validateCycles();
bool validateCycles(const SymbolOrPlaceholder& s,
std::unordered_multimap<SymbolOrPlaceholder, SymbolOrPlaceholder>& graph,
std::unordered_set<SymbolOrPlaceholder>& symbolsVisited,
Path& path);
};
class VersionsPass: public AbstractPass<std::list<Symbol>> {
typedef AbstractPass<std::list<Symbol>> Parent;
public:
VersionsPass(PassManager* manager): AbstractPass<std::list<Symbol>>(manager){}
std::list<Symbol> process(const Expression& expression, PassContext context, const std::string& hintSymbol="") override;
VersionsGraph& getResultGraph();
virtual void finish();
protected:
std::list<Symbol> processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol="") override;
private:
VersionsGraph __graph;
AttachmentsContainerDefault<bool> __symbolsVisited;
};
}} //end of xreate::versions
namespace xreate{
template<>
std::list<Symbol>
defaultValue<std::list<Symbol>>();
template<>
struct AttachmentsDict<versions::VersionImposedDependency>
{
typedef std::list<Symbol> Data;
static const unsigned int key = 8;
};
}
#endif /* VERSIONSPASS_H */
diff --git a/cpp/src/query/containers.cpp b/cpp/src/query/containers.cpp
index 62a108e..a056a88 100644
--- a/cpp/src/query/containers.cpp
+++ b/cpp/src/query/containers.cpp
@@ -1,167 +1,173 @@
-//
-// Created by pgess on 3/14/15.
-//
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ *
+ * containers.cpp
+ * Created on 3/14/15.
+ */
#include <clasplayer.h>
#include "query/containers.h"
using namespace std;
using namespace xreate::containers;
using namespace xreate;
Implementation
Query::queryImplementation(xreate::Symbol const &s) {
if (Attachments::exists<Implementation>(s))
{
return Attachments::get<Implementation>(s);
}
return Implementation::create(s);
}
Query::Query(){
Attachments::init<Implementation>();
}
void
Query::init(ClaspLayer* clasp)
{
if (flagIsDataLoaded) return;
map<Symbol, Symbol> prototypes;
map<Symbol, string> 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<SymbolPacked, SymbolPacked>(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<SymbolPacked, string>(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);
Attachments::put<Implementation>(var, move(impl));
continue;
}
roots.emplace(move(var), move(implSerialized));
}
//fill implementation data for a cluster roots
for (const pair<Symbol, string> & root: roots)
{
Symbol prototype = prototypes[root.first];
while (prototypes.count(prototype)) {
prototype = prototypes.at(prototype);
}
Attachments::put<Implementation>(root.first, Implementation(Attachments::get<Implementation>(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<SymbolPacked, SymbolPacked>(atom->second);
Symbol root = clasp->unpack(get<0>(info));
Symbol child = clasp->unpack(get<1>(info));
if (!(child == root) && (Attachments::exists<Implementation>(root))) {
Implementation rootImpl = Attachments::get<Implementation>(root);
Attachments::put<Implementation>(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::getDeclaration(var);
switch (varDecl.op)
{
case Operator::LIST_RANGE: {
ImplementationRec<ON_THE_FLY> rec{var};
return {ON_THE_FLY, rec};
}
case Operator::LIST: {
return {SOLID, ImplementationRec<SOLID> {varDecl.getOperands().size()}};
}
default: break;
};
ImplementationLinkedList ill(var);
if (ill){
return ill.getImplementationData();
}
assert(false && "Unable to determine proper implementation for the symbol");
return Implementation();
}
Implementation
Implementation::create(const Symbol& var, const std::string& implSerialized)
{
Expression varDecl = CodeScope::getDeclaration(var);
if (implSerialized == Config::get("containers.impl.solid"))
{
return {SOLID, ImplementationRec<SOLID>{varDecl.operands.size()}};
} else if (implSerialized == Config::get("containers.impl.onthefly")) {
return {ON_THE_FLY, ImplementationRec<ON_THE_FLY>{var}};
}
assert(false && "unable to determine proper implementation for the symbol");
return Implementation();
}
ImplementationLinkedList::ImplementationLinkedList(const Symbol& source)
: flagIsValid(false), s(source){
const Expression& sourceExpr = CodeScope::getDeclaration(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<ON_THE_FLY>{s}};
}
diff --git a/cpp/src/query/containers.h b/cpp/src/query/containers.h
index b06b486..456093b 100644
--- a/cpp/src/query/containers.h
+++ b/cpp/src/query/containers.h
@@ -1,84 +1,90 @@
-//
-// Created by pgess on 3/14/15.
-//
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ *
+ * containers.h
+ * Created on 3/14/15.
+ */
#ifndef _XREATE_CONTAINERSQUERY_H_
#define _XREATE_CONTAINERSQUERY_H_
#include "xreatemanager.h"
#include "clasplayer.h"
#include <boost/variant.hpp>
namespace xreate {
namespace containers {
enum ImplementationType {SOLID, ON_THE_FLY, LINKED_LIST};
template<ImplementationType I>
struct ImplementationRec;
template<>
struct ImplementationRec<SOLID> {
size_t size;
};
template<>
struct ImplementationRec<ON_THE_FLY>{
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<SOLID>, ImplementationRec<ON_THE_FLY>> Variant;
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<ImplementationType I>
const ImplementationRec<I>& extract() const{
const ImplementationRec<I>& rec = boost::get<ImplementationRec<I>>(data);
return rec;
}
};
class Query : public xreate::IQuery {
public:
static Implementation queryImplementation(xreate::Symbol const &s);
void init(ClaspLayer* clasp);
Query();
~Query(){}
private:
bool flagIsDataLoaded = false;
PassManager *man;
};
}
template<>
struct AttachmentsDict<containers::Implementation> {
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 3697073..2e8093b 100644
--- a/cpp/src/query/context.cpp
+++ b/cpp/src/query/context.cpp
@@ -1,207 +1,210 @@
-/*
- * adhoc.cpp
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * context.cpp
*
* Created on: Dec 1, 2015
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*/
#include <query/context.h>
#include <boost/range/iterator_range_core.hpp>
#include <boost/iterator/transform_iterator.hpp>
using namespace std;
namespace xreate { namespace context {
const Domain domainEmpty;
const Decisions decisionsEmpty;
const FunctionDemand functionDemandEmpty;
ContextQuery::ContextQuery(){}
const Domain&
ContextQuery::getContext(const ScopePacked& scopeId) const{
if (!__modelContext.count(scopeId)){
return domainEmpty;
}
return __modelContext.at(scopeId);
}
const Domain&
ContextQuery::getContext(CodeScope* const scope) const{
return getContext(clasp->pack(scope));
}
//DEBT compatibility of forced context with context resolution for interpretation
void
ContextQuery::forceContext(const ScopePacked& scopeId, std::list<Expression> 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<ScopePacked, Expression> __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& atomBinding = Config::get("clasp.bindings.scope");
this->clasp = clasp;
ClaspLayer::ModelFragment query = clasp->query(atomBinding);
//static context
if (query){
map<ScopePacked, vector<Expression>> dictContext;
for (auto i = query->first; i!=query->second; ++i){
ScopePacked idScope;
Expression context;
std::string link;
tie(idScope, context, link) = ClaspLayer::parse<ScopePacked, Expression, string>(i->second);
if (link == "strong") {
dictContext[idScope].push_back(context);
}
}
for (map<ScopePacked, vector<Expression>>::value_type& entry: dictContext){
__modelContext.insert(move(entry));
}
}
prepareFunctionDemandModel();
prepareDecisionModels();
}
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<string, Expression>(i->second);
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");
std::multimap<Expression, Expression> 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<ScopePacked, Expression, Expression>(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<const Expression&,const Expression>& 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 FunctionDemand&
ContextQuery::getFunctionDemand(const std::string& name) const {
if (__modelFunctionDemand.count(name)){
return __modelFunctionDemand.at(name);
}
return functionDemandEmpty;
}
const Decisions&
ContextQuery::getFinalDecisions(const ScopePacked& scopeId) const{
if (__modelStaticDecisions.count(scopeId)){
return __modelStaticDecisions.at(scopeId);
}
return decisionsEmpty;
}
const Domain&
ContextQuery::getTopicDomain(const Expression& topic) const{
if (__modelTopicDomains.count(topic)){
return __modelTopicDomains.at(topic);
}
return domainEmpty;
}
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);
if (itDecisions != itDecisionsAllTopics->second.end()){
return itDecisions->second;
}
}
return decisionsEmpty;
}
// const std::string& atomLateBinding = Config::get("clasp.bindings.function_uncertain");
// query = clasp->query(atomLateBinding);
//
// std::map<std::string, std::vector<Expression>> dictFunctionDomain;
// if (query){
// for (auto i = query->first; i!=query->second; ++i){
// string nameFunction;
// Expression context;
// tie(nameFunction, context) = ClaspLayer::parse<ScopePacked, Expression>(i->second);
// dictFunctionDomain.at(nameFunction).push_back(context);
// }
//
// for(auto& entry: dictFunctionDomain){
// __modelFunctionDomain.emplace(entry.first, move(entry.second));
// }
// }
}} /* namespace xreate::context */
diff --git a/cpp/src/query/context.h b/cpp/src/query/context.h
index 3fc0240..e2f241b 100644
--- a/cpp/src/query/context.h
+++ b/cpp/src/query/context.h
@@ -1,95 +1,98 @@
-/*
- * adhoc.h
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * context.h
*
* Created on: Dec 1, 2015
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*/
#ifndef SRC_QUERY_CONTEXT_H_
#define SRC_QUERY_CONTEXT_H_
#include "clasplayer.h"
#include "ast.h"
#include "serialization.h"
#include <unordered_map>
#include <boost/bimap.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/member.hpp>
namespace xreate{ namespace context{
typedef ExpressionSerialization<RequirementIntegralCode>::Serializer Domain;
typedef boost::bimap<size_t, Expression> FunctionDemand;
typedef std::map<Expression, Expression> Decisions;
typedef std::map<Expression, Expression> DependentDecision;
class ContextQuery: public IQuery {
//AdhocQuery();
public:
const Domain& getContext(const ScopePacked& scopeId) const;
const Domain& getContext(CodeScope* const scope) const;
void forceContext(const ScopePacked& scopeId, std::list<Expression> context);
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<ScopePacked, Domain> __modelContext;
std::map<std::string, FunctionDemand> __modelFunctionDemand;
std::map<ScopePacked, Decisions> __modelStaticDecisions;
std::map<Expression, Domain> __modelTopicDomains;
std::map<ScopePacked, std::map<Expression, DependentDecision>> __modelDependentDecisions;
void prepareFunctionDemandModel();
void prepareDecisionModels();
};
}} // namespace xreate::context */
/*
template <typename ATTACHMENTS>
class ContextAttachments: private std::unordered_map<size_t, ATTACHMENTS> {
typedef std::unordered_map<size_t, ATTACHMENTS> PARENT;
public:
ContextAttachments(ContextAttachments&& other)
: PARENT(std::move(other)), domain(std::move(other.domain)) {}
ContextAttachments(std::vector<Expression>&& expressions, std::vector<ATTACHMENTS>&& attachments)
: domain(move(expressions))
{
size_t size = domain.size();
for (size_t i=0; i<size; ++i){
PARENT::emplace(i, std::move(attachments[i]));
}
}
size_t size() const {
return PARENT::size();
}
size_t count(const Expression& e) const {
return (domain.getExpressionId(e)? 1: 0);
}
const ATTACHMENTS& at(const Expression& e) const{
auto id = domain.getExpressionId(e);
assert(id);
return PARENT::at(*id);
}
private:
ContextDomain domain;
};
typedef ContextAttachments<ManagedFnPtr> FunctionSpecializations ;
*/
#endif /* SRC_QUERY_CONTEXT_H_ */
diff --git a/cpp/src/serialization.h b/cpp/src/serialization.h
index 7131ab3..49d2d14 100644
--- a/cpp/src/serialization.h
+++ b/cpp/src/serialization.h
@@ -1,30 +1,33 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* serialization.h
*
- * Created on: 13 февр. 2016
- * Author: pgess
+ * Created on: 03/13. 2016
+ * Author: pgess <v.melnychenko@xreate.org>
*/
#ifndef SRC_SERIALIZATION_SERIALIZATION_H_
#define SRC_SERIALIZATION_SERIALIZATION_H_
#include "aux/serialization/expressionserializer.h"
namespace xreate {
struct RequirementIntegralCode{};
template<class Requirements=void>
struct ExpressionSerialization {
typedef PackedExpression Code;
typedef ExpressionSerializer Serializer;
};
template<>
struct ExpressionSerialization<RequirementIntegralCode>{
typedef size_t Code;
typedef ExpressionSerializerIntegral Serializer;
};
}
#endif /* SRC_SERIALIZATION_SERIALIZATION_H_ */
diff --git a/cpp/src/utils.cpp b/cpp/src/utils.cpp
index 134ea62..94fdd66 100644
--- a/cpp/src/utils.cpp
+++ b/cpp/src/utils.cpp
@@ -1,24 +1,33 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * utils.cpp
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ */
+
#include "utils.h"
#include <boost/locale/encoding_utf.hpp>
using namespace xreate;
Config Config::__self = Config();
Config::Config()
: __storage{json_file{ "config/default.json" }}
{}
using boost::locale::conv::utf_to_utf;
std::wstring
utf8_to_wstring(const std::string& str)
{
return utf_to_utf<wchar_t>(str.c_str(), str.c_str() + str.size());
}
std::string
wstring_to_utf8(const std::wstring& str)
{
return utf_to_utf<char>(str.c_str(), str.c_str() + str.size());
-}
\ No newline at end of file
+}
diff --git a/cpp/src/utils.h b/cpp/src/utils.h
index 95bb82a..5b9bc56 100644
--- a/cpp/src/utils.h
+++ b/cpp/src/utils.h
@@ -1,159 +1,168 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * utils.cpp
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ */
+
#ifndef UTILS_H
#define UTILS_H
#include "jeayeson/jeayeson.hpp"
//TODO use type mark to mark dirty/mutable members
/*
template<class T>
struct DdesctructableClass<T> {
}
*/
/*
template<class OriginalType>
struct TagUpdatable{
TagUpdatable(const OriginalType& source)
: __source(source)
{}
TagUpdatable() = delete;
const OriginalType& __source;
};
struct Updatable;
template <class Tag, class OT>
struct TagsDictionary
{};
template<class OT>
struct TagsDictionary<Updatable, OT>
{
typedef TagUpdatable<OT> TagName;
};
template<class Tag, class OT>
struct awareOf
{
awareOf(OT& dest)
: __dest(dest)
{}
awareOf<Tag, OT>&
operator= (const typename TagsDictionary<Tag, OT>::TagName& source)
{
__dest = source.__source;
}
private:
OT& __dest;
};
template<class Tag<OT>>
const OT&
awareOf(const Tag<OT>& holder)
{
return std::forward<OT>(holder.__source);
}
*/
namespace xreate {
template<class Tag, class Source>
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<class Source>
using Expanded = AddTag<Expand_t, Source>;
//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<json_value>(key).get<std::string>();
}
};
/**
* Decorators support
*/
template<class DecoratorTag>
struct DecoratorsDict{
//typedef ConcreteDecoratorForTag result;
};
template<class DecoratorTag>
struct Decorators{
typedef typename DecoratorsDict<DecoratorTag>::result Instance;
template<class Base>
static Instance* getInterface(Base* obj){
return dynamic_cast< Instance* > (obj);
}
};
}
std::wstring
utf8_to_wstring(const std::string& str);
std::string
wstring_to_utf8(const std::wstring& str);
#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 <<x << RST
#define FYEL(x) KYEL << x << RST
#define FBLU(x) KBLU << x << RST
#define FMAG(x) KMAG x RST
#define FCYN(x) KCYN x RST
#define FWHT(x) KWHT x RST
#define BOLD(x) "\x1B[1m" x RST
#define UNDL(x) "\x1B[4m" x RST
#endif // UTILS_H
diff --git a/cpp/src/xreatemanager.cpp b/cpp/src/xreatemanager.cpp
index 63af268..6a4cd32 100644
--- a/cpp/src/xreatemanager.cpp
+++ b/cpp/src/xreatemanager.cpp
@@ -1,123 +1,126 @@
-/*
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
* xreatemanager.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on July 3, 2017, 6:03 PM
*/
#include "xreatemanager.h"
#include "clasplayer.h"
#include "aux/xreatemanager-decorators.h"
#include "llvmlayer.h"
#include "main/Parser.h"
#include <assert.h>
#include <list>
namespace xreate {
void
PassManager::registerPass(AbstractPassBase* pass, const PassId& id, AbstractPassBase* parent)
{
__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<AbstractPassBase*> 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::prepare(AST* ast){
root = ast;
clasp = new ClaspLayer();
clasp->ast = ast;
llvm = new LLVMLayer(ast);
}
PassManager::~PassManager(){}
typedef XreateManagerDecoratorFull XreateManagerDecoratorDefault;
namespace details{ namespace tier2{
XreateManager*
XreateManager::prepare(std::string&& code){
auto man = new XreateManagerImpl<XreateManagerDecoratorDefault>;
man->prepareCode(std::move(code));
return man;
}
XreateManager*
XreateManager::prepare(FILE* code){
auto man = new XreateManagerImpl<XreateManagerDecoratorDefault>;
man->prepareCode(code);
return man;
}
}}
namespace details { namespace tier1 {
XreateManager*
XreateManager::prepare(std::string&& code){
auto man = new XreateManagerImpl<XreateManagerDecoratorDefault>;
man->prepareCode(std::move(code));
return man;
}
XreateManager*
XreateManager::prepare(FILE* code){
auto man = new XreateManagerImpl<XreateManagerDecoratorDefault>;
man->prepareCode(code);
return man;
}
}}
XreateManager*
XreateManager::prepare(std::string&& code) {
auto man = new XreateManagerImpl<XreateManagerDecoratorDefault>;
man->prepareCode(std::move(code));
return man;
}
XreateManager*
XreateManager::prepare(FILE* code){
auto man = new XreateManagerImpl<XreateManagerDecoratorDefault>;
man->prepareCode(code);
return man;
}
}
diff --git a/cpp/src/xreatemanager.h b/cpp/src/xreatemanager.h
index 7ffb3c3..16a1f22 100644
--- a/cpp/src/xreatemanager.h
+++ b/cpp/src/xreatemanager.h
@@ -1,122 +1,132 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * xreatemanager.h
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ * Created on July 3, 2017, 6:03 PM
+ */
+
#ifndef PASSMANAGER_H
#define PASSMANAGER_H
#include <string>
#include <map>
//stdio external
struct _IO_FILE;
typedef struct _IO_FILE FILE;
namespace xreate { namespace grammar { namespace main {
class Scanner;
}}}
namespace xreate {
class AbstractPassBase;
class ClaspLayer;
class LLVMLayer;
class AST;
enum class PassId {
CFGPass,
CompilePass,
DFGPass,
EnvironmentTestsPass,
LoggerPass,
AdhocPass,
RulesPass,
InterpretationPass,
VersionsPass
};
class PassManager{
public:
void prepare(AST* ast);
void registerPass(AbstractPassBase* pass, const PassId& id, AbstractPassBase* prerequisite=nullptr);
AbstractPassBase* getPassById(const PassId& id);
bool isPassRegistered(const PassId& id);
void executePasses();
virtual ~PassManager();
ClaspLayer* clasp;
LLVMLayer* llvm;
AST* root;
private:
std::map<PassId, AbstractPassBase*> __passes;
std::multimap<AbstractPassBase*, AbstractPassBase*> __passDependencies;
};
namespace details{ namespace tier2{
class XreateManager: public virtual PassManager{
public:
virtual ~XreateManager(){};
virtual void initPasses()=0;
// virtual void executePasses()=0;
virtual void analyse()=0;
virtual void* run()=0;
static XreateManager* prepare(std::string&& code);
static XreateManager* prepare(FILE* code);
};
template<class Decorator>
class XreateManagerImpl: public Decorator {
public:
};
}} //namespace details::tier2
namespace details{ namespace tier1{
class XreateManager: public virtual PassManager{
public:
virtual void analyse()=0;
virtual void* run()=0;
static XreateManager* prepare(std::string&& code);
static XreateManager* prepare(FILE* code);
};
template<class Decorator>
class XreateManagerImpl: public XreateManager, public details::tier2::XreateManagerImpl<Decorator> {
typedef details::tier2::XreateManagerImpl<Decorator> PARENT;
public:
void analyse(){
PARENT::initPasses();
PARENT::executePasses();
PARENT::analyse();
}
void* run(){
return PARENT::run();
}
};
}} //namespace details::tier1
class XreateManager: public virtual PassManager{
public:
virtual void* run()=0;
static XreateManager* prepare(std::string&& code);
static XreateManager* prepare(FILE* code);
};
template<class Decorator>
class XreateManagerImpl: public XreateManager, public details::tier1::XreateManagerImpl<Decorator>{
typedef details::tier1::XreateManagerImpl<Decorator> PARENT;
public:
void* run(){
PARENT::analyse();
return PARENT::run();
}
};
} //namespace xreate
#endif
diff --git a/cpp/tests/ExpressionSerializer.cpp b/cpp/tests/ExpressionSerializer.cpp
index a5764da..58cf5ae 100644
--- a/cpp/tests/ExpressionSerializer.cpp
+++ b/cpp/tests/ExpressionSerializer.cpp
@@ -1,65 +1,67 @@
-/*
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
* testExpressionSerializer.cpp
*
* Created on: Jan 4, 2016
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*/
#include "aux/serialization/expressionserializer.h"
#include "serialization.h"
#include "ast.h"
#include "gtest/gtest.h"
using namespace xreate;
using namespace std;
TEST(ExpressionSerializer, pack1){
PackedExpression x;
x << std::make_pair(0xA1, 0x100);
size_t* storage = reinterpret_cast<size_t*> (*x);
ASSERT_EQ(0xA100000000000000, *storage);
x << std::make_pair(0x23456, 0x100000);
ASSERT_EQ(0xA123456000000000, *storage);
x << std::make_pair(0x7654321, 0x10000000);
ASSERT_EQ(0xA123456765432100, *storage);
x << std::make_pair(0xABBA, 0x10000);
storage = reinterpret_cast<size_t*> (*x);
ASSERT_EQ(0xA1234567654321AB, *storage);
ASSERT_EQ(0xBA00000000000000, *(storage+1));
}
TEST(ExpressionSerializer, serialize1){
Expression a(Operator::CALL, {Expression(string("a")), Expression(string("a"))});
Expression b(Operator::CALL, {Expression(string("a")), Expression(string("b"))});
ExpressionSerializer serializer(vector<Expression>{a, b});
PackedExpression packA = serializer.getId(a);
PackedExpression packB = serializer.getId(b);
PackedExpression packA2 = serializer.getId(a);
ASSERT_EQ(packA, packA2);
ASSERT_NE(packA, packB);
}
TEST(ExpressionSerializer, serialize2){
Expression a(Operator::CALL, {Expression(string("a")), Expression(string("a"))});
Expression b(Operator::CALL, {Expression(string("a")), Expression(string("b"))});
Expression c(Atom<Identifier_t>("c"));
typedef ExpressionSerialization<RequirementIntegralCode>::Serializer Serializer;
Serializer serializer(vector<Expression>{a, b});
ASSERT_EQ(2, serializer.size());
ASSERT_EQ(1, serializer.count(a));
ASSERT_EQ(1, serializer.count(b));
ASSERT_EQ(0, serializer.count(c));
Serializer serializer2(move(serializer));
ASSERT_EQ(1, serializer2.count(a));
}
diff --git a/cpp/tests/adhoc.cpp b/cpp/tests/adhoc.cpp
index d088cd0..eae5f4a 100644
--- a/cpp/tests/adhoc.cpp
+++ b/cpp/tests/adhoc.cpp
@@ -1,195 +1,196 @@
-/*
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
* adhoc-exceptions.cpp
-
*
* Created on: Nov 19, 2015
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*/
class Adhoc_pass_Adhoc1_Test;
#define FRIENDS_ADHOC \
friend class ::Adhoc_pass_Adhoc1_Test;
#include "ast.h"
#include "xreatemanager.h"
#include "gtest/gtest.h"
#include <stdio.h>
#include <memory>
#include <sstream>
#include <stdlib.h>
#include "pass/adhocpass.h"
#include "pass/compilepass.h"
#include "llvmlayer.h"
using namespace xreate;
using namespace xreate::adhoc;
using namespace std;
TEST(Adhoc, ast_operatorAdhoc1){
XreateManager* man = XreateManager::prepare (
"test = function:: int {\n"
" ad hoc exception(nonImplemented)\n"
"}");
Expression subject = man->root->findFunction("test")->getEntryScope()->getBody();
ASSERT_EQ(Operator::ADHOC, subject.op);
Expression exception = AdhocExpression(subject).getCommand();
ASSERT_EQ("exception", exception.getValueString());
}
TEST(Adhoc, ast_schemeAdhoc1){
XreateManager* man = XreateManager::prepare (
"interface(adhoc){\n"
" pre function expectNoErrors:: bool {\n"
" case (Error) {false}\n"
" case (Success) {true}\n"
" }\n"
" }");
assert(man->root->__interfacesData.count(ASTInterface::Adhoc));
Expression adhocData = man->root->__interfacesData.find(ASTInterface::Adhoc)->second;
ASSERT_EQ(Operator::SWITCH, adhocData.operands[0].op);
}
TEST(Adhoc, pass_Adhoc1){
details::tier1::XreateManager* man = details::tier1::XreateManager::prepare (
"interface(adhoc){\n"
" pre function expectNoErrors:: bool {\n"
" case (Error) {false}\n"
" case (Success) {true}\n"
" }\n"
"}\n"
"main = function::int; entry {0} \n"
);
man->analyse();
AdhocPass* pass = reinterpret_cast<AdhocPass* >(man->getPassById(PassId::AdhocPass));
EXPECT_TRUE(pass->__schemes.size() > 0);
AdhocScheme* scheme = pass->__schemes.begin()->second;
EXPECT_EQ("expectNoErrors", scheme->getName());
}
TEST(Adhoc, full_1){
XreateManager* man = XreateManager::prepare (
" import raw (\"core/control-context.lp\").\n"
" interface(adhoc){\n"
" pre function expectNoErrors:: bool {\n"
" case (error) {false}\n"
" case (success) {true}\n"
" }\n"
" }\n"
" test1 = pre function {\n"
" context:: expectNoErrors."
" ad hoc success\n"
" }"
"main = function::bool;entry {\n"
" test1()\n"
" }");
bool (*main)() = (bool (*)()) man->run();
bool result = main();
ASSERT_EQ(true, result);
}
TEST(Adhoc, full_2){
XreateManager* man = XreateManager::prepare (
" import raw (\"core/control-context.lp\").\n"
" interface(adhoc){\n"
" pre function expectNoErrors:: bool {\n"
" case (error) {false}\n"
" case (success) {true}\n"
" }\n"
" pre function expectErrors:: bool {\n"
" case (error) {true}\n"
" case (success) {false}\n"
" }\n"
" }\n"
" test1 = pre function {\n"
" context:: expectNoErrors."
" ad hoc success\n"
" }\n"
" test2 = pre function {\n"
" context:: expectErrors."
" ad hoc success\n"
" }"
"main = function::bool;entry {\n"
" test1() != test2()\n"
"}");
bool (*main)() = (bool (*)()) man->run();
bool result = main();
ASSERT_EQ(true, result);
}
//TODO adhoc type. FDecl sets wrong type in prefunc case(invalid type))
TEST(Adhoc, full_contextExpectNoErrrors){
XreateManager* man = XreateManager::prepare (
"import raw (\"core/control-context.lp\").\n"
"interface(extern-c){\n"
" xml2 = library:: pkgconfig(\"libxml-2.0\").\n"
" \n"
" include {\n"
" xml2 = [\"stdlib.h\"]\n"
" }.\n"
"}"
"interface(adhoc){\n"
" pre function expectNoErrors:: bool {\n"
" case (error) {false}\n"
" case (success) {true}\n"
" }\n"
"}\n"
"expectErrorCode = pre function(x::int){\n"
" if (x==0)::undef {ad hoc success}\n"
" else {ad hoc error}\n"
"}\n"
"main = function::bool; entry {\n"
" context:: expectNoErrors."
" expectErrorCode(system(\"ls -la\"))\n"
"}" );
int (*main)() = (int (*)()) man->run();
ASSERT_EQ(1, main());
}
//DEBT Implement compilation of switch adhoc
TEST(Adhoc, ast_switchAdhoc1){
XreateManager* man = XreateManager::prepare (
"test1 = function:: bool {\n"
" x = 0. \n"
" switch ad hoc (x:: errors)\n"
" case (error) {0}\n"
" case (success) {1}\n"
"\n"
"}"
);
Expression eSwitch = man->root->findFunction("test1")->getEntryScope()->getBody();
EXPECT_EQ(Operator::SWITCH_ADHOC, eSwitch.op);
EXPECT_EQ(3, eSwitch.operands.size());
EXPECT_EQ(1, eSwitch.tags.size());
EXPECT_EQ("errors", eSwitch.tags.begin()->first);
Expression eCondition = eSwitch.getOperands()[0];
EXPECT_EQ("x", eCondition.getValueString());
-}
\ No newline at end of file
+}
diff --git a/cpp/tests/ast.cpp b/cpp/tests/ast.cpp
index b6f3514..17bee50 100644
--- a/cpp/tests/ast.cpp
+++ b/cpp/tests/ast.cpp
@@ -1,88 +1,90 @@
-/*
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
* ast.cpp
*
* Created on: Jun 11, 2015
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*/
#include "gtest/gtest.h"
#include "xreatemanager.h"
#include "main/Parser.h"
using namespace std;
using namespace xreate;
using namespace xreate::grammar::main;
TEST(AST, Containers1){
FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r");
Scanner scanner(input);
Parser parser(&scanner);
parser.Parse();
assert(!parser.errors->count && "Parser errors");
fclose(input);
}
TEST(AST, InterfacesDataCFA) {
XreateManager* man = XreateManager::prepare
("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, syntax_recognizeIdentifiers){
XreateManager* man = XreateManager::prepare(R"Code(
test= function(a:: num):: num; entry {
a = b:: int.
b = 8:: int.
a
}
)Code");
}
TEST(AST, syntax_operatorIndex){
XreateManager* man = XreateManager::prepare(R"Code(
test= function(a:: num):: num; entry {
b = a[1].
b
}
)Code");
}
TEST(AST, Variants_switch){
XreateManager* man = XreateManager::prepare(R"Code(
Color = type variant{Blue, White, Green}.
main = function:: int {
x = White()::Color.
switch variant(x)::int
case (Green) {0}
case (White) {1}
case (Blue){2}
}
)Code");
Expression e= man->root->findFunction("main")->getEntryScope()->getBody();
ASSERT_EQ(4, e.getOperands().size());
ASSERT_EQ(3, e.blocks.size());
}
TEST(AST, DISABLED_InterfacesDataDFA){
}
TEST(AST, DISABLED_InterfacesDataExtern){
}
//TODO xreate.atg: replace all Type<> as ExprAnnotations<>
diff --git a/cpp/tests/attachments.cpp b/cpp/tests/attachments.cpp
index 54b8bba..8655137 100644
--- a/cpp/tests/attachments.cpp
+++ b/cpp/tests/attachments.cpp
@@ -1,26 +1,26 @@
-/*
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
* attachments.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on January 22, 2017, 12:16 PM
*/
-
-
#include "attachments.h"
#include "ast.h"
#include "gtest/gtest.h"
using namespace xreate;
TEST(Attachments, basic1){
AttachmentsContainerDefault<bool>* c = new AttachmentsContainerDefault<bool>();
Expression expTest(Atom<Number_t>(10));
c->put<Expression>(expTest, true);
Expression expTest2(Atom<Number_t>(11));
ASSERT_FALSE(c->exists<Expression>(expTest2));
-}
\ No newline at end of file
+}
diff --git a/cpp/tests/cfa.cpp b/cpp/tests/cfa.cpp
index 37912d3..e1ed8da 100644
--- a/cpp/tests/cfa.cpp
+++ b/cpp/tests/cfa.cpp
@@ -1,120 +1,122 @@
-/*
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
* testsCFG.cpp
*
* Created on: Jul 17, 2015
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*/
#include "xreatemanager.h"
#include "pass/dfapass.h"
#include "pass/cfapass.h"
#include "analysis/DominatorsTreeAnalysisProvider.h"
#include "gtest/gtest.h"
#include <boost/scoped_ptr.hpp>
#include <boost/smart_ptr/scoped_array.hpp>
using namespace xreate;
using namespace xreate::cfa;
using namespace std;
TEST(CFA, testFunctionAnnotationsClasp){
string&& program =
"f2 = function::int; annotationF2 {\n"
" 0\n"
"}\n"
"\n"
"f1 = function:: int; entry; annotationF1 {\n"
" f2() + 10\n"
"}";
details::tier1::XreateManager* man = details::tier1::XreateManager::prepare(move(program));
man->analyse();
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(CFA, testLoopContextExists){
details::tier1::XreateManager* man = details::tier1::XreateManager::prepare (
"interface(cfa){\n"
" operator fold:: annotation1.\n"
"}\n"
"\n"
"main = function:: int; entry {\n"
" x = [1..10]:: [int].\n"
" sum = loop fold (x->el:: int, 0->sum):: int {\n"
" el + sum + f1()\n"
" }. \n"
" sum\n"
"}"
"case context:: annotation1 {"
" f1 = function::int {\n"
" x = 0:: int. "
" x\n"
" }"
"}"
);
man->analyse();
ClaspLayer::ModelFragment model = man->clasp->query("annotation1");
ScopePacked scopeIdActual = std::get<0>(ClaspLayer::parse<ScopePacked>(model->first->second));
CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope();
const Expression& exprSum = scopeEntry->getDeclaration(scopeEntry->getSymbol("sum"));
CodeScope* scopeExpected = exprSum.blocks.front();
ScopePacked scopeIdExpected = man->clasp->pack(scopeExpected);
ASSERT_EQ(scopeIdExpected, scopeIdActual);
}
TEST(CFA, 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<XreateManager> manager
(XreateManager::prepare(move(program)));
manager->registerPass(new CFAPass(manager.get()) , PassId::CFGPass);
manager->executePasses();
manager->clasp->run();
dominators::DominatorsTreeAnalysisProvider domProvider;
domProvider.run(manager->clasp);
dominators::DominatorsTreeAnalysisProvider::Dominators expectedFDom= {
{0, {0, 9}}
,{1, {1, 4}}
,{2, {7, 8}}
,{3, {2, 3}}
,{4, {5, 6}}
};
dominators::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/compilation.cpp b/cpp/tests/compilation.cpp
index 607e408..12377ae 100644
--- a/cpp/tests/compilation.cpp
+++ b/cpp/tests/compilation.cpp
@@ -1,95 +1,104 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * compilation.cpp
+ *
+ * Created on: -
+ * Author: pgess <v.melnychenko@xreate.org>
+ */
+
#include "xreatemanager.h"
#include "gtest/gtest.h"
using namespace xreate;
//DEBT implement no pkgconfig ways to link libs
//TOTEST FunctionUnit::compileInline
TEST(Compilation, DISABLED_functionInline1){
}
TEST(Compilation, functionEntry1){
std::unique_ptr<XreateManager> program(XreateManager::prepare(
"func1 = function(a:: int):: int {a+8} \
func2 = function::int; entry {12 + func1(4)} \
"));
void* entryPtr = program->run();
int (*entry)() = (int (*)())(intptr_t)entryPtr;
int answer = entry();
ASSERT_EQ(24, answer);
}
TEST(Compilation, full_IFStatementWithVariantType){
XreateManager* man = XreateManager::prepare(
"Color = type variant {RED, BLUE, GREEN}.\n"
"\n"
" main = function(x::int):: bool; entry {\n"
" color = if (x == 0 )::Color {RED()} else {BLUE()}.\n"
" if (color == BLUE())::bool {true} else {false}\n"
" }"
);
bool (*main)(int) = (bool (*)(int)) man->run();
ASSERT_FALSE(main(0));
ASSERT_TRUE(main(1));
}
TEST(Compilation, full_StructUpdate){
XreateManager* man = XreateManager::prepare(
R"Code(
Rec = type {
a :: int,
b:: int
}.
test= function:: int; entry {
a = {a = 18, b = 20}:: Rec.
b = a + {a = 11}:: Rec.
b["a"]
}
)Code");
int (*main)() = (int (*)()) man->run();
int result = main();
ASSERT_EQ(11, result);
}
TEST(Compilation, AnonymousStruct_init_index){
std::string code =
R"Code(
main = function:: int; entry {
x = {10, 15} :: {int, int}.
x[1]
}
)Code";
std::unique_ptr<XreateManager> man(XreateManager::prepare(move(code)));
int (*main)() = (int (*)()) man->run();
EXPECT_EQ(15, main());
}
TEST(Compilation, AnonymousStruct_init_update){
std::string code =
R"Code(
main = function:: int; entry {
x = {10, 15} :: {int, int}.
y = x + {6}:: {int, int}.
y[0]
}
)Code";
std::unique_ptr<XreateManager> man(XreateManager::prepare(move(code)));
int (*main)() = (int (*)()) man->run();
EXPECT_EQ(6, main());
}
diff --git a/cpp/tests/containers.cpp b/cpp/tests/containers.cpp
index f49d209..92b1e1e 100644
--- a/cpp/tests/containers.cpp
+++ b/cpp/tests/containers.cpp
@@ -1,110 +1,112 @@
-/*
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
* containers.cpp
*
* Created on: Jun 9, 2015
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*/
#include "xreatemanager.h"
#include "query/containers.h"
#include "main/Parser.h"
#include "gtest/gtest.h"
using namespace std;
using namespace xreate::grammar::main;
using namespace xreate::containers;
using namespace xreate;
TEST(Containers, ListAsArray){
XreateManager* man = XreateManager::prepare(
R"Code(
main = function(x:: int):: int;entry {
a = [1, 2, 3]:: [int].
a[x]
}
)Code" );
void* mainPtr = man->run();
int (*main)(int) = (int (*)(int))mainPtr;
ASSERT_EQ(2, main(1));
delete man;
}
TEST(Containers, ListAsArray2){
XreateManager* man = XreateManager::prepare(
R"Code(
// CONTAINERS
interface(dfa) {
operator map:: (op(seqaccess)) -> impl(solid).
operator list_range:: ()->impl(on_the_fly).
operator list:: ()->impl(solid).
operator fold:: (op(seqaccess)).
operator index:: (op(randaccess)).
}
import raw("core/containers.lp").
main = function:: int;entry {
a= [1, 2, 3]:: [int].
b= loop map(a->el:: int):: [int]{
2 * el
}.
sum = loop fold(b->el:: int, 0->acc):: int {
acc + el
}.
sum
}
)Code" );
void* mainPtr = man->run();
int (*main)() = (int (*)())mainPtr;
ASSERT_EQ(12, main());
delete man;
}
TEST(Containers, ContanierLinkedList1){
FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r");
assert(input != nullptr);
Scanner scanner(input);
Parser parser(&scanner);
parser.Parse();
AST* ast = parser.root->finalize();
CodeScope* body = ast->findFunction("test")->getEntryScope();
const Symbol symb_chilrenRaw{body->getSymbol("childrenRaw"), body};
containers::ImplementationLinkedList iLL(symb_chilrenRaw);
ASSERT_EQ(true, static_cast<bool>(iLL));
ASSERT_EQ("next", iLL.fieldPointer);
Implementation impl = Implementation::create(symb_chilrenRaw);
ASSERT_NO_FATAL_FAILURE(impl.extract<ON_THE_FLY>());
ImplementationRec<ON_THE_FLY> recOnthefly = impl.extract<ON_THE_FLY>();
ASSERT_EQ(symb_chilrenRaw, recOnthefly.source);
}
TEST(Containers, Implementation_LinkedListFull){
FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r");
assert(input != nullptr);
std::unique_ptr<XreateManager> program(XreateManager::prepare(input));
void* mainPtr = program->run();
int (*main)() = (int (*)())(intptr_t)mainPtr;
int answer = main();
ASSERT_EQ(17, answer);
fclose(input);
}
diff --git a/cpp/tests/context.cpp b/cpp/tests/context.cpp
index 98dc389..783f0db 100644
--- a/cpp/tests/context.cpp
+++ b/cpp/tests/context.cpp
@@ -1,495 +1,497 @@
-/*
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
* frame-context.cpp
*
* Created on: Dec 3, 2015
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*/
#include "xreatemanager.h"
#include "query/context.h"
#include "gtest/gtest.h"
#include <iostream>
#include <boost/scoped_ptr.hpp>
using namespace xreate;
using namespace xreate::context;
TEST(Context, frame_Context1){
details::tier1::XreateManager* man = details::tier1::XreateManager::prepare(
" import raw (\"core/control-context.lp\").\n"
" compute = function::int {\n"
" 0\n"
" }\n"
" computeFast = function:: int {\n"
" context:: computation(fast).\n"
" compute()\n"
" }\n"
" computePrecisely = function:: int {\n"
" context:: computation(precise). \n"
" compute()\n"
" }\n"
"test = function(cmnd:: int):: int; entry {\n"
" context:: arithmetic(iee754). \n"
" if (cmnd > 0)::int {computePrecisely()} else {computeFast()} \n"
"}\n"
);
ContextQuery* query = (ContextQuery*) man->clasp->registerQuery(new ContextQuery(), QueryId::ContextQuery);
man->analyse();
CodeScope* scopeTestC = man->root->findFunction("compute")->getEntryScope();
const Domain& context = query->getContext(man->clasp->pack(scopeTestC));
int contextSize = context.size();
EXPECT_EQ(1, contextSize); //arithmetic(iee754)
}
TEST(Context, contextAsRequirementSuccessful1){
XreateManager* man = XreateManager::prepare(
" import raw (\"core/control-context.lp\").\n"
" case context::safe {\n"
" funcSensitive = function::int {\n"
" 0\n"
" }}\n"
" test = function:: int; entry {\n"
" context:: safe; test.\n"
" funcSensitive()\n"
" }\n"
);
int (*main)() = (int (*)()) man->run();
ASSERT_EQ(0, main());
}
TEST(Context, contextAsRequirementFailed){
XreateManager* man = XreateManager::prepare(
" import raw (\"core/control-context.lp\").\n"
" case context::safe {\n"
" funcSensitive = function::int {\n"
" 0\n"
" }}\n"
" test = function:: int; entry {\n"
" context:: non_safe; test.\n"
" funcSensitive()\n"
" }\n"
);
ASSERT_DEATH(man->run(), "findFunction");
}
TEST(Context, ContextPropagationNested){
XreateManager* man = XreateManager::prepare(
" import raw (\"core/control-context.lp\").\n"
" case context::safe {\n"
" square = function(x:: int) ::int {\n"
" x * x\n"
" }}\n"
" test = function:: int; entry {\n"
" context:: safe; test.\n"
" range = [1..10]:: [int]. \n"
" loop fold(range->x::int, 0->acc):: int { \n"
" acc + square(x) \n"
" } \n"
" }\n"
);
int (*main)() = (int (*)()) man->run();
ASSERT_EQ(385, main());
}
TEST(Context, ContextPropagationNestedInterfunction){
XreateManager* man = XreateManager::prepare(
" import raw (\"core/control-context.lp\").\n"
" case context::toMillimeters {\n"
" convertConcrete = function(source:: num)::num {\n"
" 10 * source \n"
" }\n"
" }\n"
" case context::toInches {\n"
" convertConcrete = function(source:: num)::num {\n"
" 2 * source \n"
" }\n"
" }\n"
"convert= function(source:: num):: num { \n"
"convertConcrete(source) \n"
"} \n"
"test = function(source:: num):: num; entry {\n"
" context:: toMillimeters.\n"
" convert(1)\n"
"}\n" );
int (*main)(int) = (int (*)(int)) man->run();
ASSERT_EQ(10, main(1));
}
TEST(Context, full_ContextBasedFunctionSpecialization){
XreateManager* man = XreateManager::prepare(
" import raw (\"core/control-context.lp\").\n"
" 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_RuleContext){
/*
"rule context:: childs(Child)\n"
" case artefact(Item)\n"
" {\n"
" artefact_depends(Item, Child)\n"
" }";
*/
XreateManager* man = XreateManager::prepare(
" import raw (\"core/control-context.lp\").\n"
" 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)) {truth}\n"
"\n"
" convert(1)\n"
" }" );
man->clasp->addRawScript("truth.");
int (*entry)() = (int (*)()) man->run();
ASSERT_EQ(10, entry());
}
TEST(Context, full_InheritedRuleContext){
XreateManager* man = XreateManager::prepare(
" 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)) {truth}\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("truth.");
int (*entry)(int) = (int (*)(int)) man->run();
ASSERT_EQ(10, entry(0));
ASSERT_EQ(1, entry(1));
}
TEST(Context, full_LateContext){
details::tier1::XreateManager* man = details::tier1::XreateManager::prepare(
"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->analyse();
ContextQuery* queryContext = reinterpret_cast<ContextQuery*>(man->clasp->getQuery(QueryId::ContextQuery));
Expression exprSwitch = man->root->findFunction("main")->__entry->getBody();
CodeScope* blockDefault = man->root->findFunction("main")->__entry->getBody().operands[1].blocks.front();
ScopePacked blockDefaultId = man->clasp->pack(blockDefault);
const Domain& domDefault = queryContext->getContext(blockDefaultId);
ASSERT_EQ(1, domDefault.count(Expression(Atom<Identifier_t>("centi"))));
std::list<ManagedFnPtr> 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 FunctionDemand& demMain = queryContext->getFunctionDemand("main");
ASSERT_EQ(0, demMain.size());
const FunctionDemand& demCalculate = queryContext->getFunctionDemand("calculate");
ASSERT_EQ(1, demCalculate.size());
int (*entry)(int) = (int (*)(int)) man->run();
ASSERT_EQ(1000, entry(0));
ASSERT_EQ(100, entry(1));
}
TEST(Context, loopContextExists){
XreateManager* man = XreateManager::prepare (
"import raw (\"core/control-context.lp\").\n"
"interface(cfa){\n"
" operator fold:: annotation1.\n"
"}\n"
"\n"
"main = function:: int; entry {\n"
" x = [1..10]:: [int].\n"
" sum = loop fold (x->el:: int, 0->sum):: int {\n"
" el + sum + f1()\n"
" }. \n"
" sum\n"
"}"
"case context:: annotation1 {"
" f1 = function::int {\n"
" x = 0:: int. "
" x\n"
" }"
"}"
);
man->run();
}
TEST(Context, pathDependentContext){
std::string program =
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)
}
case default {0}
}
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).
switch(output):: num
case (0) {
toMeters(value)
}
case (1) {
toKilo(value)
}
case default {0}
}
toMeters = function(value::num)::num {
rule context:: convert(X, meters) case (input(X)) {truth}
doConvert(value)
}
toKilo = function(value::num)::num {
rule context:: convert(X, kilo) case (input(X)) {truth}
doConvert(value)
}
doConvert = function(value::num)::num{
convert(value)
})CODE";
boost::scoped_ptr<details::tier1::XreateManager> man(details::tier1::XreateManager::prepare(move(program)));
man->clasp->addRawScript("truth.");
man->analyse();
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));
}
//TODO recover context loop and enable the test
TEST(Context, DISABLED_full_LoopContext){
XreateManager* man = XreateManager::prepare(
" import raw (\"core/control-context.lp\")\n"
" 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));
-}
\ No newline at end of file
+}
diff --git a/cpp/tests/dfa.cpp b/cpp/tests/dfa.cpp
index 53deb4e..8396abc 100644
--- a/cpp/tests/dfa.cpp
+++ b/cpp/tests/dfa.cpp
@@ -1,14 +1,16 @@
-/*
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
* DFGtests.cpp
*
* Created on: Jul 23, 2015
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*/
#include "xreatemanager.h"
#include "pass/dfapass.h"
#include "gtest/gtest.h"
using namespace xreate;
using namespace std;
//DEBT dfa tests: dfa scheme, dfa scheme + return value annoation (example: script/testpass/containers...)
diff --git a/cpp/tests/effects-versions.cpp b/cpp/tests/effects-versions.cpp
index 6f2687d..2f18544 100644
--- a/cpp/tests/effects-versions.cpp
+++ b/cpp/tests/effects-versions.cpp
@@ -1,277 +1,279 @@
-/*
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
* Created on: Dec 16, 2016
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*/
#include "pass/versionspass.h"
#include "xreatemanager.h"
#include "gtest/gtest.h"
using namespace xreate;
using namespace xreate::versions;
TEST(Effects, syntax_versions_1){
XreateManager* man = XreateManager::prepare(R"Code(
test= function(a:: num):: num; entry {
x= b[8].
b = 5:: num.
x{1} = a:: num.
x{1} + a
}
)Code");
}
TEST(Effects, analysis_versions_1){
XreateManager* man = XreateManager::prepare(
R"Code(
test= function:: num; entry {
x{0}= 3:: int.
x{1} = x{0} + 1.
x{1}
}
)Code");
VersionsPass* pass = new VersionsPass(man);
pass->run();
VersionsGraph graph = pass->getResultGraph();
ASSERT_TRUE(graph.validate());
}
TEST(Effects, analysis_versions_2){
XreateManager* man = XreateManager::prepare(
R"Code(
test= function(a:: num):: num; entry {
x{0}= 3:: int.
b = [1, 2, x{0}].
x{1} = b[2].
x{1} + a
}
)Code");
VersionsPass* pass = new VersionsPass(man);
pass->run();
VersionsGraph graph = pass->getResultGraph();
ASSERT_TRUE(graph.validate());
}
TEST(Effects, analysis_versions_2_1_fail){
XreateManager* man = XreateManager::prepare(
R"Code(
test= function(a:: num):: num; entry {
x{0}= 5:: int.
b = x{0}.
x{1} = 2.
b + x{1}
}
)Code");
VersionsPass* pass = new VersionsPass(man);
pass->run();
VersionsGraph graph = pass->getResultGraph();
graph.__debug_print(std::cout);
ASSERT_FALSE(graph.validate());
}
TEST(Effects, analysis_versions_2_2){
XreateManager* man = XreateManager::prepare(
R"Code(
test= function(a:: num):: num; entry {
x{0}= 5:: int.
b = intrinsic copy(x{0}).
x{1} = 2.
b + x{1}
}
)Code");
VersionsPass* pass = new VersionsPass(man);
pass->run();
VersionsGraph graph = pass->getResultGraph();
graph.__debug_print(std::cout);
ASSERT_TRUE(graph.validate());
}
TEST(Effects, analysis_versions_3){
XreateManager* man = XreateManager::prepare(
R"Code(
test= function:: num; entry {
x{0}= 3:: int.
a = x{0}:: int.
b = a :: int.
x{1} = b.
x{1}
}
)Code");
VersionsPass* pass = new VersionsPass(man);
pass->run();
VersionsGraph graph = pass->getResultGraph();
graph.__debug_print(std::cout);
ASSERT_TRUE(graph.validate());
std::cout << "========================\n";
graph.__debug_print(std::cout);
AttachmentsContainerDefault<std::list<Symbol>>* attachmentsDependency = graph.representAsAttachments();
CodeScope* scope = man->root->findFunction("test")->getEntryScope();
const std::list<Symbol>& dependenciesX1 = attachmentsDependency->get(Symbol{ScopedSymbol{1, 1}, scope});
ASSERT_EQ(3, dependenciesX1.size());
}
TEST(Effects, compilation_versions_1){
details::tier1::XreateManager* man = details::tier1::XreateManager::prepare(
R"Code(
test= function:: num; entry {
x{1} = b.
b = a :: int.
a = x{0}:: int.
x{0}= 3:: int.
x{1}
}
)Code");
man->analyse();
if (!man->isPassRegistered(PassId::VersionsPass)){
VersionsPass* pass = new VersionsPass(man);
pass->run();
pass->finish();
}
int (*body)() = (int (*)())man->run();
int answer = body();
ASSERT_EQ(3, answer);
}
TEST(Effects, compilation_versions_versionInit1){
details::tier1::XreateManager* man = details::tier1::XreateManager::prepare(
R"Code(
test= function:: num; entry {
x{0} = 3.
x{0}
}
)Code");
man->analyse();
if (!man->isPassRegistered(PassId::VersionsPass)){
VersionsPass* pass = new VersionsPass(man);
pass->run();
pass->finish();
}
int (*body)() = (int (*)())man->run();
int answer = body();
ASSERT_EQ(3, answer);
}
TEST(Effects, compilation_versions_versionNext1){
details::tier1::XreateManager* man = details::tier1::XreateManager::prepare(
R"Code(
test= function:: num; entry {
x{0} = 5.
x{1} = x{0} - 2.
x{1}
}
)Code");
man->analyse();
if (!man->isPassRegistered(PassId::VersionsPass)){
VersionsPass* pass = new VersionsPass(man);
pass->run();
pass->finish();
}
int (*body)() = (int (*)())man->run();
int answer = body();
ASSERT_EQ(3, answer);
}
TEST(Effects, compilation_versions_IntrinsicCopy1){
details::tier1::XreateManager* man = details::tier1::XreateManager::prepare(
R"Code(
test= function:: num; entry {
x{0} = 5.
b = intrinsic copy (x{0}).
x{1} = 2.
b - x{1}
}
)Code");
man->analyse();
if (!man->isPassRegistered(PassId::VersionsPass)){
VersionsPass* pass = new VersionsPass(man);
pass->run();
pass->finish();
}
int (*body)() = (int (*)())man->run();
int answer = body();
ASSERT_EQ(3, answer);
}
TEST(Effects, compilation_versions_varexchange){
details::tier1::XreateManager* man = details::tier1::XreateManager::prepare(
R"Code(
test= function:: num; entry {
a{0} = 3.
b{0} = 5.
tmp = intrinsic copy (a{0}).
a{1} = b{0}.
b{1} = tmp.
b{1}
}
)Code");
man->analyse();
if (!man->isPassRegistered(PassId::VersionsPass)){
VersionsPass* pass = new VersionsPass(man);
pass->run();
pass->finish();
}
int (*body)() = (int (*)())man->run();
int answer = body();
ASSERT_EQ(3, answer);
}
/*
TEST(Effects, analysis_versions_copy){
}
TEST(Effects, syntax_references1){
}
TEST(Effects, syntax_scope_versions1){
}
TEST(Effects, DynamicVersions_analysis){
}
*/
diff --git a/cpp/tests/externc.cpp b/cpp/tests/externc.cpp
index 97799f8..b619517 100644
--- a/cpp/tests/externc.cpp
+++ b/cpp/tests/externc.cpp
@@ -1,106 +1,115 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * externc.cpp
+ *
+ * Created on: -
+ * Author: pgess <v.melnychenko@xreate.org>
+ */
+
#include "gtest/gtest.h"
#include "xreatemanager.h"
#include "main/Scanner.h"
#include "main/Parser.h"
#include <iostream>
#include <llvm/Support/DynamicLibrary.h>
using namespace std;
using namespace xreate;
TEST(InterfaceExternC, testAST) {
std::string code = " \
interface(extern-c){ \
xml2 = library:: pkgconfig(\"libxml-2.0\"). \
\
include { \
xml2 = [\"libxml/tree.h\"] \
}. \
} \
";
xreate::grammar::main::Scanner scanner(reinterpret_cast<const unsigned char*> (code.c_str()), code.size());
xreate::grammar::main::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<string> 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<string> 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_uniform(24) }";
std::unique_ptr<XreateManager> program(XreateManager::prepare(move(code)));
void* entryPtr = program->run();
int (*entry)() = (int (*)())(intptr_t) entryPtr;
int answer = 24;
answer = entry();
cout << answer;
ASSERT_LT(answer, 24);
}
TEST(InterfaceExternC, testStructFields1) {
FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate", "r");
assert(input != nullptr);
xreate::grammar::main::Scanner scanner(input);
xreate::grammar::main::Parser parser(&scanner);
parser.Parse();
AST* ast = parser.root->finalize();
CodeScope* body = ast->findFunction("test")->getEntryScope();
const ExpandedType& t2Tree = ast->getType(body->getDeclaration(body->getSymbol("tree")));
LLVMLayer llvm(ast);
TypeUtils utils(&llvm);
std::vector<std::string>fields = utils.getStructFields(t2Tree);
auto field = std::find(fields.begin(), fields.end(), "children");
ASSERT_TRUE(field != fields.end());
}
diff --git a/cpp/tests/interpretation.cpp b/cpp/tests/interpretation.cpp
index 1c1feb4..9ac23ef 100644
--- a/cpp/tests/interpretation.cpp
+++ b/cpp/tests/interpretation.cpp
@@ -1,438 +1,447 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * interpretation.cpp
+ *
+ * Created on: -
+ * Author: pgess <v.melnychenko@xreate.org>
+ */
+
#include "attachments.h"
using namespace xreate;
#include "xreatemanager.h"
#include "compilation/targetinterpretation.h"
#include "gtest/gtest.h"
#include "boost/scoped_ptr.hpp"
//#define FRIENDS_INTERPRETATION_TESTS \
// friend class ::Modules_AST2_Test; \
// friend class ::Modules_Discovery1_Test; \
// friend class ::Modules_Solve1_Test;
#include "pass/interpretationpass.h"
using namespace xreate::grammar::main;
using namespace xreate::interpretation;
TEST(Interpretation, Analysis_StatementIF_1){
XreateManager* man = XreateManager::prepare(
R"Code(
main = function::bool {
x = "a":: string.
y = if (x=="b"):: bool; interpretation(force) {
true
} else {
false
}.
y
}
)Code" );
InterpretationPass* pass = new InterpretationPass(man);
pass->run();
CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope();
Symbol symbolY{scopeEntry->getSymbol("y"), scopeEntry};
InterpretationData& dataSymbolY = Attachments::get<InterpretationData>(symbolY);
ASSERT_EQ(INTR_ONLY, dataSymbolY.resolution);
}
TEST(Interpretation, Compilation_StatementIF_1){
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(
R"Code(
main = function::int; entry {
x = "a":: string.
y = if (x=="b"):: string; interpretation(force) {
1
} else {
0
}.
y
}
)Code" );
man->analyse();
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){
XreateManager* man = XreateManager::prepare(
R"Code(
main = function(x:: int):: int {
comm= "inc":: string; interpretation(force).
y = if (comm == "inc")::int {x+1} else {x}.
y
}
)Code" );
InterpretationPass* pass = new InterpretationPass(man);
pass->run();
CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope();
Symbol symbolY{scopeEntry->getSymbol("y"), scopeEntry};
InterpretationData& dataSymbolY = Attachments::get<InterpretationData>(symbolY);
ASSERT_EQ(CMPL_ONLY, dataSymbolY.resolution);
ASSERT_EQ(IF_INTERPRET_CONDITION, dataSymbolY.op);
}
TEST(Interpretation, Compilation_StatementIF_InterpretCondition_1){
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(
R"Code(
main = function(x:: int):: int; entry {
comm= "inc":: string; interpretation(force).
y = if (comm == "inc")::int {x+1} else {x}.
y
}
)Code" );
man->analyse();
InterpretationPass* pass;
if (man->isPassRegistered(PassId::InterpretationPass)){
pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass);
} else {
pass = new InterpretationPass(man);
pass->run();
}
int (*main)(int) = (int (*)(int))man->run();
int result = main(1);
ASSERT_EQ(2, result);
}
TEST(Interpretation, Compilation_StatementFOLD_INTERPRET_INPUT_1){
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(
R"Code(
main = function(x:: int):: int; entry {
commands = ["inc", "double", "dec"]:: [string]; interpretation(force).
loop fold(commands->comm::string, x->operand):: int{
switch(comm)::int
case ("inc"){
operand + 1
}
case ("dec"){
operand - 1
}
case ("double"){
operand * 2
}
}
}
)Code" );
man->analyse();
InterpretationPass* pass;
if (man->isPassRegistered(PassId::InterpretationPass)){
pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass);
} else {
pass = new InterpretationPass(man);
pass->run();
}
const ManagedFnPtr& funcMain = man->root->findFunction("main");
InterpretationData& dataBody = Attachments::get<InterpretationData>(funcMain);
ASSERT_EQ(FOLD_INTERPRET_INPUT, dataBody.op);
int (*main)(int) = (int (*)(int))man->run();
int result = main(10);
ASSERT_EQ(21, result);
}
TEST(Interpretation, StatementCall_RecursionNo_1){
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(
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->analyse();
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){
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(
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->analyse();
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(ANY, resolutionActual);
int (*main)() = (int (*)())man->run();
int result = main();
ASSERT_EQ(0, result);
}
TEST(Interpretation, StatementCall_RecursionIndirect_1){
XreateManager* man = XreateManager::prepare(
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");
}
TEST(Interpretation, PartialIntr_1){
XreateManager* man = XreateManager::prepare(
R"Code(
evaluate= function(argument:: num, code:: string; interpretation(force)):: num {
switch(code)::int
case ("inc") {argument + 1}
case ("dec") {argument - 1}
case ("double") {argument * 2}
}
main = function::int; entry {
commands= ["inc", "double", "dec"]:: [string]; interpretation(force).
loop fold(commands->comm::string, 10->operand):: int{
evaluate(operand, comm)
}
}
)Code" );
InterpretationPass* pass = new InterpretationPass(man);
pass->run();
ManagedFnPtr fnEvaluate = man->root->findFunction("evaluate");
InterpretationResolution resFnEvaluate= pass->process(fnEvaluate);
ASSERT_EQ(CMPL_ONLY, resFnEvaluate);
ASSERT_TRUE(FunctionInterpretationHelper::needPartialInterpretation(fnEvaluate));
const Expression& exprLoop = man->root->findFunction("main")->__entry->getBody();
Symbol symbCallEv{{0, versions::VERSION_NONE}, exprLoop.blocks.front()};
InterpretationData dataCallEv = Attachments::get<InterpretationData>(symbCallEv);
ASSERT_EQ(CMPL_ONLY, dataCallEv.resolution);
ASSERT_EQ(CALL_INTERPRET_PARTIAL, dataCallEv.op);
}
TEST(Interpretation, Compilation_PartialIntr_2){
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(
R"Code(
evaluate= function(argument:: num, code:: string; interpretation(force)):: num {
switch(code)::int
case ("inc") {argument + 1}
case ("dec") {argument - 1}
case ("double") {argument * 2}
case default {argument}
}
main = function::int; entry {
commands= ["inc", "double", "dec"]:: [string]; interpretation(force).
loop fold(commands->comm::string, 10->operand):: int{
evaluate(operand, comm)
}
}
)Code" );
man->analyse();
if (!man->isPassRegistered(PassId::InterpretationPass)){
InterpretationPass* pass = new InterpretationPass(man);
pass->run();
}
int (*main)() = (int (*)())man->run();
int result = main();
ASSERT_EQ(21, result);
}
TEST(Interpretation, PartialIntr_3){
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(
R"Code(
Command= type variant {INC, DEC, DOUBLE}.
evaluate= function(argument:: num, code:: Command; interpretation(force)):: num {
switch variant(code)::int
case (INC) {argument + 1}
case (DEC) {argument - 1}
case (DOUBLE) {argument * 2}
}
main = function::int; entry {
commands= [INC(), DOUBLE(), DEC()]:: [Command]; interpretation(force).
loop fold(commands->comm::Command, 10->operand):: int{
evaluate(operand, comm)
}
}
)Code" );
man->analyse();
if (!man->isPassRegistered(PassId::InterpretationPass)){
InterpretationPass* pass = new InterpretationPass(man);
pass->run();
}
int (*main)() = (int (*)())man->run();
int result = main();
ASSERT_EQ(21, result);
}
TEST(Interpretation, SwitchVariant){
xreate::XreateManager* man = xreate::XreateManager::prepare(
R"Code(
OneArgument = type{x::int}.
TWoArgument = type {x::int, y::int}.
Command= type variant {
ADD::TwoArguments,
DEC:: OneArgument,
DOUBLE::OneArgument
}.
main = function::int; entry{
program = ADD({x=2, y=3})::Command; interpretation(force).
switch variant(program)::int
case (ADD) {program["x"]+program["y"]}
case (DEC) {1}
case (DOUBLE) {2}
}
)Code" );
int (*main)() = (int (*)())man->run();
int result = main();
ASSERT_EQ(5, result);
}
TEST(Interpretation, SwitchVariantAlias){
xreate::XreateManager* man = xreate::XreateManager::prepare(
R"Code(
OneArgument = type{x::int}.
TWoArgument = type {x::int, y::int}.
Command= type variant {
ADD::TwoArguments,
DEC:: OneArgument,
DOUBLE::OneArgument
}.
main = function::int; entry{
program = [ADD({x=2, y=3}), DEC({x=8})]::Command; interpretation(force).
switch variant(program[0]->program)::int
case (ADD) {program["x"]+program["y"]}
case (DEC) {1}
case (DOUBLE) {2}
}
)Code" );
int (*main)() = (int (*)())man->run();
int result = main();
ASSERT_EQ(5, result);
}
TEST(InterpretationExamples, Regexp1){
FILE* input = fopen("scripts/dsl/regexp.xreate","r");
assert(input != nullptr);
std::unique_ptr<XreateManager> man(XreateManager::prepare(input));
int (*main)() = (int (*)())man->run();
int result = main();
ASSERT_EQ(4, result);
}
//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
index 6947ae6..1de81f0 100644
--- a/cpp/tests/loops.cpp
+++ b/cpp/tests/loops.cpp
@@ -1,178 +1,187 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * loops.cpp
+ *
+ * Created on: -
+ * Author: pgess <v.melnychenko@xreate.org>
+ */
+
#include "xreatemanager.h"
#include "gtest/gtest.h"
using namespace std;
TEST(Loop, SimpleLoop1){
string code =
R"CODE(
main = function:: int; entry {
input = [1..5]:: [int].
loop fold(input->el::int, 0->sum)::int
{
sum + el
}
}
)CODE";
xreate::XreateManager* man = xreate::XreateManager::prepare(move(code));
int (*funcMain)() = (int (*)()) man->run();
int answerActual = funcMain();
ASSERT_EQ(15, answerActual);
}
TEST(Loop, Break1){
string code =
R"CODE(
main = function:: int; entry {
input = [1..10]:: [int].
loop fold(input->el::int, 0->sum)::int
{
if (sum>5)::int {
sum:: int; break
} else {sum+el}
}
}
)CODE";
xreate::XreateManager* man = xreate::XreateManager::prepare(move(code));
int (*funcMain)() = (int (*)()) man->run();
int answerActual = funcMain();
ASSERT_EQ(6, answerActual);
}
TEST(Loop, NestedLoopsSimple1){
string code =
R"CODE(
main = function:: int; entry {
listX = [1..5]:: [int].
loop fold(listX->x::int, 0->acc)::int
{
listY = [1..5]:: [int].
row = loop fold(listY->y::int, 1->acc):: int {
acc * ( y + x)
}.
acc + row
}
}
)CODE";
xreate::XreateManager* man = xreate::XreateManager::prepare(move(code));
int (*funcMain)() = (int (*)()) man->run();
int answerActual = funcMain();
ASSERT_EQ(55320, answerActual);
}
TEST(Loop, NestedLoopsBreak1){
string code =
R"CODE(
main = function:: int; entry {
listX = [1..5]:: [int].
loop fold(listX->x::int, 0->acc)::int
{
listY = [1..5]:: [int].
row = loop fold(listY->y::int, 1->acc):: int {
res = acc * ( y + x) :: int.
if (res > 20):: int {
20:: int; break
} else {
res
}
}.
acc + row
}
}
)CODE";
xreate::XreateManager* man = xreate::XreateManager::prepare(move(code));
int (*funcMain)() = (int (*)()) man->run();
int answerActual = funcMain();
ASSERT_EQ(100, answerActual);
}
TEST(Loop, NestedLoopsBreak2){
string code =
R"CODE(
main = function:: int; entry {
listX = [1..3]:: [int].
loop fold(listX->x::int, 0->acc)::int
{
listY = [1..5]:: [int].
row = loop fold(listY->y::int, 1->acc):: int {
res = acc * y :: int.
if (res > 24):: int {
24:: int; break
} else {
res
}
}.
if (x==3)::int{
acc:: int; break
} else {
acc + row
}
}
}
)CODE";
xreate::XreateManager* man = xreate::XreateManager::prepare(move(code));
int (*funcMain)() = (int (*)()) man->run();
int answerActual = funcMain();
ASSERT_EQ(48, answerActual);
}
//TEST nested loop breaks.
//TEST 2 breaks^ outer loop break, inner loop break
TEST(Loop, InfiniteLoop1){
string code =
R"Code(
fac = function(x:: int):: int{
range = [2..x] :: [int].
loop fold(range->i::int, 1->acc)::int {
acc * i
}
}
main = function:: int; entry {
loop fold inf(2->state) :: int {
if (fac(state)==120)::int {
state::int; break
} else {state + 1}
}
}
)Code" ;
xreate::XreateManager* man = xreate::XreateManager::prepare(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/main.cpp b/cpp/tests/main.cpp
index 0e1f7de..c45667e 100644
--- a/cpp/tests/main.cpp
+++ b/cpp/tests/main.cpp
@@ -1,14 +1,23 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * main.cpp
+ *
+ * Created on: -
+ * Author: pgess <v.melnychenko@xreate.org>
+ */
+
#include "utils.h"
#include <gtest/gtest.h>
using namespace std;
using namespace xreate;
int main(int argc, char **argv) { testing::GTEST_FLAG(color) = "yes";
string testsTemplate = Config::get("tests.template");
string testsFilter = Config::get(string("tests.templates.") + testsTemplate);
testing::GTEST_FLAG(filter) = testsFilter;
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/cpp/tests/modules.cpp b/cpp/tests/modules.cpp
index d2f0e62..a857c5d 100644
--- a/cpp/tests/modules.cpp
+++ b/cpp/tests/modules.cpp
@@ -1,321 +1,323 @@
-/*
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
* modules.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on June 18, 2017, 8:25 PM
*/
class Modules_AST2_Test;
class Modules_Discovery1_Test;
class Modules_Solve1_Test;
#define FRIENDS_MODULES_TESTS \
friend class ::Modules_AST2_Test; \
friend class ::Modules_Discovery1_Test; \
friend class ::Modules_Solve1_Test;
#include "modules.h"
#include "aux/xreatemanager-decorators.h"
#include "aux/xreatemanager-modules.h"
#include "xreatemanager.h"
#include "modules/Parser.h"
#include "gtest/gtest.h"
#include <boost/filesystem.hpp>
#include <regex>
#include <clingo/clingocontrol.hh>
namespace fs = boost::filesystem;
using namespace std;
using namespace xreate;
using namespace xreate::modules;
TEST(Modules, AST1) {
FILE* input = fopen("scripts/dsl/regexp.xreate","r");
assert(input != nullptr);
Scanner scanner(input);
Parser parser(&scanner);
parser.Parse();
ASSERT_EQ(parser.errors->count, 0);
}
TEST(Modules, AST2){
string code = R"Code(
module {
name(test1).
status(untested).
require provides(logging).
include controller("/tmp/test-controller.ls").
discover("/tmp/root/").
}
)Code";
Scanner scanner(reinterpret_cast<const unsigned char*>(code.c_str()), code.size());
Parser parser(&scanner);
parser.Parse();
ModuleRecord module = parser.module;
ASSERT_EQ(2, module.__properties.size());
ASSERT_EQ("name", module.__properties.front().getValueString());
ASSERT_EQ("status", module.__properties.back().getValueString());
ASSERT_EQ(1, module.__queries.size());
ASSERT_EQ("provides", module.__queries.front().getValueString());
ASSERT_EQ(1, module.__controllers.size());
ASSERT_EQ("/tmp/test-controller.ls", module.__controllers.front());
ASSERT_EQ(1, module.__discoveries.size());
ASSERT_EQ("/tmp/root/", module.__discoveries.front());
}
TEST(Modules, Discovery1){
const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54723/";
string codeA =
R"Code(module {
name(testA).
status(needToTestMore).
})Code";
string codeB =
R"Code(module {
name(testB).
status(needToTestEvenMore).
})Code";
string codeMain = string("module{discover \"") + dirModulesRoot + "\".}";
fs::create_directories(dirModulesRoot);
fs::ofstream fileA(dirModulesRoot + "a.xreate");
fileA << codeA;
fileA.close();
fs::ofstream fileB(dirModulesRoot + "b.xreate");
fileB << codeB;
fileB.close();
Scanner scanner(reinterpret_cast<const unsigned char*>(codeMain.c_str()), codeMain.size());
Parser parser(&scanner);
parser.Parse();
ModulesRegistry registry;
ModulesSolver solver(&registry);
solver.discoverModules(parser.module);
fs::remove_all(dirModulesRoot);
std::string output = solver.__program.str();
cout << output << endl;
ASSERT_NE(string::npos, output.find("bind_module(0, name(testA))."));
ASSERT_NE(string::npos, output.find("bind_module(1, status(needToTestEvenMore))."));
}
TEST(Modules, Requests1){
}
TEST(Modules, Solve1){
const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54724/";
string codeA =
R"Code(module {
name(testA).
provide(superService).
status(needToTestMore).
})Code";
string codeB =
R"Code(module {
name(testB).
provide(superService).
status(needToTestEvenMore).
})Code";
string codeMain =
R"Code(module {
discover("/tmp/testModulesDiscovery1_t54724/")
include controller ("/tmp/testModulesDiscovery1_t54724/controller")
require (superService)
})Code";
string codeController =
R"Code(
status_score(0, needToTestEvenMore).
status_score(1, needToTestMore).
module_include_candidate(X, Y, Request):-
module_require(X, Request); bind_module(Y, provide(Request)).
module_include_winner(X, Request, MaxScore) :-
MaxScore = #max{Score: module_include_candidate(X, Y, Request), bind_module(Y, status(Status)), status_score(Score, Status)};
module_require(X, Request).
module_include(X, Y) :-
module_include_winner(X, Request, MaxScore);
bind_module(Y, provide(Request));
bind_module(Y, status(Status));
status_score(MaxScore, Status).
)Code";
fs::create_directories(dirModulesRoot);
fs::ofstream fileA(dirModulesRoot + "a.xreate");
fileA << codeA;
fileA.close();
fs::ofstream fileB(dirModulesRoot + "b.xreate");
fileB << codeB;
fileB.close();
fs::ofstream fileController(dirModulesRoot + "controller");
fileController << codeController;
fileController.close();
Scanner scanner(reinterpret_cast<const unsigned char*>(codeMain.c_str()), codeMain.size());
Parser parser(&scanner);
parser.Parse();
ModulesRegistry registry;
ModulesSolver solver(&registry);
solver.init("", parser.module);
fs::remove_all(dirModulesRoot);
cout << solver.__program.str() << endl;
std::list<std::string> modulesRequired = solver.run(parser.module);
ASSERT_EQ(1, modulesRequired.size());
string moduleActualRequired = modulesRequired.front();
string moduleExpected = dirModulesRoot + "a.xreate";
ASSERT_EQ(moduleExpected, moduleActualRequired);
}
TEST(Modules, Compilation1){
const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54726/";
string codeMain =
R"Code(
module {
discover("/tmp/testModulesDiscovery1_t54726/")
include controller("/tmp/testModulesDiscovery1_t54726/controller")
require (superService)
}
test = function:: int; entry {
getYourNumber()
}
)Code";
string codeA =
R"Code(module {
name(testA).
provide(superService).
status(needToTestEvenMore).
}
getYourNumber= function:: int {0}
)Code";
string codeB =
R"Code(module {
name(testB).
provide(superService).
status(needToTestMore).
}
getYourNumber= function:: int {1}
)Code";
string codeController =
R"Code(
status_score(0, needToTestEvenMore).
status_score(1, needToTestMore).
module_include_candidate(X, Y, Request):-
module_require(X, Request); bind_module(Y, provide(Request)).
module_include_winner(X, Request, MaxScore) :-
MaxScore = #max{Score: module_include_candidate(X, Y, Request), bind_module(Y, status(Status)), status_score(Score, Status)};
module_require(X, Request).
module_include(X, Y) :-
module_include_winner(X, Request, MaxScore);
bind_module(Y, provide(Request));
bind_module(Y, status(Status));
status_score(MaxScore, Status).
)Code";
fs::create_directories(dirModulesRoot);
fs::ofstream fileA(dirModulesRoot + "a.xreate");
fileA << codeA;
fileA.close();
fs::ofstream fileB(dirModulesRoot + "b.xreate");
fileB << codeB;
fileB.close();
fs::ofstream fileController(dirModulesRoot + "controller");
fileController << codeController;
fileController.close();
auto man = new XreateManagerImpl<XreateManagerDecoratorModules<XreateManagerDecoratorFull>>();
man->prepareCode(std::move(codeMain));
fs::remove_all(dirModulesRoot);
int (*funcMain)() = (int (*)()) man->run();
int result = funcMain();
ASSERT_EQ(1, result);
}
TEST(Modules, Compilation_AssignModulePath1){
const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54725/";
string codeMain =
R"Code(
module {
discover("/tmp/testModulesDiscovery1_t54725/")
include controller("/tmp/testModulesDiscovery1_t54725/controller")
require (superService)
}
test = function:: int; entry {
getYourNumber()
}
)Code";
string codeA =
R"Code(module {
name(testA).
provide(superService).
status(needToTestEvenMore).
}
getYourNumber= function:: int {0}
)Code";
string codeController =
R"Code(
module_include(X, "/tmp/testModulesDiscovery1_t54725/a.xreate") :- module_require(X, superService).
)Code";
fs::create_directories(dirModulesRoot);
fs::ofstream fileA(dirModulesRoot + "a.xreate");
fileA << codeA;
fileA.close();
fs::ofstream fileController(dirModulesRoot + "controller");
fileController << codeController;
fileController.close();
auto man = new XreateManagerImpl<XreateManagerDecoratorModules<XreateManagerDecoratorFull>>();
man->prepareCode(std::move(codeMain));
fs::remove_all(dirModulesRoot);
int (*funcMain)() = (int (*)()) man->run();
int result = funcMain();
ASSERT_EQ(0, result);
}
diff --git a/cpp/tests/supplemental/versions-algorithm-data_dependency.cpp b/cpp/tests/supplemental/versions-algorithm-data_dependency.cpp
index 7a4612d..121e0ad 100644
--- a/cpp/tests/supplemental/versions-algorithm-data_dependency.cpp
+++ b/cpp/tests/supplemental/versions-algorithm-data_dependency.cpp
@@ -1,296 +1,297 @@
-
-/*
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
* File: algorithm-data_dependency
* Date: Dec 23, 2016
* Author: pgess <v.melnychenko@xreate.org>
*/
#include <unordered_set>
#include <unordered_map>
#include <string>
#include <map>
#include "gtest/gtest.h"
#include <initializer_list>
#include <cstdio>
const int V_NOVERSION = -2;
const int V_ENDOFLIFE = -1;
struct Symbol {
std::string name;
int version;
Symbol getNextVersion() const{
return Symbol{name, version+1};
}
};
namespace std
{
template<>
struct hash<Symbol>
{
typedef Symbol argument_type;
typedef std::size_t result_type;
result_type operator()(argument_type const& s) const
{
result_type const h1 ( std::hash<std::string>()(s.name) );
return h1 ^ (s.version << 1); // or use boost::hash_combine
}
};
template<>
struct equal_to<Symbol>
{
typedef Symbol argument_type;
bool operator()(const argument_type& __x, const argument_type& __y) const
{ return __x.name == __y.name && __x.version == __y.version; }
};
}
//Ограничения:
// - точно знаем следующую версию на этапе декл. (C.NV.1)
class DDSolver{
public:
void l1_applyLowerBound(const Symbol& left, const std::initializer_list<Symbol>& dependencies){
for (Symbol right: dependencies){
//lower bound:
__infs.emplace(left, right);
__sups.emplace(right, left);
}
}
void l1_applyOwnUpperBound(const Symbol& left){
//own upper bound:
//C.NV.1
__infs.emplace(left.getNextVersion(), left);
__sups.emplace(left, left.getNextVersion());
}
void l1_applyDependentUpperBound(const Symbol& left, const std::initializer_list<Symbol>& dependencies){
// additionally apply dependent upper bound
for (Symbol right: dependencies){
auto right2 = right.getNextVersion();
__infs.emplace(right2, left);
__sups.emplace(left, right2);
}
}
void addVariable(const Symbol& left, const std::initializer_list<Symbol>& dependencies){
l1_applyLowerBound(left, dependencies);
l1_applyOwnUpperBound(left);
//initialization upper bound
l1_applyDependentUpperBound(left, dependencies);
}
//TODO assert: only aliases allowed
void addAlias(const Symbol& left, const std::initializer_list<Symbol>& dependencies){
l1_applyLowerBound(left, dependencies);
l1_applyOwnUpperBound(left);
//lifetime upper bound
l1_applyDependentUpperBound(left.getNextVersion(), dependencies);
}
bool checkCyclicComponent(const Symbol& s, std::unordered_set<Symbol>& symbolsVisited, std::unordered_set<Symbol>& symbolsSups){
if (symbolsVisited.count(s)) return false;
symbolsVisited.insert(s);
symbolsSups.insert(s);
auto rangeInf = __infs.equal_range(s);
if (__infs.count(s))
for (auto sInf = rangeInf.first; sInf != rangeInf.second; ++sInf){
if (symbolsSups.count(sInf->second)) {
__flagCycle = std::make_pair(sInf->second, s);
return true;
}
if(checkCyclicComponent(sInf->second, symbolsVisited, symbolsSups)) return true;
}
symbolsSups.erase(s);
return false;
}
bool checkCyclicFull(){
std::unordered_set<Symbol> symbolsVisited, symbolsSups;
std::unordered_multimap<Symbol, Symbol>::iterator s;
for (s = __infs.begin(); s != __infs.end(); ++s){
if(checkCyclicComponent(s->first, symbolsVisited, symbolsSups)) return true;
}
return false;
}
bool validate(){
return !checkCyclicFull();
}
void solve(){
std::unordered_set<Symbol> binEnabled, binFrontier;
//seed
for (auto edge: __sups){
if (! __infs.count(edge.first)){
binEnabled.insert(edge.first);
binFrontier.insert(edge.first);
}
}
while (binFrontier.size()){
const Symbol& node= *binFrontier.begin();
//print node:
std:: printf("put (%s, %d)\n", node.name.c_str(), node.version);
auto rangeSups = __sups.equal_range(node);
for(auto sup=rangeSups.first; sup != rangeSups.second; ++sup){
bool flagEnabled = true;
auto rangeInfs = __infs.equal_range(sup->second);
for (auto inf=rangeInfs.first; inf != rangeInfs.second; ++inf){
if (!binEnabled.count(inf->second)){
flagEnabled = false;
break;
}
}
if (flagEnabled){
binEnabled.insert(sup->second);
binFrontier.insert(sup->second);
}
}
binFrontier.erase(node);
}
}
void solve2(Symbol nodeEntry, std::unordered_set<Symbol>& binPreviousNodes, std::unordered_set<Symbol>& binEnabledNodes){
binPreviousNodes.insert(nodeEntry);
auto rangeChilds = __infs.equal_range(nodeEntry);
for(auto node=rangeChilds.first; node != rangeChilds.second; ++node){
if (binEnabledNodes.count(node->second)) continue;
auto nodeError = binPreviousNodes.find(node->second);
if (nodeError != binPreviousNodes.end()){
std:: printf("(%s, %d) - (%s, %d)",
nodeError->name.c_str(), nodeError->version,
node->second.name.c_str(), node->second.version);
assert(false);
}
solve2(node->second, binPreviousNodes, binEnabledNodes);
}
std:: printf("put (%s, %d)\n", nodeEntry.name.c_str(), nodeEntry.version);
binEnabledNodes.insert(nodeEntry);
binPreviousNodes.erase(nodeEntry);
// auto rangeParents = __sups.equal_range(nodeEntry);
// for(auto node=rangeParents.first; node != rangeParents.second; ++node){
// std::unordered_set<Symbol> binEmpty;
// solve2(node->second, binEmpty, binEnabledNodes);
// }
}
void __debug_printGraph(){
for (auto edge: __infs){
std:: printf("(%s, %d) <- (%s, %d) \n",
edge.second.name.c_str(), edge.second.version,
edge.first.name.c_str(), edge.first.version);
}
}
private:
std::unordered_multimap<Symbol, Symbol> __sups;
std::unordered_multimap<Symbol, Symbol> __infs;
public:
std::pair<Symbol, Symbol> __flagCycle;
};
TEST(Datadependency, test1){
DDSolver solver;
solver.addAlias(Symbol{"c", V_NOVERSION}, {Symbol{"a", 0}});
solver.addVariable(Symbol{"a", 1}, {Symbol{"b", 0}});
solver.addVariable(Symbol{"b", 1}, {Symbol{"c", V_NOVERSION}});
solver.__debug_printGraph();
ASSERT_FALSE(solver.validate());
std:: printf("(%s, %d) - (%s, %d)",
solver.__flagCycle.first.name.c_str(), solver.__flagCycle.first.version,
solver.__flagCycle.second.name.c_str(), solver.__flagCycle.second.version);
}
TEST(Datadependency, test2){
DDSolver solver;
solver.addVariable(Symbol{"c", V_NOVERSION}, {Symbol{"a", 0}});
solver.addVariable(Symbol{"a", 1}, {Symbol{"b", 0}});
solver.addVariable(Symbol{"b", 1}, {Symbol{"c", V_NOVERSION}});
ASSERT_TRUE(solver.validate());
solver.solve();
}
TEST(Datadependency, test3){
DDSolver solver;
solver.addVariable(Symbol{"c", V_NOVERSION}, {Symbol{"a", 0}});
solver.addVariable(Symbol{"a", 1}, {Symbol{"b", 0}});
solver.addVariable(Symbol{"b", 1}, {Symbol{"c", V_NOVERSION}});
std::unordered_set<Symbol> binPreviousNodes, binEnabledNodes;
solver.solve2(Symbol{"b", 1}, binPreviousNodes, binEnabledNodes);
ASSERT_TRUE(true);
}
TEST(Datadependency, test4){
DDSolver solver;
solver.addVariable(Symbol{"c", V_NOVERSION}, {Symbol{"a", 0}});
solver.addVariable(Symbol{"a", 1}, {Symbol{"b", 0}});
solver.addVariable(Symbol{"b", 1}, {Symbol{"c", V_NOVERSION}});
std::unordered_set<Symbol> binPreviousNodes, binEnabledNodes;
solver.solve2(Symbol{"b", 1}, binPreviousNodes, binEnabledNodes);
ASSERT_TRUE(true);
}
TEST(Datadependency, test5){
DDSolver solver;
solver.addAlias(Symbol{"b", V_NOVERSION}, {Symbol{"a", 0}});
solver.addVariable(Symbol{"a", 1}, {Symbol{"b", V_NOVERSION}});
std:: printf("(%s, %d) - (%s, %d)",
solver.__flagCycle.first.name.c_str(), solver.__flagCycle.first.version,
solver.__flagCycle.second.name.c_str(), solver.__flagCycle.second.version);
ASSERT_TRUE(solver.validate());
}
TEST(Datadependency, test6){
DDSolver solver;
solver.addVariable(Symbol{"a", 1}, {Symbol{"a", 0}});
std::unordered_set<Symbol> binPreviousNodes, binEnabledNodes;
solver.solve2(Symbol{"a", 1}, binPreviousNodes, binEnabledNodes);
ASSERT_TRUE(solver.validate());
-}
\ No newline at end of file
+}
diff --git a/cpp/tests/types.cpp b/cpp/tests/types.cpp
index 8f0613f..991f55e 100644
--- a/cpp/tests/types.cpp
+++ b/cpp/tests/types.cpp
@@ -1,179 +1,181 @@
-/*
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
* types.cpp
*
* Created on: Jun 4, 2015
- * Author: pgess
+ * Author: pgess <v.melnychenko@xreate.org>
*/
#include "gtest/gtest.h"
#include "xreatemanager.h"
#include "llvmlayer.h"
#include "main/Parser.h"
using namespace std;
using namespace xreate;
using namespace xreate::grammar::main;
TEST(Types, DependantTypes1) {
string&& code = "XmlNode = type {\n"
" tag:: string,\n"
" attrs:: [string], \n"
" content:: string\n"
"}.\n";
std::unique_ptr<XreateManager> program(XreateManager::prepare(move(code)));
ExpandedType typeXmlNode = program->root->findType("XmlNode");
ASSERT_EQ(TypeOperator::STRUCT, typeXmlNode->__operator);
ASSERT_EQ(3, typeXmlNode->__operands.size());
ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(0).__value);
ASSERT_EQ(TypeOperator::ARRAY, typeXmlNode->__operands.at(1).__operator);
ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(2).__value);
}
TEST(Types, ast_ParameterizedTypes_FeatureTypeIndex_1) {
string&& code = "XmlNode = type {\n"
" tag:: string,\n"
" attrs:: [string],\n"
" content:: string\n"
"}.\n"
""
"Template = type(Leaf) {Leaf, [Leaf[content]]}."
"Concrete = type Template(XmlNode).";
std::unique_ptr<XreateManager> program(XreateManager::prepare(move(code)));
ExpandedType typeConcrete = program->root->findType("Concrete");
ASSERT_EQ(TypeOperator::STRUCT, 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 {\n"
" tag:: string,\n"
" attrs:: [string],\n"
" content:: string\n"
"}.\n"
""
"Tree = type(Leaf) {Leaf, [Tree(Leaf)]}."
"Concrete = type Tree(XmlNode).";
std::unique_ptr<XreateManager> program(XreateManager::prepare(move(code)));
ExpandedType typeConcrete = program->root->findType("Concrete");
ASSERT_EQ(TypeOperator::STRUCT, 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 {\n"
" tag:: string,\n"
" /* attrs:: [string],*/\n"
" content:: string\n"
"}.\n"
""
"Tree = type(Leaf) {Leaf, [Tree(Leaf)]}."
"Concrete = type Tree(XmlNode).";
std::unique_ptr<XreateManager> program(XreateManager::prepare(move(code)));
ExpandedType typeConcrete = program->root->findType("Concrete");
llvm::Type* raw = program->llvm->toLLVMType(typeConcrete);
}
TEST(Types, ArrayOfExternal1){
FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r");
assert(input != nullptr);
Scanner scanner(input);
Parser parser(&scanner);
parser.Parse();
AST* ast = parser.root->finalize();
CodeScope* body = ast->findFunction("test")->getEntryScope();
const ExpandedType& t2 = ast->getType(body->getDeclaration(body->getSymbol("childrenRaw")));
EXPECT_EQ(t2->__operator, TypeOperator::ARRAY);
}
TEST(Types, ExternType1){
FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r");
assert(input != nullptr);
Scanner scanner(input);
Parser parser(&scanner);
parser.Parse();
AST* ast = parser.root->finalize();
CodeScope* body = ast->findFunction("test")->getEntryScope();
const ExpandedType& t2 = ast->getType(body->getDeclaration(body->getSymbol("tree")));
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<XreateManager> program(XreateManager::prepare(move(code)));
ExpandedType typ = program->root->findType("colors");
EXPECT_EQ(TypeOperator::VARIANT, typ->__operator);
Expression eRed = program->root->findFunction("test")->getEntryScope()->getBody();
EXPECT_EQ(Operator::VARIANT, eRed.op);
const ExpandedType& typ2 = program->root->getType(eRed);
EXPECT_EQ(TypeOperator::VARIANT, typ2->__operator);
}
TEST(Types, full_VariantType_Switch1){
string&& code =
" colors = type variant{RED, BLUE, GREEN}. \n"
" test = function:: colors {GREEN()} \n"
"main = function:: int; entry { \n"
" switch(test()):: int \n"
" case (GREEN()) {0} \n"
" case default {1} \n"
"}";
XreateManager* man = XreateManager::prepare(move(code));
int (*main)() = (int (*)()) man->run();
EXPECT_EQ(0, main());
}
TEST(Types, ast_VariantType2){
std::string script=
R"Code(
Expression = type
variant {
Num:: int,
String:: string,
Func:: {name::string, arguments::[Expression]}
}.
)Code";
std::unique_ptr<XreateManager> program(XreateManager::prepare(move(script)));
ExpandedType typ = program->root->findType("Expression");
ASSERT_EQ(3, typ.get().fields.size());
}
//TEST(Types, A)
//TOTEST string type
diff --git a/scripts/containers/Containers_Implementation_LinkedList1.xreate b/scripts/containers/Containers_Implementation_LinkedList1.xreate
index aa35328..510191f 100644
--- a/scripts/containers/Containers_Implementation_LinkedList1.xreate
+++ b/scripts/containers/Containers_Implementation_LinkedList1.xreate
@@ -1,47 +1,50 @@
-
- // EXTERN INCLUDES
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+ // EXTERN INCLUDES
interface(extern-c){
xml2 = library:: pkgconfig("libxml-2.0").
include {
xml2 = ["libxml/tree.h"]
}.
}
// CONTAINERS
interface(dfa) {
operator map:: (op(seqaccess)) -> impl(solid).
operator list_range:: ()->impl(on_the_fly).
operator list:: ()->impl(solid).
operator fold:: (op(seqaccess)).
/* operator index:: (op(randaccess)). - BREAKS THE ANALYSIS. MAKE tree VIEWED AS COLLECTION */
/* operator map: (op(seqaccess)) -> impl(llvm_array | on_the_fly); */
}
import raw("core/containers.lp").
// PROGRAM
XmlNode = type {
tag:: string,
/* attrs:: [string],*/
content:: string
}.
Tree = type {Leaf, [Tree(Leaf)]}.
XmlTree = type Tree(XmlNode).
test= function:: num; entry {
filename = "scripts/containers/Containers_Implementation_LinkedList1-data.xml" :: string.
docRaw = xmlParseFile(filename) :: xmlDocPtr.
tree= xmlDocGetRootElement(docRaw) :: xmlNodePtr.
childrenRaw = tree["children"]:: [xmlNodePtr]; linkedlist(next, null).
size = loop fold(childrenRaw->child:: xmlNodePtr, 0->count):: int {
count +1::int
}.
size
}
diff --git a/scripts/dsl/regexp.xreate b/scripts/dsl/regexp.xreate
index 11d7299..608d708 100644
--- a/scripts/dsl/regexp.xreate
+++ b/scripts/dsl/regexp.xreate
@@ -1,72 +1,76 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
interface(extern-c){
xml2 = library:: pkgconfig("libxml-2.0").
include {
xml2 = ["string.h"]
}.
}
Matcher = type variant {Sequence, ZeroOrMore, Text}.
matchText = function(text::string, matcher::string, posStart::i64):: i64 {
textLength = strlen(text):: i64.
matcherLength = strlen(matcher):: i64.
if(textLength >= posStart + matcherLength):: i64{
if(strncmp(text + posStart, matcher, matcherLength) == 0):: i64 {
matcherLength
} else {-1:: i64}
} else {-2:: i64}
}
matchSequence = function(text::string, pattern::undef; interpretation(force), posStart::i64):: i64; interpretation(suppress){
textLength = length(text):: i64.
loop fold(pattern-> matcher:: undef, posStart->pos):: i64{
recognizedSymbols = match(text, matcher, pos):: i64.
if (recognizedSymbols > 0):: i64{
pos+recognizedSymbols
} else {
pos:: i64; break
}
}
}
matchZeroOrMore= function(text::string, matcher::undef; interpretation(force), posStart::i64):: i64; interpretation(suppress){
textLength = length(text):: i64.
loop fold inf(posStart->pos):: i64{
recognizedSymbols = match(text, matcher, pos):: i64.
if (recognizedSymbols > 0):: i64{
pos+recognizedSymbols
} else {
pos:: i64; break
}
}
}
match = function(text::string, pattern::undef; interpretation(force), posStart::i64)::i64; interpretation(suppress){
key= pattern[0]::Matcher.
switch variant(key) :: int
case (Sequence) {matchSequence(text, pattern[1], posStart)}
case (ZeroOrMore) {matchZeroOrMore(text, pattern[1], posStart)}
case (Text) {matchText(text, pattern[1], posStart)}
}
main = function:: i64; entry {
patternAB =
[Sequence(),
[[ZeroOrMore(), [Text(), "a"]],
[Text(), "b"]]] :: undef; interpretation(force).
// matchers = ["The ", "only ", "way "] :: [string]; interpretation(force).
match("aaab", patternAB, 0):: i64
}

Event Timeline