No OneTemporary

File Metadata

Created
Sat, Mar 14, 4:38 AM
diff --git a/config/default.json b/config/default.json
index b193258..a6f1199 100644
--- a/config/default.json
+++ b/config/default.json
@@ -1,73 +1,73 @@
{
"containers": {
"id": {
"implementations": "impl_fulfill_cluster",
"clusters": "var_cluster",
"prototypes": "proto_cluster",
"linkedlist": "linkedlist"
},
"impl": {
"solid": "solid",
"onthefly": "on_the_fly"
}
},
"logging": {
"id": "logging"
},
"function-entry": "entry",
"clasp": {
"bindings" : {
"variable": "bind",
"function": "bind_func",
"scope": "bind_scope",
"function_demand" : "bind_function_demand",
"scope_decision": "bind_scope_decision"
},
"context" : {
"decisions":{
"dependent": "resolution_dependency"
}
},
"nonevalue": "nonevalue",
"ret": {
"symbol": "retv",
"tag": "ret"
}
},
"tests": {
- "template": "latereasoning",
+ "template": "polymorphs",
"templates": {
"current-fix":"*",
"default": "*-Adhoc.*:Containers.*:Compilation.full_IFStatementWithVariantType:Types.full_VariantType_Switch1:Context.full_LateContext:Context.pathDependentContext:CFA.testLoopContextExists",
"ast": "AST.*",
"effects": "Effects.*",
"basic": "Attachments.*",
"compilation": "Compilation.*-Compilation.full_IFStatementWithVariantType",
"communication": "Communication.*",
"cfa": "CFA.*",
"containers": "Containers.*",
"dfa": "DFA.*",
"diagnostic": "Diagnostic.*",
"dsl": "Association.*:Interpretation.*",
"exploitation": "Exploitation.*",
"ExpressionSerializer": "ExpressionSerializer.*",
"externc": "InterfaceExternC.*",
"loops": "Loop.*",
"latereasoning": "LateReasoning.*",
"modules": "Modules.*",
- "polymorphs": "Polymorphs.call1",
+ "polymorphs": "Polymorphs.*",
"types": "Types.*",
"virtualization": "Virtualization.test2",
"vendorsAPI/clang": "ClangAPI.*",
"vendorsAPI/xml2": "libxml2*"
}
}
}
diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt
index c7e0c70..03464bf 100644
--- a/cpp/src/CMakeLists.txt
+++ b/cpp/src/CMakeLists.txt
@@ -1,227 +1,227 @@
cmake_minimum_required(VERSION 2.8.11)
project(xreate)
cmake_policy(SET CMP0022 NEW)
message("MODULES" ${CMAKE_MODULE_PATH})
# LLVM
#======================
FIND_PACKAGE (LLVM REQUIRED)
set(LLVM_VERSION ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR})
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message("LLVM LIB PATH:" ${LLVM_LIBRARY_DIRS})
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
INCLUDE_DIRECTORIES(${LLVM_INCLUDE_DIRS})
message(STATUS "INCLUDE DIR: ${LLVM_INCLUDE_DIRS}")
add_definitions(${LLVM_DEFINITIONS})
message("LLVM DEFS: " ${LLVM_DEFINITIONS})
llvm_map_components_to_libnames(LLVM_LIBS core nativecodegen native executionengine mcjit support option)
message("LLVM LIBS: " ${LLVM_LIBS})
# CLANG
#======================
set(CLANG_LIBS
clangCodeGen
clangASTMatchers
clangQuery
clangTooling
clangFrontend
clangSerialization
clangDriver
clangParse
clangSema
clangAnalysis
clangAST
clangEdit
clangLex
clangBasic
)
# POTASSCO
#======================
set(POTASSCO_PATH "/opt/potassco/clingo" CACHE PATH "Path to potassco sources")
set(POTASSCO_INCLUDE_PATH
${POTASSCO_PATH}/libgringo
${POTASSCO_PATH}/libclasp
${POTASSCO_PATH}/libclingo
${POTASSCO_PATH}/libprogram_opts
${POTASSCO_PATH}/liblp
)
INCLUDE_DIRECTORIES(${POTASSCO_INCLUDE_PATH})
set(LIBCLASP_LIBS
clingo
clasp
gringo
program_opts
reify
lp
)
message("CLASP LIBS: " ${LIBCLASP_LIBS})
# OTHER DEPENDENCIES
#===========================
set(JEAYESON_INCLUDE_PATH
${CMAKE_HOME_DIRECTORY}/../vendors/jeayeson/include/
)
INCLUDE_DIRECTORIES(${JEAYESON_INCLUDE_PATH})
# COCO
#===========================
set(COCO_EXECUTABLE "" CACHE PATH "Path to coco executable")
set(COCO_FRAMES_PATH "" CACHE PATH "Path to coco frames")
set(COCO_GRAMMAR_PATH ${CMAKE_HOME_DIRECTORY}/../grammar/)
set(COCO_SOURCE_FILES_MAIN
${COCO_GRAMMAR_PATH}/main/Parser.cpp
${COCO_GRAMMAR_PATH}/main/Scanner.cpp
)
set(COCO_SOURCE_FILES_MODULES
${COCO_GRAMMAR_PATH}/modules/Parser.cpp
${COCO_GRAMMAR_PATH}/modules/Scanner.cpp
)
set(COCO_SOURCE_FILES ${COCO_SOURCE_FILES_MODULES} ${COCO_SOURCE_FILES_MAIN})
INCLUDE_DIRECTORIES(${COCO_GRAMMAR_PATH})
add_custom_command(OUTPUT ${COCO_SOURCE_FILES_MAIN}
COMMAND ${COCO_GRAMMAR_PATH}/gen-grammar main ${COCO_EXECUTABLE} ${COCO_FRAMES_PATH}
WORKING_DIRECTORY ${COCO_GRAMMAR_PATH}
MAIN_DEPENDENCY ${COCO_GRAMMAR_PATH}/xreate.ATG
)
add_custom_command(OUTPUT ${COCO_SOURCE_FILES_MODULES}
COMMAND ${COCO_GRAMMAR_PATH}/gen-grammar modules ${COCO_EXECUTABLE} ${COCO_FRAMES_PATH}
WORKING_DIRECTORY ${COCO_GRAMMAR_PATH}
MAIN_DEPENDENCY ${COCO_GRAMMAR_PATH}/modules.ATG
)
message(STATUS "COCO GRAMMAR BUILD STATUS:" ${COCO_OUTPUT})
# XREATE
#======================
set(SOURCE_FILES
- clasplayer.cpp
query/polymorph.cpp
+ clasplayer.cpp
+ analysis/utils.cpp
analysis/dfagraph.cpp
pass/dfapass.cpp
compilation/targetinterpretation.cpp
pass/interpretationpass.cpp
ast.cpp
xreatemanager.cpp
analysis/typeinference.cpp
aux/xreatemanager-decorators.cpp
compilation/operators.cpp
compilation/transformations.cpp
compilation/transformersaturation.cpp
pass/compilepass.cpp
pass/versionspass.cpp
attachments.cpp
ExternLayer.cpp
analysis/cfagraph.cpp
- analysis/utils.cpp
compilation/containers.cpp
compilation/advancedinstructions.cpp
llvmlayer.cpp
utils.cpp
pass/abstractpass.cpp
pass/cfapass.cpp
contextrule.cpp
query/containers.cpp
analysis/DominatorsTreeAnalysisProvider.cpp
aux/serialization/expressionserializer.cpp
modules.cpp
)
set(XREATE_INCLUDE_DIRS
${CMAKE_CURRENT_SOURCE_DIR}/
)
INCLUDE_DIRECTORIES(${XREATE_INCLUDE_DIRS})
set(XREATE_PRIVATE_INCLUDE_DIRS
${XREATE_INCLUDE_DIRS}
${COCO_GRAMMAR_PATH}
${JEAYESON_INCLUDE_PATH}
${LLVM_INCLUDE_DIRS}
${POTASSCO_INCLUDE_PATH}
)
add_library(${PROJECT_NAME} SHARED ${COCO_SOURCE_FILES} ${SOURCE_FILES})
target_link_libraries(${PROJECT_NAME})
target_include_directories(${PROJECT_NAME} INTERFACE
${XREATE_INCLUDE_DIRS}
${COCO_GRAMMAR_PATH}
${JEAYESON_INCLUDE_PATH}
${LLVM_INCLUDE_DIRS}
${POTASSCO_INCLUDE_PATH}
)
get_directory_property(DEFINITIONS_ALL DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_DEFINITIONS)
message("definitions all: " ${DEFINITIONS_ALL})
target_compile_definitions(${PROJECT_NAME} INTERFACE ${DEFINITIONS_ALL})
get_directory_property(COMPILATION_OPTIONS_ALL DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_OPTIONS)
message("compilations all: " ${COMPILATION_OPTIONS_ALL})
target_compile_options(${PROJECT_NAME} INTERFACE ${COMPILATION_OPTIONS_ALL})
SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY
INTERFACE_LINK_LIBRARIES ${LIBCLASP_LIBS} ${CLANG_LIBS} ${LLVM_LIBS} tbb boost_system boost_filesystem
)
#${CLANG_LIBS}
#set (LINK_INTERFACE_LIBRARIES "")
# FUNCTION(PREPEND var prefix)
# SET(listVar "")
# FOREACH(f ${ARGN})
# LIST(APPEND listVar "${prefix}/${f}")
# ENDFOREACH(f)
# SET(${var} "${listVar}" PARENT_SCOPE)
# ENDFUNCTION(PREPEND)
#set(COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "-j4")
#cotire(xreate)
# MACRO (ADD_PCH_RULE _header_filename _src_list)
# SET(_gch_filename "${_header_filename}.gch")
# LIST(APPEND ${_src_list} ${_gch_filename})
# SET (_args ${CMAKE_CXX_FLAGS})
# LIST(APPEND _args -c ${_header_filename} -o ${_gch_filename})
# GET_DIRECTORY_PROPERTY(DIRINC INCLUDE_DIRECTORIES)
# foreach (_inc ${DIRINC})
# LIST(APPEND _args "-I" ${_inc})
# endforeach(_inc ${DIRINC})
# SEPARATE_ARGUMENTS(_args)
# add_custom_command(OUTPUT ${_gch_filename}
# COMMAND rm -f ${_gch_filename}
# COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1} ${_args}
# DEPENDS ${_header_filename})
# ENDMACRO(ADD_PCH_RULE _header_filename _src_list)
# ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/ast.h SOURCE_FILES)
# ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/llvmlayer.h SOURCE_FILES)
# ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/clasplayer.h SOURCE_FILES)
# ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/pass/abstractpass.h SOURCE_FILES)
diff --git a/cpp/src/analysis/dfagraph.cpp b/cpp/src/analysis/dfagraph.cpp
index fc4fbd8..19d9c44 100644
--- a/cpp/src/analysis/dfagraph.cpp
+++ b/cpp/src/analysis/dfagraph.cpp
@@ -1,239 +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/.
*
* File: DFAGraph.h
* Author: pgess <v.melnychenko@xreate.org>
*
*/
/**
* \file dfagraph.h
* \brief Data Flow Analysis(DFA) graph data
*
*/
#include "analysis/dfagraph.h"
#include "analysis/utils.h"
-#include <list>
-
using namespace std;
-
-namespace xreate {namespace dfa {
- struct VisitorNodeHash : public boost::static_visitor<size_t>
- {
- std::size_t operator()(const xreate::SymbolPacked& node) const noexcept
- {
- return 2* (node.identifier + 2 * node.scope + 3 * std::abs(node.version)) + 1;
- }
-
- std::size_t operator()(const xreate::dfa::SymbolAnonymous& node) const noexcept
- {
- return 2 * node.id;
- }
- };
-}}
-
-std::size_t
-hash<xreate::dfa::SymbolNode>::operator()(xreate::dfa::SymbolNode const& s) const noexcept
-{
- return boost::apply_visitor(xreate::dfa::VisitorNodeHash(), s);
-}
+using namespace xreate::analysis;
namespace xreate { namespace dfa {
-bool operator==(const SymbolAnonymous& s1, const SymbolAnonymous& s2){
- return s1.id == s2.id && s1.flagIsUsed == s2.flagIsUsed;
-}
-
-//NOTE: Any changes should be reflected in ParseImplAtom<SymbolPacked>
-class VisitorFormatSymbol: public boost::static_visitor<boost::format> {
-public:
-
- boost::format operator()(const SymbolPacked& node) const {
- boost::format formatSymbNamed("s(%1%,%2%,%3%)");
- return formatSymbNamed % node.identifier % node.version % node.scope ;
- }
-
- boost::format operator()(const SymbolAnonymous& node) const {
- //boost::format formatSymbAnonymous("anon(%1%)");
- boost::format formatSymbAnonymous("a%1%");
- return formatSymbAnonymous % node.id;
- }
-};
-
void
DFACallInstance::print(std::ostringstream& output) const{
boost::format formatArgs;
- boost::format formatInstance("dfa_callinstance(%1%, %2%).");
- boost::format formatRet("dfa_callret(%1%, %2%).");
+ boost::format formatInstance("dfa_callfn(%1%, %2%).");
switch (type) {
case WEAK:
formatArgs = boost::format("weak(dfa_callargs(%1%, %2%, %3%)).");
break;
case STRONG:
formatArgs = boost::format("weak(dfa_callargs(%1%, %2%, %3%)).\ndfa_callargs(%1%, %2%, %3%).");
break;
}
output << formatInstance
- % id % fnName
+ % analysis::writeSymbolNode(retActual)
+ % fnName
<< endl;
for(std::pair<SymbolPacked, SymbolNode> rec: args) {
SymbolNode argFormal(rec.first);
output << formatArgs
- % id
- % boost::apply_visitor(VisitorFormatSymbol(), argFormal)
- % boost::apply_visitor(VisitorFormatSymbol(), rec.second)
+ % analysis::writeSymbolNode(retActual)
+ % analysis::writeSymbolNode(argFormal)
+ % analysis::writeSymbolNode(rec.second)
<< endl;
}
-
- output << formatRet
- % id
- % boost::apply_visitor(VisitorFormatSymbol(), retActual)
- << endl;
}
void
DFAGraph::addDependency(const SymbolNode& node, const SymbolNode& subnode){
__dependencies.emplace(node, subnode);
if (boost::get<SymbolPacked>(&node)){
__usedSymbols.insert(node);
}
if (boost::get<SymbolPacked>(&subnode)){
__usedSymbols.insert(node);
}
}
void
DFAGraph::printDependencies(std::ostringstream& output) const{
for(const SymbolNode& root: __roots){
printDependency(output, root, root);
}
}
void
DFAGraph::printDependency(std::ostringstream& output, const SymbolNode& nodeCurrent, const SymbolNode& nodeDependent) const {
auto range = __dependencies.equal_range(nodeCurrent);
for (auto it = range.first; it != range.second; ++it){
if (boost::get<SymbolAnonymous>(&it->second)){
if (!__usedSymbols.count(it->second)){
printDependency(output, it->second, nodeDependent);
continue;
}
}
boost::format formatDependency("dfa_depends(%1%, %2%).");
output << formatDependency
- % boost::apply_visitor(VisitorFormatSymbol(), nodeDependent)
- % boost::apply_visitor(VisitorFormatSymbol(), it->second)
+ % analysis::writeSymbolNode(nodeDependent)
+ % analysis::writeSymbolNode(it->second)
<< endl;
printDependency(output, it->second, it->second);
}
}
void
DFAGraph::printInplaceAnnotations(SymbolNode node, const Expression& expression) {
// write down in-place expression tags:
boost::format formatBind("bind(%1%, %2%).");
if (expression.tags.size()) __usedSymbols.insert(node);
for (const pair<std::string, Expression>& tag : expression.tags){
for (const string& tagPart: xreate::analysis::compile(tag.second)) {
__output << formatBind
- % boost::apply_visitor(VisitorFormatSymbol(), node)
+ % analysis::writeSymbolNode(node)
% tagPart
<< endl;
}
}
}
void
DFAGraph::printAlias(const SymbolNode& symbFormal, const SymbolNode& symbActual){
__usedSymbols.insert(symbFormal); __usedSymbols.insert(symbActual);
boost::format formatAlias("dfa_alias(%1%, %2%).");
__output << formatAlias
- % boost::apply_visitor(VisitorFormatSymbol(), symbFormal)
- % boost::apply_visitor(VisitorFormatSymbol(), symbActual)
+ % analysis::writeSymbolNode(symbFormal)
+ % analysis::writeSymbolNode(symbActual)
<< endl;
}
void
DFAGraph::printWeakAlias(const SymbolNode& symbFormal, const SymbolNode& symbActual){
__usedSymbols.insert(symbFormal); __usedSymbols.insert(symbActual);
boost::format formatAlias("weak(dfa_alias(%1%, %2%)).");
__output << formatAlias
- % boost::apply_visitor(VisitorFormatSymbol(), symbFormal)
- % boost::apply_visitor(VisitorFormatSymbol(), symbActual)
+ % analysis::writeSymbolNode(symbFormal)
+ % analysis::writeSymbolNode(symbActual)
<< endl;
}
void
DFAGraph::printFunctionRet(ManagedFnPtr function, const SymbolNode& symbolRet){
boost::format formatRet("dfa_fnret(%1%, %2%).");
__usedSymbols.insert(symbolRet);
__output << formatRet
% function->getName()
- % boost::apply_visitor(VisitorFormatSymbol(), symbolRet)
+ % analysis::writeSymbolNode(symbolRet)
<< endl;
__roots.insert(symbolRet);
}
void
DFAGraph::addCallInstance(DFACallInstance&& instance){
__usedSymbols.insert(instance.retActual);
for(const auto arg: instance.args){
__usedSymbols.insert(SymbolNode(arg.first));
__usedSymbols.insert(arg.second);
}
__callInstances.push_back(std::move(instance));
}
void
DFAGraph::print(std::ostringstream& output) const{
output << endl << "%\t\tStatic analysis: DFA" << endl;
//Dependencies
printDependencies(output);
//Add generated report
output << __output.str() << endl;
//Call instances
for(const DFACallInstance& instance: __callInstances){
instance.print(output);
}
output << endl;
}
void
DFAGraph::printSymbols(ClaspLayer* clasp){
boost::format formatHint("shint(%1%, \"%2%\").");
for (const SymbolNode& node : __usedSymbols) {
- __output << "v(" << boost::apply_visitor(VisitorFormatSymbol(), node) << "). ";
+ __output << "v(" << analysis::writeSymbolNode(node) << "). ";
if (const SymbolPacked* symbol = boost::get<SymbolPacked>(&node)){
- __output << formatHint % boost::apply_visitor(VisitorFormatSymbol(), node) % clasp->getHintForPackedSymbol(*symbol);
+ __output << formatHint % analysis::writeSymbolNode(node) % clasp->getHintForPackedSymbol(*symbol);
}
__output << endl;
}
}
}} //end of namespace xreate::dfa
diff --git a/cpp/src/analysis/dfagraph.h b/cpp/src/analysis/dfagraph.h
index 44ff5f3..90a6d6f 100644
--- a/cpp/src/analysis/dfagraph.h
+++ b/cpp/src/analysis/dfagraph.h
@@ -1,79 +1,58 @@
/* 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 <v.melnychenko@xreate.org>
*
* Created on June 27, 2016, 1:50 PM
*/
#ifndef DFA_H
#define DFA_H
#include "clasplayer.h"
#include <unordered_set>
-namespace xreate { namespace dfa {
-
- struct SymbolAnonymous {
- unsigned int id;
- bool flagIsUsed = false;
- };
-
- bool operator==(const SymbolAnonymous& s1, const SymbolAnonymous& s2);
- typedef boost::variant<SymbolAnonymous, SymbolPacked> SymbolNode;
-}}
-
-namespace std {
-
- template<>
- struct hash<xreate::dfa::SymbolNode> {
- std::size_t operator()(xreate::dfa::SymbolNode const& s) const noexcept;
- };
-}
-
namespace xreate {namespace dfa {
enum DFACallInstanceType {
STRONG, WEAK
};
class DFACallInstance {
public:
- unsigned int id;
std::string fnName;
std::vector<std::pair<SymbolPacked, SymbolNode>> args;
SymbolNode retActual;
DFACallInstanceType type;
void print(std::ostringstream& output) const;
};
/** \brief Holds DFA Analysis report produced by DFAPass */
class DFAGraph : public IAnalysisReport {
public:
// DFAGraph(ClaspLayer* engine): __clasp(engine){}
virtual void print(std::ostringstream& output) const override;
void addCallInstance(DFACallInstance && instance);
void addDependency(const SymbolNode& node, const SymbolNode& subnodeBlock);
void printInplaceAnnotations(SymbolNode node, const Expression& expression);
void printAlias(const SymbolNode& symbFormal, const SymbolNode& symbActual);
void printWeakAlias(const SymbolNode& symbFormal, const SymbolNode& symbActual);
void printFunctionRet(ManagedFnPtr function, const SymbolNode& symbolRet);
void printDependencies(std::ostringstream& output) const;
void printSymbols(ClaspLayer* clasp);
private:
mutable std::ostringstream __output;
std::list<DFACallInstance> __callInstances;
std::unordered_multimap<SymbolNode, SymbolNode> __dependencies;
std::unordered_set<SymbolNode> __usedSymbols;
std::unordered_set<SymbolNode> __roots;
void printDependency(std::ostringstream& output, const SymbolNode& nodeCurrent, const SymbolNode& nodeDependent) const;
};
}} // end of namespace xreate::dfa
#endif /* DFA_H */
-
diff --git a/cpp/src/analysis/utils.cpp b/cpp/src/analysis/utils.cpp
index c089196..1d5b3d6 100644
--- a/cpp/src/analysis/utils.cpp
+++ b/cpp/src/analysis/utils.cpp
@@ -1,142 +1,165 @@
/* 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>
*/
/**
* \file aux.h
* \brief Data representation in ASP format ready for use by reasoner
*/
#include "utils.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::INVALID: {
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;
}
-}}
+
+//NOTE: Any changes should be reflected in ParseImplAtom<SymbolPacked>,
+// ParseImplAtom<SymbolNode>
+class VisitorFormatSymbol: public boost::static_visitor<boost::format> {
+public:
+
+ boost::format operator()(const SymbolPacked& node) const {
+ boost::format formatSymbNamed("s(%1%,%2%,%3%)");
+ return formatSymbNamed % node.identifier % node.version % node.scope ;
+ }
+
+ boost::format operator()(const SymbolAnonymous& node) const {
+ boost::format formatSymbAnonymous("a(%1%)");
+ return formatSymbAnonymous % node.id;
+ }
+};
+
+boost::format writeSymbolNode(const SymbolNode& symbol){
+ return boost::apply_visitor(VisitorFormatSymbol(), symbol);
+}
+
+}} //end of xreate::analysis
+
+
diff --git a/cpp/src/analysis/utils.h b/cpp/src/analysis/utils.h
index ec6a332..0abaf62 100644
--- a/cpp/src/analysis/utils.h
+++ b/cpp/src/analysis/utils.h
@@ -1,27 +1,31 @@
/* 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 <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);
-}}
+
+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 writeSymbolNode(const SymbolNode& symbol);
+
+}} //end of xreate::analysis
#endif /* AUX_H */
diff --git a/cpp/src/attachments.h b/cpp/src/attachments.h
index 9072d2c..bf087e8 100644
--- a/cpp/src/attachments.h
+++ b/cpp/src/attachments.h
@@ -1,181 +1,180 @@
/* 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 (next vacant id - 13);
// Defined attachments:
//-----------------------------------------------------
// 1 containers::Implementation
// 3 interpretation::InterpretationData
// 5 interpretation::FunctionInterpretationData
// 6 VariableVersion
// 7 IdentifierSymbol
// 8 versions::VersionImposedDependency
// 9 SymbolAlias
-// 10 CallGuard Expression
// 11 TypeInferred
// 12 LateBinding
};
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_
diff --git a/cpp/src/clasplayer.cpp b/cpp/src/clasplayer.cpp
index 325b5ac..d3d2980 100644
--- a/cpp/src/clasplayer.cpp
+++ b/cpp/src/clasplayer.cpp
@@ -1,459 +1,560 @@
/* 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
*/
/**
* \file clasplayer.h
* \brief Resoner. Wrapper over Clasp reasoner library
*/
#include "clasplayer.h"
#include "analysis/utils.h"
#include "utils.h"
#include <gringo/scripts.hh>
#include <boost/format.hpp>
#include <boost/algorithm/string/join.hpp>
#include <iostream>
#include <memory>
+#include <boost/variant/detail/apply_visitor_binary.hpp>
using namespace std;
//TODO escape identifiers started with upper case symbol
+
namespace xreate {
+ bool operator==(const SymbolAnonymous& s1, const SymbolAnonymous& s2){
+ return s1.id == s2.id && s1.flagIsUsed == s2.flagIsUsed;
+ }
+
+ struct VisitorSymbolNodeHash : public boost::static_visitor<size_t> {
+ std::size_t operator()(const xreate::SymbolPacked& node) const noexcept{
+ return 2* (node.identifier + 3 * node.scope + 5 * std::abs(node.version));
+ }
+
+ std::size_t operator()(const xreate::SymbolAnonymous& node) const noexcept{
+ return 7 * node.id;
+ }
+ };
+}
+
+namespace std {
+ std::size_t
+ hash<xreate::SymbolNode>::operator()(xreate::SymbolNode const& s) const noexcept {
+ return boost::apply_visitor(xreate::VisitorSymbolNodeHash(), s);
+ }
+ std::size_t
+ hash<xreate::SymbolGeneralized>::operator()(xreate::SymbolGeneralized const& s) const noexcept {
+ return xreate::AttachmentsId<xreate::SymbolGeneralized>::getId(s);
+ }
+}
+
+namespace xreate {
void
ClaspLayer::printWarnings(std::ostream& out) {
const std::string warningTag = "warning";
auto warningsModel = query(warningTag);
if(warningsModel.size())
for (auto warning: warningsModel) {
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) {
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");
const string& atomLateStatement = "late";
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 atomAlias = std::get<1>(parse<Gringo::Symbol, Gringo::Symbol>(atom)).name().c_str();
__model.addStaticAtom(atomAlias, atom);
} else if(atomName == atomLateStatement){
//late atom format: (Symbol, (tuple of keys), (tuple of values), late-annotation)
auto atomLate = parse<SymbolPacked, std::list<SymbolPacked>, std::list<Expression>, Gringo::Symbol>(atom);
const string& atomAlias = get<3>(atomLate).name().c_str();
__model.addLateAtom(atomAlias, get<0>(atomLate),
get<3>(atomLate), get<1>(atomLate),
get<2>(atomLate));
}
__model.addStaticAtom(atomName, atom);
}
return true;
}
void
ClaspLayer::registerReport(IAnalysisReport* report){
__reports.push_back(report);
}
void
ClaspLayer::runReports(){
for(IAnalysisReport* report: __reports){
report->print(__partGeneral);
delete report;
}
__reports.clear();
}
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;
if(ast)
for (string fn: ast->__rawImports)
{
std::ifstream file(fn);
if (!file){
std::cout << "Can't process script file: " << fn << std::endl;
assert(false);
}
while(!file.eof()){
string line;
std::getline(file, line);
out << line << endl;
}
}
}
void
ClaspLayer::addRawScript(std::string&& script){
__partGeneral << script;
}
void
ClaspLayer::run() {
involveImports();
runReports();
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(): __model(this), ast(nullptr){
}
-ReasoningModel
-ClaspLayer::queryCompiled(const std::string& atom) {
+const ReasoningModel&
+ClaspLayer::queryCompiled() {
return __model;
}
StaticModel
ClaspLayer::query(const std::string& atom){
return __model.queryStatic(atom);
}
ScopePacked
ClaspLayer::pack(const 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){
auto result = __indexSymbolNameHints.find(symbol);
return (result == __indexSymbolNameHints.end())? "" : result->second;
}
-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);
}
+class VisitorUnpackSymbol: public boost::static_visitor<SymbolGeneralized> {
+public:
+ VisitorUnpackSymbol(ClaspLayer* clasp): __clasp(clasp) {}
+
+ SymbolGeneralized operator()(const SymbolPacked& symbol) const {
+ return __clasp->unpack(symbol);
+ }
+
+ SymbolGeneralized operator()(const SymbolAnonymous& symbol) const {
+ return symbol;
+ }
+
+private:
+ ClaspLayer* __clasp;
+};
+
+class VisitorPackSymbol: public boost::static_visitor<SymbolNode> {
+public:
+ VisitorPackSymbol(ClaspLayer* clasp, const std::string& hintSymbolName)
+ : __clasp(clasp), __hint(hintSymbolName) {}
+
+ SymbolNode operator()(const Symbol& symbol) const {
+ return __clasp->pack(symbol, __hint);
+ }
+
+ SymbolNode operator()(const SymbolAnonymous& symbol) const {
+ return symbol;
+ }
+
+private:
+ ClaspLayer* __clasp;
+ std::string __hint;
+};
+
+SymbolNode ClaspLayer::pack(const SymbolGeneralized& symbol, const std::string& hintSymbolName){
+ return boost::apply_visitor(VisitorPackSymbol(this, hintSymbolName), symbol);
+}
+
+SymbolGeneralized ClaspLayer::unpack(const SymbolNode& symbol)
+{
+ return boost::apply_visitor(VisitorUnpackSymbol(this), symbol);
+}
+
boost::optional<Gringo::Symbol>
GuardedAnnotation::get(const std::list<Expression>& keys) const{
for (const auto& entry: guardedSymbols){
const std::list<Expression>& keysExpected = entry.first;
auto keysIt = keys.begin();
bool result = true;
for(const Expression& keyExpected: keysExpected){
if(! (keyExpected == *keysIt)) {result = false; break; }
++keysIt;
}
if(!result) continue;
return entry.second;
}
return boost::none;
}
std::list<Expression>
-ReasoningModel::findKeys(const std::list<SymbolPacked>& keys) {
+ReasoningModel::findKeys(const std::list<SymbolPacked>& keys) const{
std::list<Expression> result;
std::transform(keys.begin(), keys.end(), std::inserter(result, result.end()), [this](const SymbolPacked& key){
return Attachments::get<LateBinding>(this->clasp->unpack(key));
});
return result;
}
void ReasoningModel::addStaticAtom(const std::string& atomAlias, const Gringo::Symbol& atom){
modelStatic.emplace(atomAlias, atom);
}
-void ReasoningModel::addLateAtom(const std::string& alias, const SymbolPacked& symbol,
+void ReasoningModel::addLateAtom(const std::string& alias, const SymbolNode& symbol,
const Gringo::Symbol& atom, const std::list<SymbolPacked>& guardKeys,
const std::list<Expression>& guardBindings){
- LateModel& model = modelGuarded[symbol];
- if(!model.bindings.count(alias)){
- model.bindings.emplace(alias, guardKeys);
+ LateModel& model = modelGuarded[alias];
+ if(!model.bindings.count(symbol)){
+ model.bindings.emplace(symbol, guardKeys);
}
- GuardedAnnotation& annotation = model.annotations[alias];
+ GuardedAnnotation& annotation = model.annotations[symbol];
annotation.guardedSymbols.push_back(make_pair(guardBindings, atom));
}
StaticModel
-ReasoningModel::queryStatic(const std::string& alias) {
+ReasoningModel::queryStatic(const std::string& alias) const{
StaticModel result;
if (! modelStatic.count(alias)){
return result;
}
auto currentDataRange = modelStatic.equal_range(alias);
std::copy(currentDataRange.first, currentDataRange.second, std::inserter(result, result.end()));
return result;
}
StaticModel
-ReasoningModel::queryLate(const std::string& alias, const SymbolPacked& symbol){
+ReasoningModel::queryLate(const std::string& alias, const SymbolNode& symbol) const{
StaticModel result;
- if (!modelGuarded.count(symbol)) return StaticModel();
+ if (!modelGuarded.count(alias)) return StaticModel();
- const LateModel& model = modelGuarded.at(symbol);
- assert(model.bindings.count(alias));
- const list<SymbolPacked>& bindings = model.bindings.at(alias);
+ const LateModel& model = modelGuarded.at(alias);
+ assert(model.bindings.count(symbol));
+ const list<SymbolPacked>& bindings = model.bindings.at(symbol);
list<Expression>&& keys = findKeys(bindings);
- auto range = model.annotations.equal_range(alias);
- for(auto it = range.first; it != range.second; ++it){
- auto annotation = it->second.get(keys);
- if(annotation){
- result.emplace(make_pair(alias, *annotation));
- }
+ const GuardedAnnotation& annGuarded = model.annotations.at(symbol);
+ auto ann = annGuarded.get(keys);
+ if(ann){
+ result.emplace(make_pair(alias, *ann));
}
return result;
}
+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);
+}
+
Expression
ParseImplAtom<Expression>::get(const Gringo::Symbol& atom) {
switch (atom.type()) {
case Gringo::SymbolType::Num: return Expression(atom.num());
case Gringo::SymbolType::Str: return Expression(Atom<String_t>(std::string(atom.string().c_str())));
case Gringo::SymbolType::Fun:
{
//FUNC
Expression result(Operator::CALL,{Expression(Atom<Identifier_t>(std::string(atom.name().c_str())))});
for (const Gringo::Symbol& arg : atom.args()) {
result.addArg(ParseImplAtom<Expression>::get(arg));
}
return result;
}
default:
{
assert(false);
}
}
}
int
ParseImplAtom<int>::get(const Gringo::Symbol& atom) {
switch (atom.type()){
case Gringo::SymbolType::Num: return atom.num();
default: break;
}
assert(false && "Inappropriate symbol type");
}
std::string
ParseImplAtom<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");
}
SymbolPacked
ParseImplAtom<SymbolPacked>::get(const Gringo::Symbol& atom) {
- auto result = ClaspLayer::parse<unsigned int, unsigned int, unsigned int>(atom);
+ auto result = ClaspLayer::parse<int, int, int>(atom);
return SymbolPacked(std::get<0>(result), std::get<1>(result), std::get<2>(result));
};
Gringo::Symbol
ParseImplAtom<Gringo::Symbol>::get(const Gringo::Symbol& atom) {
return atom;
}
+SymbolNode
+ParseImplAtom<SymbolNode>::get(const Gringo::Symbol& atom) {
+ assert(atom.type() == Gringo::SymbolType::Fun
+ && "Inappropriate symbol type");
+
+ if (atom.name() == "a"){
+ return SymbolAnonymous{(unsigned int) std::get<0>(ClaspLayer::parse<int>(atom))};
+
+ } else if (atom.name() == "s"){
+ return ParseImplAtom<SymbolPacked>::get(atom);
+ }
+
+ assert(false && "Wrong symbol format");
+}
+
+class VisitorSymbolId: public boost::static_visitor<unsigned int> {
+public:
+ unsigned int operator()(const Symbol& symbol) const {
+ return AttachmentsId<Symbol>::getId(symbol);
+ }
+
+ unsigned int operator()(const SymbolAnonymous& symbol) const {
+ return symbol.id;
+ }
+};
+
+unsigned int
+AttachmentsId<SymbolGeneralized>::getId(const SymbolGeneralized& symbol){
+ return boost::apply_visitor(VisitorSymbolId(), symbol);
+}
+
} //end of xreate namespace
/**
* \class xreate::ClaspLayer
* \brief Reasoning and logic Solver.
*
* Wraps external brilliant fantastic tool [Clasp solver](https://potassco.org/clasp/)
*
* For building *logic program* for reasoning ClaspLayer takes input from:
* - Raw scripts. Client could append arbitrary ASP script to _logic program_. \ref addRawScript()
* - Includes. There is possibility to specify external files with ASP scripts
* to append to _logic program_. \ref involveImports() (private member)
* - Diagnostic rules. Rules that produce diagnostic messages during
* compilation(warnings) or even able to halt compilation with errors.
* addRuleWarning(), \ref registerWarning()
* - DFA data. \ref setDFAData()
* - CFA data. \ref setCFAData()
* - Dominators Analysis. See xreate::dominators::DominatorsTreeAnalysisProvider.
* Executed by \ref run()
* - Context rules. See xreate::ContextRule and general [Context Explanation](/w/concepts/context)
*
* Data sources implement xreate::IAnalysisReport. Generally, input could be loosely divided into three categories:
* - *Internally derived* data. CFA, DFA, Dominators analyses *automatically* feed reasoner by
* useful insights about data, structure and algorithms of a program
* - *User provided* data. CFA, DFA, Diagnostic/Context rules feed reasoner by
* annotations Developer specifically provides manually
* - *External* data. Raw scripts and includes feed reasoner with third-party data
* related to a different aspects of a program possibly produced by external analyzers
*
* Once ClaspLayer got input from all providers and logic program is fully constructed
* it runs external Clasp solver and receives back desired solutions.
*
* Output of Clasp reasoner is recognized and accessed via *queries*.
* IQuery represents an interface between reasoner's output and rest of Xreate.
* Each query inherits xreate::IQuery interface. Currently there are queries as follows:
* - xreate::containers::Query to catch solutions regarding Containers implementation. See [Containers Explanation](/w/concepts/containers)
* - xreate::context::ContextQuery to catch solution regarding Context. See [Context Explanation](/w/concepts/context)
*
* \sa See xreate::dfa::DFAPass, xreate::cfa::CFAPass, xreate::IQuery, xreate::IAnalysisReport, xreate::dominators::DominatorsTreeAnalysisProvider
*/
\ No newline at end of file
diff --git a/cpp/src/clasplayer.h b/cpp/src/clasplayer.h
index ec4c0b9..2328067 100644
--- a/cpp/src/clasplayer.h
+++ b/cpp/src/clasplayer.h
@@ -1,275 +1,314 @@
/* 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 <unordered_map>
#include <boost/bimap.hpp>
#include <boost/bimap/multiset_of.hpp>
#include <boost/optional.hpp>
#include <boost/scoped_ptr.hpp>
#include <list>
#include <limits>
namespace xreate {
typedef unsigned int ScopePacked;
const ScopePacked SCOPE_ABSTRACT_GLOBAL = std::numeric_limits<ScopePacked>::max();
struct SymbolPacked {
SymbolPacked(){}
SymbolPacked(ScopedSymbol i, ScopePacked s): identifier(i.id), version(i.version), scope(s){}
SymbolPacked(VNameId symbolId, versions::VariableVersion symbolVersion, ScopePacked symbolScope)
: identifier(symbolId), version(symbolVersion), scope(symbolScope){}
VNameId identifier;
versions::VariableVersion version;
ScopePacked scope;
};
+
bool operator==(const SymbolPacked& s1, const SymbolPacked& s2);
bool operator<(const SymbolPacked& s1, const SymbolPacked& s2);
+struct SymbolAnonymous {
+ unsigned int id;
+ bool flagIsUsed = false;
+};
+
+bool operator==(const SymbolAnonymous& s1, const SymbolAnonymous& s2);
+
+typedef boost::variant<SymbolAnonymous, SymbolPacked> SymbolNode;
+typedef boost::variant<SymbolAnonymous, Symbol> SymbolGeneralized;
+
+template<>
+struct AttachmentsId<SymbolGeneralized>{
+ static unsigned int getId(const SymbolGeneralized& symbol);
+};
+
+} namespace std {
+
+ template<>
+ struct hash<xreate::SymbolNode> {
+ std::size_t operator()(xreate::SymbolNode const& s) const noexcept;
+ };
+
+ template<>
+ struct hash<xreate::SymbolGeneralized> {
+ std::size_t operator()(xreate::SymbolGeneralized const& s) const noexcept;
+ };
+}
+
+namespace xreate {
+
enum class DFGConnection {
STRONG, WEAK, PROTOTYPE
};
/** \brief Designated to mark analysis results that can be composed as *logic program* */
class IAnalysisReport {
public:
/** \brief Composes *logic program* based on analysis data into ASP format and appends to a stream*/
virtual void print(std::ostringstream& output) const = 0;
virtual ~IAnalysisReport(){};
};
/** \brief Logic program query interface */
class IQuery {
public:
virtual void init(ClaspLayer* clasp) = 0;
virtual ~IQuery() {}
};
enum class QueryId {
ContainersQuery,
PolymorphQuery
};
namespace dfa{
class DFAGraph;
}
namespace cfa {
class CFAGraph;
}
typedef std::multimap<std::string, Gringo::Symbol> StaticModel;
typedef StaticModel::const_iterator StaticModelIterator;
struct GuardedAnnotation{
std::list<std::pair<std::list<Expression>, Gringo::Symbol>> guardedSymbols;
boost::optional<Gringo::Symbol> get(const std::list<Expression>& keys) const;
};
struct LateModel{
- std::map<std::string, GuardedAnnotation> annotations;
- std::map<std::string, std::list<SymbolPacked>> bindings;
+ std::unordered_map<SymbolNode, GuardedAnnotation> annotations;
+ std::unordered_map<SymbolNode, std::list<SymbolPacked>> bindings;
};
//DEBT implement querying as a view/joining iterators without actual data copying
//DEBT how to implement late model RESET(invalidate all child models)
class ReasoningModel{
public:
ReasoningModel(ClaspLayer* claspLayer): clasp(claspLayer) {}
- void addLateAtom(const std::string& alias, const SymbolPacked& symbol,
+ void addLateAtom(const std::string& alias, const SymbolNode& symbol,
const Gringo::Symbol& atom, const std::list<SymbolPacked>& guardKeys,
const std::list<Expression>& guardBindings);
void addStaticAtom(const std::string& atomAlias, const Gringo::Symbol& atom);
- StaticModel queryStatic(const std::string& atom);
- StaticModel queryLate(const std::string& alias, const SymbolPacked& symbol);
+ StaticModel queryStatic(const std::string& atom) const;
+ StaticModel queryLate(const std::string& alias, const SymbolNode& symbol) const;
private:
ClaspLayer* clasp;
StaticModel modelStatic;
- std::map<SymbolPacked, LateModel> modelGuarded;
- std::list<Expression> findKeys(const std::list<SymbolPacked>& keys);
+ std::map<std::string, LateModel> modelGuarded;
+ std::list<Expression> findKeys(const std::list<SymbolPacked>& keys) const;
};
struct LateBinding;
template<>
struct AttachmentsDict<LateBinding>{
typedef Expression Data;
static const unsigned int key = 12;
};
class ClaspLayer {
friend class ContextRule;
/**\name Data Providers Management */
///@{
public:
void registerReport(IAnalysisReport* report);
void runReports();
/** \brief Appends arbitrary string to *logic program*
*/
void addRawScript(std::string&& script);
private:
std::list<IAnalysisReport*> __reports;
/** Includes external text files to a *logic program* */
void involveImports();
///@}
/**\name Queries Management */
///@{
public:
/** \brief Adds query. See xreate::IQuery */
IQuery* registerQuery(IQuery* query, const QueryId& id);
/** \brief Returns particular query. See xreate::IQuery */
IQuery* getQuery(const QueryId& id);
template<class ...Types>
static std::tuple<Types...> parse(const Gringo::Symbol& atom);
StaticModel query(const std::string& atom);
- ReasoningModel queryCompiled(const std::string& atom);
+ const ReasoningModel& queryCompiled();
size_t getScopesCount() const;
SymbolPacked pack(const Symbol& symbol, std::string hintSymbolName = "");
ScopePacked pack(const CodeScope * const scope);
Symbol unpack(const SymbolPacked& symbol);
+ SymbolNode pack(const SymbolGeneralized& symbol, const std::string& hintSymbolName);
+ SymbolGeneralized unpack(const SymbolNode& symbol);
std::string getHintForPackedSymbol(const SymbolPacked& symbol);
///@}
private:
std::map<QueryId, IQuery*> __queries;
ReasoningModel __model;
std::map<SymbolPacked, std::string> __indexSymbolNameHints;
std::unordered_map<const CodeScope*, unsigned int> __indexScopes;
std::vector<const CodeScope*> __registryScopes;
/**\name Diagnostic */
///@{
//TODO diagnostic move over to separate provider/query
public:
/** \brief Adds diagnostic rule */
void addRuleWarning(const RuleWarning &rule);
/** \brief Registers diagnostic messages */
unsigned int registerWarning(std::string &&message);
private:
std::map<unsigned int, std::string> __warnings;
void printWarnings(std::ostream& out);
///@}
///@{
public:
ClaspLayer();
/** \brief Executes reasoning */
void run();
///@}
AST *ast;
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<int> {
static int get(const Gringo::Symbol& atom);
};
template<>
struct ParseImplAtom<std::string> {
static std::string get(const Gringo::Symbol& atom);
};
template<>
struct ParseImplAtom<SymbolPacked> {
static SymbolPacked get(const Gringo::Symbol& atom);
};
+template<>
+struct ParseImplAtom<SymbolNode> {
+ static SymbolNode get(const Gringo::Symbol& atom);
+};
+
template<>
struct ParseImplAtom<Gringo::Symbol> {
static Gringo::Symbol get(const Gringo::Symbol& atom);
};
template<class ItemType>
struct ParseImplAtom<std::list<ItemType>>{
static std::list<ItemType>
get(const Gringo::Symbol& atom){
assert (atom.type() == Gringo::SymbolType::Fun);
std::list<ItemType> result;
for (const Gringo::Symbol& arg: atom.args()) {
result.push_back(ParseImplAtom<ItemType>::get(arg));
}
return result;
}
};
template<>
struct ParseImplAtom<Expression> {
static Expression get(const Gringo::Symbol& atom);
};
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;
}
} //end of xreate namespace
#endif
diff --git a/cpp/src/compilation/polymorphcompiler.h b/cpp/src/compilation/polymorph.h
similarity index 87%
rename from cpp/src/compilation/polymorphcompiler.h
rename to cpp/src/compilation/polymorph.h
index 0d29cae..743dcda 100644
--- a/cpp/src/compilation/polymorphcompiler.h
+++ b/cpp/src/compilation/polymorph.h
@@ -1,63 +1,64 @@
/*
* 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: polymorphcompiler.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on October 7, 2017
*/
#ifndef POLYMORPHCOMPILER_H
#define POLYMORPHCOMPILER_H
#include "pass/compilepass.h"
#include "query/polymorph.h"
namespace xreate { namespace polymorph {
typedef Expression Guard;
template <class Parent>
class PolymorphCodeScopeUnit: public Parent{
public:
PolymorphCodeScopeUnit(const CodeScope* const codeScope, compilation::IFunctionUnit* f, CompilePass* compilePass)
: Parent(codeScope, f, compilePass) {}
protected:
compilation::ICallStatement* findFunction(const Expression& opCall) override {
//Check does invocation require guards
const std::string& nameCallee = opCall.getValueString();
const std::list<ManagedFnPtr>& specializations = Parent::pass->man->root->getFunctionSpecializations(nameCallee);
//Extern function
if (specializations.size() == 0){
return Parent::findFunction(opCall);
}
//No other specializations. Check if it has no guard
if (specializations.size() == 1){
if (!specializations.front()->guard.isValid()) {
return Parent::findFunction(opCall);
}
}
//Several specializations
- assert(Attachments::exists<PolymorphGuard>(opCall) && "Guard required");
- const Expression& guardSelected = Attachments::get<PolymorphGuard>(opCall);
+ PolymorphQuery* query = dynamic_cast<PolymorphQuery*>(Parent::pass->man->clasp->getQuery(QueryId::PolymorphQuery));
+ const Expression& guardSelected = query->get(opCall);
+
std::map<Guard, ManagedFnPtr> indexSpecs;
for(ManagedFnPtr specialization: specializations){
indexSpecs.emplace(specialization->guard, specialization);
}
- assert(indexSpecs.count(guardSelected) && "Can't found appropriate guard");
+ assert(indexSpecs.count(guardSelected) && "Can't find appropriate guard");
return new compilation::CallStatementRaw(Parent::pass->getFunctionUnit(indexSpecs.at(guardSelected))->compile(), Parent::pass->man->llvm);
}
};
} } //end of xreate::polymorph
#endif /* POLYMORPHCOMPILER_H */
diff --git a/cpp/src/compilation/scopedecorators.h b/cpp/src/compilation/scopedecorators.h
index adf7c72..9dfe62d 100644
--- a/cpp/src/compilation/scopedecorators.h
+++ b/cpp/src/compilation/scopedecorators.h
@@ -1,157 +1,157 @@
/* 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
*/
/**
* \file scopedecorators.h
* \brief Basic code block compilation xreate::compilation::ICodeScopeUnit decorators
*/
#ifndef SCOPEDECORATORS_H
#define SCOPEDECORATORS_H
#include "ast.h"
#include "compilation/targetinterpretation.h"
#include "compilation/versions.h"
#include "compilation/transformations.h"
-#include "compilation/polymorphcompiler.h"
+#include "compilation/polymorph.h"
#include <list>
namespace xreate {
class CompilePass;
namespace compilation {
class ICodeScopeUnit;
class IFunctionUnit;
/**\brief Caching ability for code scope compilation
* \extends xreate::compilation::ICodeScopeUnit
*/
template<class Parent>
class CachedScopeDecorator: public Parent{
typedef CachedScopeDecorator<Parent> SELF;
public:
CachedScopeDecorator(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){}
Symbol 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;
return Symbol{id, Parent::scope};
}
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{
const 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::getDefinition(s, true);
if (!declaration.isDefined()){
assert(__declarationsOverriden.count(s.identifier));
declaration = __declarationsOverriden[s.identifier];
} else {
(false); //in case of binding there should be raws provided.
}
}
*/
llvm::Value* resultRaw = Parent::processSymbol(s, hintRetVar);
self->__rawVars.emplace(s.identifier, resultRaw);
return resultRaw;
}
void
overrideDeclarations(std::list<std::pair<Symbol, Expression>> bindings){
reset();
for (auto entry: bindings){
SELF* self = dynamic_cast<SELF*>(Parent::function->getScopeUnit(entry.first.scope));
assert(self == this);
self->__declarationsOverriden.emplace(entry.first.identifier, entry.second);
}
}
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;
};
/**\brief Default code scope compilation functionality*/
typedef CachedScopeDecorator<
polymorph::PolymorphCodeScopeUnit<
::xreate::compilation::TransformationsScopeDecorator<
interpretation::InterpretationScopeDecorator<
versions::VersionsScopeDecorator<compilation::BasicCodeScopeUnit>>>>>
DefaultCodeScopeUnit;
} //end of compilation namespace
struct CachedScopeDecoratorTag;
struct VersionsScopeDecoratorTag;
template<>
struct DecoratorsDict<CachedScopeDecoratorTag>{
typedef compilation::CachedScopeDecorator<
polymorph::PolymorphCodeScopeUnit<
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/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp
index 19ef1aa..af39d52 100644
--- a/cpp/src/pass/compilepass.cpp
+++ b/cpp/src/pass/compilepass.cpp
@@ -1,718 +1,716 @@
/* 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
*/
/**
* \file compilepass.h
* \brief Compilation pass
*/
#include "compilepass.h"
#include "clasplayer.h"
#include <ast.h>
#include "llvmlayer.h"
#include "query/containers.h"
#include "compilation/containers.h"
#include "ExternLayer.h"
#include "compilation/targetinterpretation.h"
#include "pass/versionspass.h"
#include "compilation/scopedecorators.h"
#include "compilation/operators.h"
#include "analysis/typeinference.h"
#include <boost/optional.hpp>
#include <memory>
#include <iostream>
using namespace std;
using namespace llvm;
namespace xreate { namespace compilation{
std::string
BasicFunctionUnit::prepareName(){
AST* ast = IFunctionUnit::pass->man->root;
string name = ast->getFunctionSpecializations(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 BasicFunctionUnit DefaultFunctionUnit;
ICodeScopeUnit::ICodeScopeUnit(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass)
: pass(compilePass), function(f), scope(codeScope), currentBlockRaw(nullptr) {
}
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);
}
}
//Do not name function call that returns Void.
std::string nameStatement = hintDecl;
if (calleeInfo->getReturnType()->isVoidTy()){
nameStatement.clear();
}
return llvm->builder.CreateCall(__calleeTy, __callee, args, nameStatement);
}
//DESABLEDFEATURE implement inlining
class CallStatementInline : public ICallStatement {
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(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass)
: ICodeScopeUnit(codeScope, f, compilePass) {
}
llvm::Value*
BasicCodeScopeUnit::processSymbol(const Symbol& s, std::string hintRetVar) {
Expression declaration = CodeScope::getDefinition(s);
const CodeScope* scope = s.scope;
ICodeScopeUnit* scopeExternal = ICodeScopeUnit::function->getScopeUnit(scope);
llvm::Value* resultRaw;
if (scopeExternal == this){
resultRaw = process(declaration, hintRetVar);
currentBlockRaw = pass->man->llvm->builder.GetInsertBlock();
} else {
assert(scopeExternal->currentBlockRaw);
llvm::BasicBlock* blockOwn = pass->man->llvm->builder.GetInsertBlock();
pass->man->llvm->builder.SetInsertPoint(scopeExternal->currentBlockRaw);
resultRaw = scopeExternal->processSymbol(s, hintRetVar);
pass->man->llvm->builder.SetInsertPoint(blockOwn);
}
return resultRaw;
}
ICallStatement*
BasicCodeScopeUnit::findFunction(const Expression& opCall) {
const std::string& calleeName = opCall.getValueString();
LLVMLayer* llvm = pass->man->llvm;
const std::list<ManagedFnPtr>& specializations = pass->man->root->getFunctionSpecializations(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);
}
//There should be only one specialization without any valid guards at this point
return new CallStatementRaw(pass->getFunctionUnit(
pass->man->root->findFunction(calleeName))->compile(),
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::AdvancedInstructions instructions = xreate::compilation::AdvancedInstructions({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);
shared_ptr<ICallStatement> callee(findFunction(expr));
const std::string& nameCallee = expr.getValueString();
//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);
}
);
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 = 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:
{
//TASK allow multiindex compilation
assert(expr.operands.size() == 2);
assert(expr.operands[0].__state == Expression::IDENT);
const std::string& hintIdent = expr.operands[0].getValueString();
Symbol s = Attachments::get<IdentifierSymbol>(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::LIST_NAMED: 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::LIST:
{
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);
}
};
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:
{
const ExpandedType& typVariant = pass->man->root->getType(expr);
llvm::Type* typVariantRaw = l.toLLVMType(typVariant);
llvm::Type* typIdRaw = llvm::cast<llvm::StructType>(typVariantRaw)->getElementType(0);
uint64_t id = expr.getValueDouble();
llvm::Value* variantRaw = llvm::UndefValue::get(typVariantRaw);
variantRaw = l.builder.CreateInsertValue(variantRaw, llvm::ConstantInt::get(typIdRaw, id), llvm::ArrayRef<unsigned>({0}));
const bool flagDoReference = expr.operands.size();
if (flagDoReference){
const ExpandedType& subtyp = ExpandedType(typVariant->__operands.at(id));
llvm::Type* subtypRaw = l.toLLVMType(subtyp);
Attachments::put<TypeInferred>(expr.operands.at(0), subtyp);
llvm::Value* subtypValue = process(expr.operands.at(0));
llvm::Type* typStorageRaw = llvm::cast<llvm::StructType>(typVariantRaw)->getElementType(1);
llvm::Value* addrAsStorage = l.builder.CreateAlloca(typStorageRaw);
llvm::Value* addrAsSubtyp = l.builder.CreateBitOrPointerCast(addrAsStorage, subtypRaw->getPointerTo());
l.builder.CreateStore(subtypValue, addrAsSubtyp);
llvm::Value* storageRaw = l.builder.CreateLoad(typStorageRaw, addrAsStorage);
variantRaw = l.builder.CreateInsertValue(variantRaw, storageRaw, llvm::ArrayRef<unsigned>({1}));
}
return variantRaw;
}
case Operator::SWITCH_VARIANT:
{
return instructions.compileSwitchVariant(expr, DEFAULT("tmpswitch"));
}
case Operator::SEQUENCE: {
return instructions.compileSequence(expr);
}
case Operator::UNDEF: {
llvm::Type* typExprUndef = l.toLLVMType(typeinference::getType(expr, *pass->man->root));
return llvm::UndefValue::get(typExprUndef);
}
case Operator::INVALID:
assert(expr.__state != Expression::COMPOUND);
switch (expr.__state) {
case Expression::IDENT:
{
Symbol s = Attachments::get<IdentifierSymbol>(expr);
return processSymbol(s, expr.getValueString());
}
case Expression::NUMBER:
{
llvm::Type* typConst = l.toLLVMType(typeinference::getType(expr, *pass->man->root));
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);
}
currentBlockRaw = pass->man->llvm->builder.GetInsertBlock();
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(const CodeScope * const 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(const CodeScope* const scope, IFunctionUnit* function){
return new DefaultCodeScopeUnit(scope, function, this);
}
} // end of compilation
compilation::IFunctionUnit*
CompilePass::getFunctionUnit(const ManagedFnPtr& function) {
unsigned int id = function.id();
if (!functions.count(id)) {
compilation::IFunctionUnit* unit = buildFunctionUnit(function);
functions.emplace(id, unit);
return unit;
}
return functions.at(id);
}
void
CompilePass::run() {
managerTransformations = new xreate::compilation::TransformationsManager();
targetInterpretation = new interpretation::TargetInterpretation(this->man->root, this);
//Find out main function;
StaticModel model = man->clasp->query(Config::get("function-entry"));
assert(model.size() && "Error: No entry function found");
assert(model.size() == 1 && "Error: Ambiguous entry function");
string nameMain = std::get<0>(ClaspLayer::parse<std::string>(model.begin()->second));
compilation::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);
-
- Attachments::init<PolymorphGuard>();
clasp->registerQuery(new polymorph::PolymorphQuery(), QueryId::PolymorphQuery);
}
} //end of namespace xreate
/**
* \class xreate::CompilePass
* \brief Encapsulates all compilation activities
*
* xreate::CompilePass iterates over xreate::AST tree and produces executable code fed by data(via xreate::Attachments) gathered by previous passes as well as data via queries(xreate::IQuery) from xreate:ClaspLayer reasoner.
* Compilation's done using xreate::LLVMLayer(wrapper over LLVM toolchain) and based on following aspects:
* - Containers support. See \ref compilation/containers.h
* - Late Conext compilation. See xreate::context::LateContextCompiler2
* - Interpretation support. See xreate::interpretation::TargetInterpretation
* - Loop saturation support. See xreate::compilation::TransformerSaturation
* - External Code access. See xreate::ExternLayer(wrapper over Clang library)
*
* \section adaptability_sect Adaptability
* xreate::CompilePass's architecture provides adaptability by employing:
* - %Function Decorators to alter function-level compilation. See xreate::compilation::IFunctionUnit
* - Code Block Decorators to alter code block level compilation. See xreate::compilation::ICodeScopeUnit
* Default functionality defined by \ref xreate::compilation::DefaultCodeScopeUnit
* - Targets to allow more versitile extensions.
* Currently only xreate::interpretation::TargetInterpretation use Targets infrastructure. See xreate::compilation::Target
* - %Altering Function invocation. xreate::compilation::ICallStatement
*
* Client able to construct compiler with desired decorators using xreate::compilation::CompilePassCustomDecorators.
* As a handy alias, `CompilePassCustomDecorators<void, void>` constructs default compiler
*
*/
diff --git a/cpp/src/pass/dfapass.cpp b/cpp/src/pass/dfapass.cpp
index c1b34c0..7beb72f 100644
--- a/cpp/src/pass/dfapass.cpp
+++ b/cpp/src/pass/dfapass.cpp
@@ -1,234 +1,233 @@
/* 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
*/
/**
* \file dfapass.h
* \brief Data Flow Analysis(DFA)
*/
//DEBT DFA represent VersionaPass in declarative form using applyDependencies
// applyDependencies(expression, context, cache, decl);
//DEBT DFA prepare static annotations and represent InterpretationPass in declarative form
// applyStaticAnnotations(expression, context, cache, decl);
//DEBT DFA Eliminate dfa schemes
#include "pass/dfapass.h"
#include "xreatemanager.h"
#include "clasplayer.h"
#include <boost/format.hpp>
#include <boost/variant/variant.hpp>
using namespace std;
namespace xreate {namespace dfa {
DFAPass::DFAPass(PassManager* manager)
: AbstractPass(manager)
, graph{new DFAGraph()}
, clasp(manager->clasp) { }
void
DFAPass::processCallInstance(const Expression& expr, PassContext context, const SymbolNode& result) {
const string &nameCalleeFunction=expr.getValueString();
//TODO implement processFnCall/Uncertain
list<ManagedFnPtr> variantsCalleeFunction=man->root->getFunctionSpecializations(nameCalleeFunction);
vector<SymbolNode> operands;
operands.reserve(expr.getOperands().size());
for(const Expression& arg : expr.getOperands()) {
operands.push_back(process(arg, context));
}
//Set calling relations:
DFACallInstanceType type=variantsCalleeFunction.size()>1?WEAK:STRONG;
for(ManagedFnPtr function : variantsCalleeFunction) {
CodeScope *scopeRemote=function->getEntryScope();
DFACallInstance callInstance;
- callInstance.id=expr.id;
callInstance.fnName=function->getName();
callInstance.type=type;
std::vector<SymbolNode>::const_iterator nodeActual=operands.begin();
for(const std::string &identFormal : scopeRemote->__bindings) {
const ScopedSymbol symbolFormal{scopeRemote->__identifiers.at(identFormal), versions::VERSION_NONE};
SymbolPacked symbolFormalPacked=clasp->pack(Symbol{symbolFormal, scopeRemote}, nameCalleeFunction+":"+identFormal);
callInstance.args.push_back(std::make_pair(symbolFormalPacked, *nodeActual));
++nodeActual;
}
callInstance.retActual=result;
SymbolNode retFormal=SymbolNode(clasp->pack(Symbol{ScopedSymbol::RetSymbol, scopeRemote}, nameCalleeFunction+":[ret]"));
graph->addCallInstance(std::move(callInstance));
}
}
void
DFAPass::processDependencies(const SymbolNode& node, const Expression& expression, PassContext context, ProcessingCache& cache) {
cache.operands.reserve(expression.getOperands().size());
for(const Expression &op : expression.getOperands()) {
const SymbolNode& subnodeOperand=process(op, context);
cache.operands.push_back(subnodeOperand);
graph->addDependency(node, subnodeOperand);
}
cache.blocks.reserve(expression.blocks.size());
for(CodeScope* block : expression.blocks) {
const SymbolNode& subnodeBlock=process(block, context);
cache.blocks.push_back(subnodeBlock);
graph->addDependency(node, subnodeBlock);
}
}
SymbolNode
DFAPass::process(const Expression& expression, PassContext context, const std::string& varDecl) {
SymbolNode result;
if(Attachments::exists<SymbolAlias>(expression)){
Symbol varSymbol=Attachments::get<SymbolAlias>(expression);
result=clasp->pack(varSymbol, varDecl);
} else if(expression.__state==Expression::IDENT&&expression.tags.size()==0){
Symbol varSymbol=Attachments::get<IdentifierSymbol>(expression);
result=clasp->pack(varSymbol, expression.getValueString());
} else {
result=SymbolAnonymous{expression.id};
}
graph->printInplaceAnnotations(result, expression);
switch(expression.__state) {
case Expression::COMPOUND: {
switch(expression.op) {
case Operator::CALL: {
processCallInstance(expression, context, result);
break;
}
case Operator::IF: {
const SymbolNode& scopeA=process(expression.blocks.front(), context, "ifTrue" + std::to_string(expression.id));
const SymbolNode& scopeB=process(expression.blocks.back(), context, "ifFalse" + std::to_string(expression.id));
const SymbolNode& condition=process(expression.operands.at(0), context);
graph->addDependency(result, scopeA);
graph->addDependency(result, scopeB);
graph->addDependency(result, condition);
graph->printWeakAlias(result, scopeA);
graph->printWeakAlias(result, scopeB);
break;
}
case Operator::SWITCH:
case Operator::SWITCH_VARIANT: {
for(CodeScope* block : expression.blocks) {
const SymbolNode& subnodeBlock=process(block, context, "case"+to_string(block->getBody().id));
graph->addDependency(result, subnodeBlock);
graph->printWeakAlias(result, subnodeBlock);
}
const SymbolNode& condition=process(expression.operands.at(0), context);
graph->addDependency(result, condition);
break;
}
default: {
ProcessingCache cache;
processDependencies(result, expression, context, cache);
break;
}
}
break;
}
case Expression::IDENT: {
SymbolNode symbIdent=AbstractPass<SymbolNode>::process(expression, context, varDecl);
if(!(result==symbIdent)){
graph->addDependency(result, symbIdent);
graph->printAlias(result, symbIdent);
}
break;
}
case Expression::NUMBER:
case Expression::STRING: {
break;
}
case Expression::INVALID:
case Expression::BINDING: {
assert(false);
break;
}
}
return result;
}
SymbolNode
DFAPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl) {
if (!hintBlockDecl.empty()) {
Symbol symbRet{ScopedSymbol::RetSymbol, scope};
clasp->pack(symbRet, hintBlockDecl + ":[ret]");
}
for(const std::string& binding : scope->__bindings) {
Symbol bindingSymbol{scope->getSymbol(binding), scope};
SymbolPacked bindingPacked=clasp->pack(bindingSymbol, binding);
getSymbolCache().setCachedValue(bindingSymbol, SymbolNode(bindingPacked));
}
return AbstractPass<SymbolNode>::process(scope, context, hintBlockDecl);
}
SymbolNode
DFAPass::process(ManagedFnPtr function) {
clasp->pack(Symbol{ScopedSymbol::RetSymbol, function->getEntryScope()}, function->getName()+to_string(function.id())+":[ret]");
SymbolNode result=AbstractPass<SymbolNode>::process(function);
graph->printFunctionRet(function, result);
return result;
}
void
DFAPass::finish() {
clasp->registerReport(graph);
//Declare symbols:
graph->printSymbols(clasp);
AbstractPass::finish();
}
} //end of namespace dfa
template<>
-dfa::SymbolNode
+SymbolNode
defaultValue() {
assert(false);
}
} //end of xreate namespace
/**
* \class xreate::dfa::DFAPass
* \details Provides DFA, important analysis for reasoning. Iterates over AST and stores collected data in DFAGraph
*/
diff --git a/cpp/src/query/polymorph.cpp b/cpp/src/query/polymorph.cpp
index 2302d9f..d3e15db 100644
--- a/cpp/src/query/polymorph.cpp
+++ b/cpp/src/query/polymorph.cpp
@@ -1,33 +1,55 @@
/*
* 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: polymorph.cpp
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on November 9, 2017, 12:14 PM
*/
#include "polymorph.h"
using namespace std;
namespace xreate { namespace polymorph {
+const std::string atomPolymorph = "dfa_callguard";
+
void
PolymorphQuery::init(ClaspLayer* clasp){
- const std::string& atomGuard = "dfa_callguard";
+ __clasp = clasp;
- StaticModel queryResult = clasp->query(atomGuard);
+ StaticModel queryResult = clasp->query(atomPolymorph);
if (queryResult.size()){
for (auto entry: queryResult){
- unsigned int callId;
- Expression exprGuard;
- tie(callId, exprGuard)=ClaspLayer::parse<int, Expression>(entry.second);
+ auto answer = ClaspLayer::parse<SymbolNode, Expression>(entry.second);
+ SymbolNode symbCaller = std::get<0>(answer);
+ SymbolGeneralized symbCallerUnpacked = clasp->unpack(symbCaller);
+ Expression guard = std::get<1>(answer);
- Attachments::put<PolymorphGuard>(callId, exprGuard);
+ __cacheEarlyReasoning.emplace(symbCallerUnpacked, guard);
}
}
}
+Expression
+PolymorphQuery::get(const Expression& e){
+ SymbolGeneralized symbol=Attachments::exists<SymbolAlias>(e)?
+ SymbolGeneralized(Attachments::get<SymbolAlias>(e))
+ : SymbolGeneralized(SymbolAnonymous{e.id});
+
+ if (__cacheEarlyReasoning.count(symbol)){
+ return __cacheEarlyReasoning.at(symbol);
+ }
+
+ SymbolNode symbolPacked = __clasp->pack(symbol, "");
+ StaticModel answer = __clasp->queryCompiled().queryLate(atomPolymorph, symbolPacked);
+ assert(answer.size() && "Can't find a guard");
+
+ Expression result;
+ tie(result) = ClaspLayer::parse<Expression>(answer.begin()->second);
+ return result;
+}
+
}} //end of xreate::polymorph
diff --git a/cpp/src/query/polymorph.h b/cpp/src/query/polymorph.h
index de67d35..d3374c5 100644
--- a/cpp/src/query/polymorph.h
+++ b/cpp/src/query/polymorph.h
@@ -1,37 +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/.
*
* File: polymorph.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on November 9, 2017, 12:14 PM
*/
#ifndef POLYMORPHQUERY_H
#define POLYMORPHQUERY_H
#include "clasplayer.h"
-
-namespace xreate {
- struct PolymorphGuard{};
-
- template<>
- struct AttachmentsDict<PolymorphGuard>
- {
- typedef Expression Data;
- static const unsigned int key = 10;
- };
-}
+#include <unordered_map>
namespace xreate { namespace polymorph {
class PolymorphQuery: public IQuery {
public:
virtual void init(ClaspLayer* clasp) override;
+ Expression get(const Expression& e);
+
+private:
+ std::unordered_map<SymbolGeneralized, Expression> __cacheEarlyReasoning;
+ ClaspLayer* __clasp = nullptr;
};
}}//end of xreate::polymorph
#endif /* POLYMORPHQUERY_H */
diff --git a/cpp/tests/latereasoning.cpp b/cpp/tests/latereasoning.cpp
index 5e5f54d..c74916e 100644
--- a/cpp/tests/latereasoning.cpp
+++ b/cpp/tests/latereasoning.cpp
@@ -1,86 +1,88 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* latereasoning.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on April 21, 2018, 5:10 PM
*/
#include "xreatemanager.h"
#include "clasplayer.h"
#include <boost/format.hpp>
#include "gtest/gtest.h"
using namespace xreate;
TEST(LateReasoning, test2) {
FILE* input = fopen("scripts/latereasoning/test2.xreate", "r");
assert(input != nullptr);
std::unique_ptr<XreateManager> man(XreateManager::prepare(input));
int (*main)() = (int (*)())man->run();
int result = main();
ASSERT_EQ(3, result);
}
/**
* Test plan:
* - add late annotation(several variants)
* - define late bindings
* - get late variant wrt defined bindings
**/
TEST(LateReasoning, PutAndGetLateAnnotation1) {
-#define FORMATSYMBOL(s) (formatSymb % s.identifier % s.version % s.scope).str()
+ #define FORMATSYMBOL(s) (formatSymb % s.identifier % s.version % s.scope).str()
+
Attachments::init<LateBinding>();
+ Attachments::init<versions::VariableVersion>();
std::unique_ptr<ClaspLayer> clasp(new ClaspLayer());
std::unique_ptr<CodeScope> scope(new CodeScope(nullptr));
Symbol symbA = scope->addDefinition(Atom<Identifier_t>("a"), Expression());
Symbol symbB = scope->addDefinition(Atom<Identifier_t>("b"), Expression());
Symbol symbC = scope->addDefinition(Atom<Identifier_t>("c"), Expression());
Symbol symbTarget = scope->addDefinition(Atom<Identifier_t>("target"), Expression());
SymbolPacked symbpA = clasp->pack(symbA, "a");
SymbolPacked symbpB = clasp->pack(symbB, "b");
SymbolPacked symbpC = clasp->pack(symbC, "c");
SymbolPacked symbpTarget = clasp->pack(symbTarget, "target");
boost::format formatSymb("s(%1%,%2%,%3%)");
boost::format formatLateAnnotation("late(%1%, (%2%, %3%, %4%), (%5%, %6%, %7%), %8%).");
//Add `variant1` variant
clasp->addRawScript((formatLateAnnotation
% FORMATSYMBOL(symbpTarget)
% FORMATSYMBOL(symbpA) % FORMATSYMBOL(symbpB) % FORMATSYMBOL(symbpC)
% "guard1" % "guard1" % "guard1"
% "result(variant1)"
). str());
//Add `result2` variant
clasp->addRawScript((formatLateAnnotation
% FORMATSYMBOL(symbpTarget)
% FORMATSYMBOL(symbpA) % FORMATSYMBOL(symbpB) % FORMATSYMBOL(symbpC)
% "guard2" % "guard2" % "guard2"
% "result(variant2)"
). str());
clasp->run();
//Define keys
Attachments::put<LateBinding>(symbA, Expression(Operator::CALL, {Atom<Identifier_t>("guard2")}));
Attachments::put<LateBinding>(symbB, Expression(Operator::CALL, {Atom<Identifier_t>("guard2")}));
Attachments::put<LateBinding>(symbC, Expression(Operator::CALL, {Atom<Identifier_t>("guard2")}));
//Fetch late annotation
- ReasoningModel model = clasp->queryCompiled("");
+ ReasoningModel model = clasp->queryCompiled();
StaticModel answer = model.queryLate("result", symbpTarget);
ASSERT_EQ(1, answer.size());
- auto answerParsed = clasp->parse<Gringo::Symbol, Gringo::Symbol, Gringo::Symbol, Gringo::Symbol>(answer.begin()->second);
- std::tuple<std::string> answerOption = clasp->parse<std::string>(std::get<3>(answerParsed));
- ASSERT_STREQ("variant2", std::get<0>(answerOption).c_str());
+ std::tuple<std::string> answerParsed = clasp->parse<std::string>(answer.begin()->second);
+
+ ASSERT_STREQ("variant2", std::get<0>(answerParsed).c_str());
}
\ No newline at end of file
diff --git a/cpp/tests/polymorph.cpp b/cpp/tests/polymorph.cpp
index bebb948..b7a9cf7 100644
--- a/cpp/tests/polymorph.cpp
+++ b/cpp/tests/polymorph.cpp
@@ -1,63 +1,106 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* polymorph.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on October 11, 2017, 8:37 PM
*/
#include "xreatemanager.h"
#include "ast.h"
#include <list>
#include "gtest/gtest.h"
+#include "clasplayer.h"
using namespace std;
using namespace xreate;
using namespace std;
TEST(Polymorphs, ast1) {
xreate::XreateManager* man = xreate::XreateManager::prepare(
R"CODE(
guard:: a {
test = function:: int {0}
}
guard:: b {
test = function:: int {1}
}
main = function:: int; entry { test() }
)CODE");
const std::list<ManagedFnPtr>& specs = man->root->getFunctionSpecializations("test");
ASSERT_EQ(2, specs.size());
auto itSpecs = specs.begin();
ASSERT_EQ("a", (*itSpecs)->guard.getValueString());
itSpecs++;
ASSERT_EQ("b", (*itSpecs)->guard.getValueString());
}
-TEST(Polymorphs, call1) {
+TEST(Polymorphs, StaticCall1) {
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(
R"CODE(
import raw("scripts/dfa/polymorphism.lp").
guard:: a {
test = function:: int {0}
}
guard:: b {
test = function:: int {1}
}
main = function:: int; entry { test()::int; callguard(b);dfa_polym(ret)}
)CODE");
man->analyse();
int (*main)() = (int (*)()) man->run();
+ ASSERT_EQ(1, main());
+}
+
+TEST(Polymorphs, LateCall1){
+ Attachments::init<LateBinding>();
+
+ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(
+R"CODE(
+ guard:: a {
+ test = function:: int {0}
+ }
+
+ guard:: b {
+ test = function:: int {1}
+ }
+
+ main = function:: int; entry{
+ key = 0:: int; _guard.
+ if (key == 0)::int {
+ test()::int; dfa_polym(late)
+ } else {0}
+ }
+)CODE");
+
+ man->clasp->addRawScript(
+R"RULE(
+ late(SymbRet, list(SymbGuard), list(a), dfa_callguard(a)):-
+ bind(SymbRet, dfa_polym(late));
+ bind(SymbGuard, _guard).
+
+ late(SymbRet, list(SymbGuard), list(b), dfa_callguard(b)):-
+ bind(SymbRet, dfa_polym(late));
+ bind(SymbGuard, _guard).
+)RULE");
+ man->analyse();
+
+ CodeScope* scopeMainBody = man->root->findFunction("main")->getEntryScope();
+ Symbol symbKey = Symbol{scopeMainBody->getSymbol("key"), scopeMainBody};
+
+ Attachments::put<LateBinding>(symbKey, Expression(Operator::CALL, {Atom<Identifier_t>("b")}));
+ int (*main)() = (int (*)()) man->run();
+
ASSERT_EQ(1, main());
}
\ No newline at end of file
diff --git a/scripts/dfa/polymorphism.lp b/scripts/dfa/polymorphism.lp
index c0b39b7..6f5088f 100644
--- a/scripts/dfa/polymorphism.lp
+++ b/scripts/dfa/polymorphism.lp
@@ -1,16 +1,14 @@
%INPUT
% bind(Symb, callguard(..)) - binded Ann
%
%OUTPUT
% dfa_callguard(..) - ready for processing
-dfa_callguard(Instance, Guard):-
+dfa_callguard(SymbRet, Guard):-
bind(ArgActual, callguard(Guard));
- weak(dfa_callargs(Instance, _, ArgActual));
- dfa_callret(Instance, SymbRet);
+ weak(dfa_callargs(SymbRet, _, ArgActual));
bind(SymbRet, dfa_polym(arg)).
-dfa_callguard(Instance, Guard):-
+dfa_callguard(SymbRet, Guard):-
bind(SymbRet, callguard(Guard));
- dfa_callret(Instance, SymbRet);
bind(SymbRet, dfa_polym(ret)).
diff --git a/scripts/dfa/propagation.lp b/scripts/dfa/propagation.lp
index 8fbba25..fbca42f 100644
--- a/scripts/dfa/propagation.lp
+++ b/scripts/dfa/propagation.lp
@@ -1,32 +1,32 @@
%Propagates symbol bindings registered by dfa_propagation over dfa_uppy edges
%
% INPUT:
% dfa_propagation(X) - register propagated Ann
% bind(Symb, X) - initial symbol
%
% OUTPUT:
% w/dfa_uppy - UPdate or coPY
bind(SymbA, DfaAnn):- bind(SymbB, DfaAnn); dfa_propagation(DfaAnn);
1{weak(dfa_uppy(SymbA, SymbB)); weak(dfa_uppy(SymbB,SymbA))};
v(SymbA); v(SymbB).
dfa_uppy(X, Y):- bind(X, dfa_uppy(Pseudo)); bind(Y, dfa_pseudo(Pseudo)).
dfa_uppy(X, Y):- dfa_alias(X, Y).
dfa_uppy(ArgFormal, ArgActual):- dfa_callargs(_,ArgFormal, ArgActual).
dfa_uppy(RetActual, RetFormal):-
- dfa_callret(CallId, RetActual); dfa_callinstance(CallId, FnName);
+ dfa_callfn(RetActual, FnName);
dfa_fnret(FnName, RetFormal);
#count{1: dfa_fnret(FnName, RetFormal)}1.
% WEAK ANALYSIS
%=============================================================
weak(dfa_uppy(X, Y)):- dfa_uppy(X, Y).
weak(dfa_uppy(X, Y)):- weak(dfa_alias(X, Y)).
weak(dfa_uppy(ArgFormal, ArgActual)):- weak(dfa_callargs(_,ArgFormal, ArgActual)).
weak(dfa_uppy(RetActual, RetFormal)):-
- dfa_callret(CallId, RetActual); dfa_callinstance(CallId, FnName);
+ dfa_callfn(RetActual, FnName);
dfa_fnret(FnName, RetFormal).
diff --git a/scripts/exploitation/test1.assembly.lp b/scripts/exploitation/test1.assembly.lp
index 573fca4..7fcdb32 100644
--- a/scripts/exploitation/test1.assembly.lp
+++ b/scripts/exploitation/test1.assembly.lp
@@ -1,28 +1,27 @@
% INPUT
%===========================================================
expl_siteUser(Res, Scope):-
dictVarScope(Var, Scope);
bind(Var, expl_user(Res)).
expl_siteInit(Res, Scope):-
dictVarScope(Var, Scope);
bind(Var, expl_init(Res)).
+
% OUTPUT
%===========================================================
-dfa_callguard(CallInst, explInitRealImpl):-
+dfa_callguard(Var, explInitRealImpl):-
expl_init_assignments(Res, SiteInitAssigned);
bind(Var, expl_init(Res));
- dictVarScope(Var, SiteInitAssigned);
- dfa_callret(CallInst, Var).
+ dictVarScope(Var, SiteInitAssigned).
-dfa_callguard(CallInst, explInitBogusImpl):-
+dfa_callguard(Var, explInitBogusImpl):-
not expl_init_assignments(Res, SiteInit);
bind(Var, expl_init(Res));
- dictVarScope(Var, SiteInit);
- dfa_callret(CallInst, Var).
+ dictVarScope(Var, SiteInit).
% GENERAL
%===========================================================
dictVarScope(Var, Scope):- Var=s(_, _, Scope); v(Var).
diff --git a/scripts/latereasoning/test2.assembly.lp b/scripts/latereasoning/test2.assembly.lp
index a3845ac..567c43e 100644
--- a/scripts/latereasoning/test2.assembly.lp
+++ b/scripts/latereasoning/test2.assembly.lp
@@ -1,12 +1,10 @@
-dfa_callguard(Instance, Guard):- %static local decision
+dfa_callguard(InstSymbRet, Guard):- %static local decision
bind_scope(Scope, callguard(Guard), strong);
bind(InstSymbRet, dfa_polym(cntxt));
- dfa_callinstance(Instance, FnCallee);
- dfa_callret(Instance, InstSymbRet);
InstSymbRet = s(_, _, Scope).
%Register manual demand
kleo_registered_subjects(Scope, spec(FnCallee), Guard):-
bind_scope(Scope, kleo_manual_demand(FnCallee), strong);
cfa_function_specializations(FnCallee, Guard).

Event Timeline