No OneTemporary

File Metadata

Created
Sat, Mar 14, 4:30 AM
diff --git a/config/default.json b/config/default.json
index 3a6cf8e..a73a43d 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",
"transcend": {
"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",
"templates": {
- "current-fix":"Compilation.*-Compilation.Sequence1:Compilation.full_IFStatementWithVariantType",
+ "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.Syntax1",
+ "latereasoning": "LateReasoning.Compilation2",
"modules": "Modules.*",
"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 c87e905..f03ed0e 100644
--- a/cpp/src/CMakeLists.txt
+++ b/cpp/src/CMakeLists.txt
@@ -1,230 +1,231 @@
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(STATUS "LLVM DEFS: " ${LLVM_DEFINITIONS})
execute_process(
COMMAND llvm-config --libs
OUTPUT_VARIABLE LLVM_LIBS
OUTPUT_STRIP_TRAILING_WHITESPACE)
message(STATUS "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
+ compilation/latereasoning.cpp
+ analysis/typeinference.cpp
+ aux/latereasoning.cpp
+ xreatemanager.cpp
+ transcendlayer.cpp
+ analysis/dfagraph.cpp
analysis/DominatorsTreeAnalysisProvider.cpp
llvmlayer.cpp
ExternLayer.cpp
- compilation/latereasoning.cpp
pass/compilepass.cpp
query/polymorph.cpp
- transcendlayer.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/versionspass.cpp
attachments.cpp
analysis/cfagraph.cpp
compilation/containers.cpp
compilation/advancedinstructions.cpp
utils.cpp
pass/abstractpass.cpp
pass/cfapass.cpp
contextrule.cpp
query/containers.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 b80240d..ef28ec9 100644
--- a/cpp/src/analysis/dfagraph.cpp
+++ b/cpp/src/analysis/dfagraph.cpp
@@ -1,192 +1,218 @@
/* 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"
using namespace std;
using namespace xreate::analysis;
namespace xreate { namespace dfa {
void
DFACallInstance::print(std::ostringstream& output) const{
boost::format formatArgs;
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
% analysis::writeSymbolNode(retActual)
% fnName
<< endl;
for(std::pair<SymbolPacked, SymbolNode> rec: args) {
SymbolNode argFormal(rec.first);
output << formatArgs
% analysis::writeSymbolNode(retActual)
% analysis::writeSymbolNode(argFormal)
% analysis::writeSymbolNode(rec.second)
<< 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
% analysis::writeSymbolNode(nodeDependent)
% analysis::writeSymbolNode(it->second)
<< endl;
printDependency(output, it->second, it->second);
}
}
void
-DFAGraph::printInplaceAnnotations(SymbolNode node, const Expression& expression) {
+DFAGraph::printInplaceAnnotation(const SymbolNode& node, const Expression& expression) {
// write down in-place expression tags:
boost::format formatBind("bind(%1%, %2%).");
+ __usedSymbols.insert(node);
- if (expression.tags.size()) __usedSymbols.insert(node);
+ for (const string& tag: xreate::analysis::compile(expression)) {
+ __output << formatBind
+ % analysis::writeSymbolNode(node)
+ % tag
+ << endl;
+ }
+}
- for (const pair<std::string, Expression>& tag : expression.tags){
- for (const string& tagPart: xreate::analysis::compile(tag.second)) {
- __output << formatBind
- % analysis::writeSymbolNode(node)
- % tagPart
- << endl;
- }
+void
+DFAGraph::printLateAnnotation(const SymbolNode& node,
+ const Expression& expression,
+ const std::list<latereasoning::LateSymbolRecognized>& symbols,
+ const std::list<std::string>& domains){
+ boost::format formatLateAnnotation("late(%1%, (%2%), (%3%), %4%):- %5%.");
+ boost::format formatDom("%1%(%2%)");
+ std::list<std::string> exprSerialized = xreate::analysis::compile(expression);
+ assert(exprSerialized.size() == 1);
+
+ list<string> identSymbols, identNames, domainsSerialised;
+
+ auto domainI = domains.begin();
+ for(auto symbol: symbols){
+ identSymbols.push_back(analysis::writeSymbolNode(symbol.second).str());
+ identNames.push_back(symbol.first);
+ domainsSerialised.push_back((formatDom % *domainI % symbol.first).str());
+ ++domainI;
}
+
+ __output << formatLateAnnotation
+ % analysis::writeSymbolNode(node)
+ % boost::algorithm::join(identSymbols, ", ")
+ % boost::algorithm::join(identNames, ", ")
+ % exprSerialized.front()
+ % boost::algorithm::join(domainsSerialised, "; ")
+ << 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
% 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
% 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()
% 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(TranscendLayer* transcend){
boost::format formatHint("shint(%1%, \"%2%\").");
for (const SymbolNode& node : __usedSymbols) {
__output << "v(" << analysis::writeSymbolNode(node) << "). ";
if (const SymbolPacked* symbol = boost::get<SymbolPacked>(&node)){
__output << formatHint % analysis::writeSymbolNode(node) % transcend->getHintForPackedSymbol(*symbol);
}
__output << endl;
}
}
}} //end of namespace xreate::dfa
diff --git a/cpp/src/analysis/dfagraph.h b/cpp/src/analysis/dfagraph.h
index a599ac9..00ccb67 100644
--- a/cpp/src/analysis/dfagraph.h
+++ b/cpp/src/analysis/dfagraph.h
@@ -1,58 +1,65 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: dfa.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on June 27, 2016, 1:50 PM
*/
#ifndef DFA_H
#define DFA_H
#include "transcendlayer.h"
#include <unordered_set>
+namespace xreate { namespace latereasoning {
+ typedef std::pair<std::string, SymbolPacked> LateSymbolRecognized;
+}}
+
namespace xreate {namespace dfa {
enum DFACallInstanceType {
STRONG, WEAK
};
class DFACallInstance {
public:
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(TranscendLayer* engine): __transcend(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 printInplaceAnnotation(const SymbolNode& node, const Expression& expression);
+ void printLateAnnotation(const SymbolNode& node, const Expression& expression,
+ const std::list<latereasoning::LateSymbolRecognized>& symbols,
+ const std::list<std::string>& domains);
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(TranscendLayer* transcend);
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/typeinference.cpp b/cpp/src/analysis/typeinference.cpp
index 2b48e10..38b3d5d 100644
--- a/cpp/src/analysis/typeinference.cpp
+++ b/cpp/src/analysis/typeinference.cpp
@@ -1,75 +1,93 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* typeinference.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on April 16, 2017, 10:13 AM
*/
/**
* \file typeinference.h
* \brief Type inference analysis
*/
#include "typeinference.h"
#include "llvmlayer.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/DerivedTypes.h"
+#include "transcendlayer.h"
+
+using namespace std;
namespace xreate {namespace typeinference {
//TODO type conversion:
//a) automatically expand types int -> bigger int; int -> floating
//b) detect exact type of `num` based on max used numeral / function type
//c) warning if need to truncate (allow/dissalow based on annotations)
llvm::Value*
doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, llvm::IRBuilder<>& builder){
if (tyTarget->isIntegerTy() && source->getType()->isIntegerTy())
{
llvm::IntegerType* tyTargetInt = llvm::dyn_cast<llvm::IntegerType>(tyTarget);
llvm::IntegerType* tySourceInt = llvm::dyn_cast<llvm::IntegerType>(source->getType());
if (tyTargetInt->getBitWidth() < tySourceInt->getBitWidth()){
return builder.CreateCast(llvm::Instruction::Trunc, source, tyTarget);
}
if (tyTargetInt->getBitWidth() > tySourceInt->getBitWidth()){
return builder.CreateCast(llvm::Instruction::SExt, source, tyTarget);
}
}
if (source->getType()->isIntegerTy() && tyTarget->isFloatingPointTy()){
return builder.CreateCast(llvm::Instruction::SIToFP, source, tyTarget);
}
return source;
}
ExpandedType
getType(const Expression& expression, const AST& ast){
if (expression.type.isValid()){
return ast.expandType(expression.type);
}
if (expression.__state == Expression::IDENT){
Symbol s = Attachments::get<IdentifierSymbol>(expression);
return getType(CodeScope::getDefinition(s), ast);
}
if (Attachments::exists<TypeInferred>(expression)){
return Attachments::get<TypeInferred>(expression);
}
if(expression.__state==Expression::NUMBER){
return ExpandedType (TypeAnnotation(TypePrimitive::I32));
}
assert(false && "Type can't be determined for an expression");
}
+std::vector<Expression>
+getSlaveVariants(ExpandedType t, const TranscendLayer* transcend){
+ assert(t->__operator == TypeOperator::SLAVE);
+ const string& domain = t->__valueCustom;
+ StaticModel model = transcend->query(domain);
+
+ vector<Expression> result;
+ result.reserve(model.size());
+ for(auto entry: model){
+ result.push_back(get<0>(TranscendLayer::parse<Expression>(entry.second)));
+ }
+
+ return result;
+}
+
} } //end of namespace xreate::typeinference
diff --git a/cpp/src/analysis/typeinference.h b/cpp/src/analysis/typeinference.h
index 1b8cece..aa956a3 100644
--- a/cpp/src/analysis/typeinference.h
+++ b/cpp/src/analysis/typeinference.h
@@ -1,30 +1,35 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: typeinference.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on April 16, 2017, 10:17 AM
*/
#ifndef TYPEINFERENCE_H
#define TYPEINFERENCE_H
#include "ast.h"
#include "llvm/IR/IRBuilder.h"
namespace llvm {
class Value;
class Type;
};
+namespace xreate {
+ class TranscendLayer;
+};
+
namespace xreate { namespace typeinference {
llvm::Value* doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, llvm::IRBuilder<>& builder);
ExpandedType getType(const Expression& expression, const AST& ast);
+std::vector<Expression> getSlaveVariants(ExpandedType t, const TranscendLayer* transcend);
} }//namespace xreate::typeinference
#endif /* TYPEINFERENCE_H */
diff --git a/cpp/src/analysis/utils.cpp b/cpp/src/analysis/utils.cpp
index 63592f5..471e24d 100644
--- a/cpp/src/analysis/utils.cpp
+++ b/cpp/src/analysis/utils.cpp
@@ -1,160 +1,159 @@
/* 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;
}
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/ast.cpp b/cpp/src/ast.cpp
index d73895f..8a91699 100644
--- a/cpp/src/ast.cpp
+++ b/cpp/src/ast.cpp
@@ -1,977 +1,982 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Author: pgess <v.melnychenko@xreate.org>
* File: ast.cpp
*/
/**
* \file ast.h
* \brief Syntax Tree and related code
*
* \sa xreate::AST
*/
#include "ast.h"
#include "ExternLayer.h"
#include "analysis/typeinference.h"
#include <stdexcept>
#include <iostream>
//TODO BDecl. forbid multiple body declaration (ExprTyped)
namespace std {
std::size_t
hash<xreate::ScopedSymbol>::operator()(xreate::ScopedSymbol const& s) const {
return s.id ^ (s.version << 2);
}
bool
equal_to<xreate::ScopedSymbol>::operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const {
return __x.id == __y.id && __x.version == __y.version;
}
size_t
hash<xreate::Symbol>::operator()(xreate::Symbol const& s) const {
return hash<xreate::ScopedSymbol>()(s.identifier) ^ ((long int) s.scope << 1);
}
bool
equal_to<xreate::Symbol>::operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const {
return __x == __y;
};
}
using namespace std;
namespace xreate {
Atom<Identifier_t>::Atom(const std::wstring& value) {
__value = wstring_to_utf8(value);
}
Atom<Identifier_t>::Atom(std::string && name) : __value(name) {
}
const std::string&
Atom<Identifier_t>::get() const {
return __value;
}
Atom<Number_t>::Atom(wchar_t* value) {
//DEBT reconsider number literal recognition
__value = wcstol(value, 0, 10);
}
Atom<Number_t>::Atom(int value)
: __value(value) {
}
double
Atom<Number_t>::get()const {
return __value;
}
Atom<String_t>::Atom(const std::wstring& value) {
assert(value.size() >= 2);
__value = wstring_to_utf8(value.substr(1, value.size() - 2));
}
Atom<String_t>::Atom(std::string && name) : __value(name) {}
const std::string&
Atom<String_t>::get() const {
return __value;
}
class ExpressionHints {
public:
static bool
isStringValueValid(const Expression& e) {
switch (e.__state) {
case Expression::INVALID:
assert(false);
case Expression::IDENT:
case Expression::STRING:
return true;
case Expression::NUMBER:
case Expression::BINDING:
return false;
case Expression::COMPOUND:
{
switch (e.op) {
case Operator::CALL:
return true;
default: return false;
}
}
}
return false;
}
static bool
isDoubleValueValid(const Expression& e) {
switch (e.__state) {
case Expression::NUMBER:
return true;
case Expression::INVALID:
assert(false);
case Expression::IDENT:
case Expression::STRING:
case Expression::BINDING:
return false;
case Expression::COMPOUND: {
switch (e.op) {
case Operator::VARIANT:
return true;
default: return false;
}
}
}
return false;
}
};
class TypesResolver {
private:
const AST* ast;
std::map<std::string, TypeAnnotation> scope;
std::map<TypeAnnotation, int> signatures;
ExpandedType expandType(const TypeAnnotation &t, const std::vector<TypeAnnotation> &args = std::vector<TypeAnnotation>()) {
return TypesResolver(ast, scope, signatures)(t, args);
}
std::vector<TypeAnnotation>
expandOperands(const std::vector<TypeAnnotation>& operands) {
std::vector<TypeAnnotation> pack;
pack.reserve(operands.size());
std::transform(operands.begin(), operands.end(), std::inserter(pack, pack.end()),
[this](const TypeAnnotation & t) {
return expandType(t);
});
return pack;
}
public:
TypesResolver(const AST* root, const std::map<std::string, TypeAnnotation>& scopeOuter = std::map<std::string, TypeAnnotation>(),
std::map<TypeAnnotation, int> signaturesOuter = std::map<TypeAnnotation, int>())
: ast(root), scope(scopeOuter), signatures(signaturesOuter) {
}
ExpandedType
operator()(const TypeAnnotation &t, const std::vector<TypeAnnotation> &args = std::vector<TypeAnnotation>()) {
//assert(args.size() == t.bindings.size()); // invalid number of arguments
for (size_t i = 0; i < args.size(); ++i) {
scope[t.bindings.at(i)] = args.at(i);
}
switch (t.__operator) {
case TypeOperator::LIST:
{
assert(t.__operands.size() == 1);
Expanded<TypeAnnotation> elTy = expandType(t.__operands.at(0));
return ExpandedType(TypeAnnotation(tag_array, elTy, 0));
}
case TypeOperator::LIST_NAMED:
{
std::vector<TypeAnnotation>&& packOperands = expandOperands(t.__operands);
auto typNew = TypeAnnotation(TypeOperator::LIST_NAMED, move(packOperands));
typNew.fields = t.fields;
return ExpandedType(move(typNew));
};
case TypeOperator::VARIANT:
{
std::vector<TypeAnnotation>&& packOperands = expandOperands(t.__operands);
auto typNew = TypeAnnotation(TypeOperator::VARIANT, move(packOperands));
typNew.fields = t.fields;
return ExpandedType(move(typNew));
};
case TypeOperator::CALL:
{
std::string alias = t.__valueCustom;
//find in local scope:
TypeAnnotation ty;
if (scope.count(alias)) {
ty = scope.at(alias);
} else if (ast->__indexTypeAliases.count(alias)) {
ty = ast->__indexTypeAliases.at(alias);
} else {
assert(false && "Undefined or external type");
}
std::vector<TypeAnnotation>&& operands = expandOperands(t.__operands);
TypeAnnotation signature(TypeOperator::CALL, move(operands));
signature.__valueCustom = alias;
if (signatures.count(signature)) {
auto link = TypeAnnotation(TypeOperator::LINK,{});
link.conjuctionId = signatures.at(signature);
return ExpandedType(move(link));
}
int cid = signatures.size();
signatures[signature] = cid;
TypeAnnotation tyResult = expandType(ty, operands);
tyResult.conjuctionId = cid;
return ExpandedType(move(tyResult));
};
case TypeOperator::CUSTOM:
{
if (signatures.count(t)) {
return ExpandedType(TypeAnnotation(TypeOperator::LINK, {t}));
}
signatures.emplace(t, signatures.size());
std::string alias = t.__valueCustom;
//find in local scope:
if (scope.count(alias)) {
return expandType(scope.at(alias));
}
//find in general scope:
if (ast->__indexTypeAliases.count(alias)) {
return expandType(ast->__indexTypeAliases.at(t.__valueCustom));
}
//if type is unknown keep it as is.
return ExpandedType(TypeAnnotation(t));
};
case TypeOperator::ACCESS:
{
std::string alias = t.__valueCustom;
ExpandedType tyAlias = ExpandedType(TypeAnnotation());
//Find in local scope:
if (scope.count(alias)) {
tyAlias = expandType(scope.at(alias));
//Find in global scope:
} else if ((ast->__indexTypeAliases.count(alias))) {
tyAlias = expandType(ast->__indexTypeAliases.at(alias));
} else {
assert(false && "Undefined or external type");
}
assert(tyAlias->__operator == TypeOperator::LIST_NAMED);
for (const string& field : t.fields) {
auto fieldIt = std::find(tyAlias->fields.begin(), tyAlias->fields.end(), field);
assert(fieldIt != tyAlias->fields.end() && "unknown field");
int fieldId = fieldIt - tyAlias->fields.begin();
tyAlias = expandType(tyAlias->__operands.at(fieldId));
}
return tyAlias;
}
case TypeOperator::NONE:
{
return ExpandedType(TypeAnnotation(t));
}
+ case TypeOperator::SLAVE:
+ {
+ return ExpandedType(t);
+ }
+
default:
assert(false);
}
assert(false);
return ExpandedType(TypeAnnotation());
}
};
TypeAnnotation::TypeAnnotation()
: __operator(TypeOperator::NONE), __value(TypePrimitive::Invalid) {
}
TypeAnnotation::TypeAnnotation(TypePrimitive typ)
: __value(typ) {
}
TypeAnnotation::TypeAnnotation(TypeOperator op, std::initializer_list<TypeAnnotation> operands)
: __operator(op), __operands(operands) {
}
TypeAnnotation::TypeAnnotation(TypeOperator op, std::vector<TypeAnnotation>&& operands)
: __operator(op), __operands(operands) {
}
TypeAnnotation::TypeAnnotation(llvm_array_tag, TypeAnnotation typ, int size)
: TypeAnnotation(TypeOperator::LIST,{typ}) {
__size = size;
}
bool
TypeAnnotation::isValid() const {
return !(__value == TypePrimitive::Invalid && __operator == TypeOperator::NONE);
}
bool
TypeAnnotation::operator<(const TypeAnnotation& t) const {
if (__operator != t.__operator) return __operator < t.__operator;
if (__operator == TypeOperator::NONE)
return __value < t.__value;
if (__operator == TypeOperator::CALL || __operator == TypeOperator::CUSTOM || __operator == TypeOperator::ACCESS) {
if (__valueCustom != t.__valueCustom)
return __valueCustom < t.__valueCustom;
}
return __operands < t.__operands;
}
/*
TypeAnnotation (struct_tag, std::initializer_list<TypeAnnotation>)
{}
*/
void
TypeAnnotation::addBindings(std::vector<Atom<Identifier_t>>&& params) {
bindings.reserve(bindings.size() + params.size());
std::transform(params.begin(), params.end(), std::inserter(bindings, bindings.end()),
[](const Atom<Identifier_t>& ident) {
return ident.get(); });
}
void
TypeAnnotation::addFields(std::vector<Atom<Identifier_t>>&& listFields) {
fields.reserve(fields.size() + listFields.size());
std::transform(listFields.begin(), listFields.end(), std::inserter(fields, fields.end()),
[](const Atom<Identifier_t>& ident) {
return ident.get(); });
}
unsigned int Expression::nextVacantId = 0;
Expression::Expression(const Atom<Number_t>& number)
: Expression() {
__state = NUMBER;
op = Operator::INVALID;
__valueD = number.get();
}
Expression::Expression(const Atom<String_t>& a)
: Expression() {
__state = STRING;
op = Operator::INVALID;
__valueS = a.get();
}
Expression::Expression(const Atom<Identifier_t> &ident)
: Expression() {
__state = IDENT;
op = Operator::INVALID;
__valueS = ident.get();
}
Expression::Expression(const Operator &oprt, std::initializer_list<Expression> params)
: Expression() {
__state = COMPOUND;
op = oprt;
if (op == Operator::CALL) {
assert(params.size() > 0);
Expression arg = *params.begin();
assert(arg.__state == Expression::IDENT);
__valueS = std::move(arg.__valueS);
operands.insert(operands.end(), params.begin() + 1, params.end());
return;
}
operands.insert(operands.end(), params.begin(), params.end());
}
void
Expression::setOp(Operator oprt) {
op = oprt;
switch (op) {
case Operator::INVALID:
__state = INVALID;
break;
default:
__state = COMPOUND;
break;
}
}
void
Expression::addArg(Expression &&arg) {
operands.push_back(arg);
}
void
Expression::addTags(const std::list<Expression> tags) const {
std::transform(tags.begin(), tags.end(), std::inserter(this->tags, this->tags.end()),
[](const Expression & tag) {
return make_pair(tag.getValueString(), tag);
});
}
void
Expression::addBindings(std::initializer_list<Atom<Identifier_t>> params) {
addBindings(params.begin(), params.end());
}
void
Expression::bindType(TypeAnnotation t) {
type = move(t);
}
void
Expression::addBlock(ManagedScpPtr scope) {
blocks.push_back(scope.operator->());
}
const std::vector<Expression>&
Expression::getOperands() const {
return operands;
}
double
Expression::getValueDouble() const {
return __valueD;
}
const std::string&
Expression::getValueString() const {
return __valueS;
}
void
Expression::setValue(const Atom<Identifier_t>&& v) {
__valueS = v.get();
}
void Expression::setValueDouble(double value) {
__valueD = value;
}
bool
Expression::isValid() const {
return (__state != INVALID);
}
bool
Expression::isDefined() const {
return (__state != BINDING && __state != INVALID);
}
Expression::Expression()
: __state(INVALID), op(Operator::INVALID), id(nextVacantId++) {
}
namespace details { namespace inconsistent {
AST::AST() {
Attachments::init<versions::VariableVersion>();
Attachments::init<IdentifierSymbol>();
Attachments::init<SymbolAlias>();
Attachments::init<TypeInferred>();
}
void
AST::addInterfaceData(const ASTInterface& interface, Expression&& data) {
__interfacesData.emplace(interface, move(data));
}
void
AST::addDFAData(Expression &&data) {
__dfadata.push_back(data);
}
void
AST::addExternData(ExternData &&data) {
__externdata.insert(__externdata.end(), data.entries.begin(), data.entries.end());
}
void
AST::add(Function* f) {
__functions.push_back(f);
__indexFunctions.emplace(f->getName(), __functions.size() - 1);
}
void
AST::add(MetaRuleAbstract *r) {
__rules.push_back(r);
}
void
AST::add(TypeAnnotation t, Atom<Identifier_t> alias) {
if (t.__operator == TypeOperator::VARIANT) {
for (int i = 0, size = t.fields.size(); i < size; ++i) {
__dictVariants.emplace(t.fields[i], make_pair(t, i));
}
}
__indexTypeAliases.emplace(alias.get(), move(t));
}
ManagedScpPtr
AST::add(CodeScope* scope) {
this->__scopes.push_back(scope);
return ManagedScpPtr(this->__scopes.size() - 1, &this->__scopes);
}
std::string
AST::getModuleName() {
const std::string name = "moduleTest";
return name;
}
ManagedPtr<Function>
AST::findFunction(const std::string& name) {
int count = __indexFunctions.count(name);
if (!count) {
return ManagedFnPtr::Invalid();
}
assert(count == 1);
auto range = __indexFunctions.equal_range(name);
return ManagedPtr<Function>(range.first->second, &this->__functions);
}
std::list<ManagedFnPtr>
AST::getAllFunctions() const {
const size_t size = __functions.size();
std::list<ManagedFnPtr> result;
for (size_t i = 0; i < size; ++i) {
result.push_back(ManagedFnPtr(i, &this->__functions));
}
return result;
}
//TASK select default specializations
std::list<ManagedFnPtr>
AST::getFunctionSpecializations(const std::string& fnName) const {
auto functions = __indexFunctions.equal_range(fnName);
std::list<ManagedFnPtr> result;
std::transform(functions.first, functions.second, inserter(result, result.end()),
[this](auto f) {
return ManagedFnPtr(f.second, &this->__functions);
});
return result;
}
template<>
ManagedPtr<Function>
AST::begin<Function>() {
return ManagedPtr<Function>(0, &this->__functions);
}
template<>
ManagedPtr<CodeScope>
AST::begin<CodeScope>() {
return ManagedPtr<CodeScope>(0, &this->__scopes);
}
template<>
ManagedPtr<MetaRuleAbstract>
AST::begin<MetaRuleAbstract>() {
return ManagedPtr<MetaRuleAbstract>(0, &this->__rules);
}
void
AST::recognizeVariantConstructor(Expression& function) {
assert(function.op == Operator::CALL);
std::string variant = function.getValueString();
if (!__dictVariants.count(variant)) {
return;
}
auto record = __dictVariants.at(variant);
const TypeAnnotation& typ = record.first;
function.op = Operator::VARIANT;
function.setValueDouble(record.second);
function.type = typ;
}
Atom<Number_t>
AST::recognizeVariantConstructor(Atom<Identifier_t> ident) {
std::string variant = ident.get();
assert(__dictVariants.count(variant) && "Can't recognize variant constructor");
auto record = __dictVariants.at(variant);
return Atom<Number_t>(record.second);
}
void
AST::postponeIdentifier(CodeScope* scope, const Expression& id) {
bucketUnrecognizedIdentifiers.emplace(scope, id);
}
void
AST::recognizePostponedIdentifiers() {
for (const auto& identifier : bucketUnrecognizedIdentifiers) {
if (!identifier.first->recognizeIdentifier(identifier.second)) {
//exception: Ident not found
std::cout << "Unknown symbol: " << identifier.second.getValueString() << std::endl;
assert(false && "Symbol not found");
}
}
}
xreate::AST*
AST::finalize() {
//all finalization steps:
recognizePostponedIdentifiers();
return reinterpret_cast<xreate::AST*> (this);
}
} } //namespace details::incomplete
Expanded<TypeAnnotation>
AST::findType(const std::string& name) {
// find in general scope:
if (__indexTypeAliases.count(name))
return expandType(__indexTypeAliases.at(name));
//if type is unknown keep it as is.
TypeAnnotation t(TypeOperator::CUSTOM,{});
t.__valueCustom = name;
return ExpandedType(move(t));
}
Expanded<TypeAnnotation>
AST::expandType(const TypeAnnotation &t) const {
return TypesResolver(this)(t);
}
ExpandedType
AST::getType(const Expression& expression) {
return typeinference::getType(expression, *this);
}
Function::Function(const Atom<Identifier_t>& name)
: __entry(new CodeScope(0)) {
__name = name.get();
}
void
Function::addTag(Expression&& tag, const TagModifier mod) {
string name = tag.getValueString();
__tags.emplace(move(name), move(tag));
}
const std::map<std::string, Expression>&
Function::getTags() const {
return __tags;
}
CodeScope*
Function::getEntryScope() const {
return __entry;
}
void
Function::addBinding(Atom <Identifier_t>&& name, Expression&& argument) {
__entry->addBinding(move(name), move(argument));
}
const std::string&
Function::getName() const {
return __name;
}
ScopedSymbol
CodeScope::registerIdentifier(const Expression& identifier) {
versions::VariableVersion version = Attachments::get<versions::VariableVersion>(identifier, versions::VERSION_NONE);
auto result = __identifiers.emplace(identifier.getValueString(), __vCounter);
if (result.second) {
++__vCounter;
return { __vCounter - 1, version };
}
return { result.first->second, version };
}
bool
CodeScope::recognizeIdentifier(const Expression& identifier) const {
versions::VariableVersion version = Attachments::get<versions::VariableVersion>(identifier, versions::VERSION_NONE);
const std::string& name = identifier.getValueString();
//search identifier in the current block
if (__identifiers.count(name)) {
VNameId id = __identifiers.at(name);
Symbol s;
s.identifier = ScopedSymbol{id, version};
s.scope = const_cast<CodeScope*> (this);
Attachments::put<IdentifierSymbol>(identifier, s);
return true;
}
//search in the parent scope
if (__parent) {
return __parent->recognizeIdentifier(identifier);
}
return false;
}
ScopedSymbol
CodeScope::getSymbol(const std::string& alias) {
assert(__identifiers.count(alias));
VNameId id = __identifiers.at(alias);
return {id, versions::VERSION_NONE };
}
void
CodeScope::addBinding(Expression&& var, Expression&& argument) {
argument.__state = Expression::BINDING;
__bindings.push_back(var.getValueString());
ScopedSymbol binding = registerIdentifier(var);
__declarations[binding] = move(argument);
}
Symbol
CodeScope::addDefinition(Expression&& var, Expression&& body) {
ScopedSymbol s = registerIdentifier(var);
__declarations[s] = move(body);
return Symbol{s, this};
}
CodeScope::CodeScope(CodeScope* parent)
: __parent(parent) {
}
CodeScope::~CodeScope() {
}
void
CodeScope::setBody(const Expression &body) {
assert(__declarations.count(ScopedSymbol::RetSymbol)==0 && "Attempt to reassign scope body");
__declarations[ScopedSymbol::RetSymbol] = body;
}
const Expression&
CodeScope::getBody() const{
return __declarations.at(ScopedSymbol::RetSymbol);
}
const Expression&
CodeScope::getDefinition(const Symbol& symbol, bool flagAllowUndefined){
const CodeScope* self = symbol.scope;
return self->getDefinition(symbol.identifier, flagAllowUndefined);
}
const Expression&
CodeScope::getDefinition(const ScopedSymbol& symbol, bool flagAllowUndefined) const{
static Expression expressionInvalid;
if (!__declarations.count(symbol)){
if (flagAllowUndefined) return expressionInvalid;
assert(false && "Symbol's declaration not found");
}
return __declarations.at(symbol);
}
void
RuleArguments::add(const Atom<Identifier_t> &arg, DomainAnnotation typ) {
emplace_back(arg.get(), typ);
}
void
RuleGuards::add(Expression&& e) {
push_back(e);
}
MetaRuleAbstract::
MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards)
: __args(std::move(args)), __guards(std::move(guards)) {
}
MetaRuleAbstract::~MetaRuleAbstract() {
}
RuleWarning::
RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom<String_t>&& message)
: MetaRuleAbstract(std::move(args), std::move(guards)), __message(message.get()), __condition(condition) {
}
RuleWarning::~RuleWarning() {
}
void
RuleWarning::compile(TranscendLayer& layer) {
//TODO restore addRuleWarning
//layer.addRuleWarning(*this);
}
bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2) {
return (s1.id < s2.id) || (s1.id == s2.id && s1.version < s2.version);
}
bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2) {
return (s1.id == s2.id) && (s1.version == s2.version);
}
bool operator<(const Symbol& s1, const Symbol& s2) {
return (s1.scope < s2.scope) || (s1.scope == s2.scope && s1.identifier < s2.identifier);
}
bool operator==(const Symbol& s1, const Symbol& s2) {
return (s1.scope == s2.scope) && (s1.identifier == s2.identifier);
}
bool operator<(const Expression&a, const Expression&b) {
if (a.__state != b.__state) return a.__state < b.__state;
assert(a.__state != Expression::INVALID);
switch (a.__state) {
case Expression::IDENT:
case Expression::STRING:
return a.getValueString() < b.getValueString();
case Expression::NUMBER:
return a.getValueDouble() < b.getValueDouble();
case Expression::COMPOUND:
{
assert(a.blocks.size() == 0);
assert(b.blocks.size() == 0);
if (a.op != b.op) {
return a.op < b.op;
}
bool flagAValid = ExpressionHints::isStringValueValid(a);
bool flagBValid = ExpressionHints::isStringValueValid(b);
if (flagAValid != flagBValid) {
return flagAValid < flagBValid;
}
if (flagAValid) {
if (a.getValueString() != b.getValueString()) {
return a.getValueString() < b.getValueString();
}
}
flagAValid = ExpressionHints::isDoubleValueValid(a);
flagBValid = ExpressionHints::isDoubleValueValid(b);
if (flagAValid != flagBValid) {
return flagAValid < flagBValid;
}
if (flagAValid) {
if (a.getValueDouble() != b.getValueDouble()) {
return a.getValueDouble() < b.getValueDouble();
}
}
if (a.operands.size() != b.operands.size()) {
return (a.operands.size() < b.operands.size());
}
for (size_t i = 0; i < a.operands.size(); ++i) {
bool result = a.operands[i] < b.operands[i];
if (result) return true;
}
return false;
}
case Expression::BINDING:
case Expression::INVALID:
assert(false);
}
return false;
}
bool
Expression::operator==(const Expression& other) const {
if (this->__state != other.__state) return false;
if (ExpressionHints::isStringValueValid(*this)) {
if (this->__valueS != other.__valueS) return false;
}
if (ExpressionHints::isDoubleValueValid(*this)) {
if (this->__valueD != other.__valueD) return false;
}
if (this->__state != Expression::COMPOUND) {
return true;
}
if (this->op != other.op) {
return false;
}
if (this->operands.size() != other.operands.size()) {
return false;
}
for (size_t i = 0; i<this->operands.size(); ++i) {
if (!(this->operands[i] == other.operands[i])) return false;
}
assert(!this->blocks.size());
assert(!other.blocks.size());
return true;
}
const ScopedSymbol
ScopedSymbol::RetSymbol = ScopedSymbol{0, versions::VERSION_NONE};
} //end of namespace xreate
diff --git a/cpp/src/ast.h b/cpp/src/ast.h
index e37d755..7052451 100644
--- a/cpp/src/ast.h
+++ b/cpp/src/ast.h
@@ -1,741 +1,741 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Author: pgess <v.melnychenko@xreate.org>
* File: ast.h
*/
#ifndef AST_H
#define AST_H
#include "attachments.h"
#include <vector>
#include <stdlib.h>
#include <string>
#include <list>
#include <unordered_map>
#include <unordered_set>
#include <climits>
#include "utils.h"
#include <algorithm>
namespace llvm {
class Value;
}
namespace xreate {
struct ScopedSymbol;
struct Symbol;
}
namespace std {
template<>
struct hash<xreate::ScopedSymbol> {
std::size_t operator()(xreate::ScopedSymbol const& s) const;
};
template<>
struct equal_to<xreate::ScopedSymbol> {
bool operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const;
};
template<>
struct hash<xreate::Symbol> {
size_t operator()(xreate::Symbol const& s) const;
};
template<>
struct equal_to<xreate::Symbol> {
bool operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const;
};
}
namespace xreate {
struct String_t {
};
struct Identifier_t {
};
struct Number_t {
};
struct Type_t {
};
template<typename A>
class Atom {
};
//DEBT store line:col for all atoms/identifiers
template<> class
Atom<Identifier_t> {
public:
Atom(const std::wstring& value);
Atom(std::string && name);
const std::string& get() const;
private:
std::string __value;
};
template<>
class Atom<Number_t> {
public:
Atom(wchar_t* value);
Atom(int value);
double get()const;
private:
double __value;
};
template<>
class Atom<String_t> {
public:
Atom(const std::wstring& value);
Atom(std::string && name);
const std::string& get() const;
private:
std::string __value;
};
enum class TypePrimitive {
Invalid, Bool, I8, I32, I64, Num, Int, Float, String
};
enum class TypeOperator {
- NONE, CALL, CUSTOM, VARIANT, LIST, LIST_NAMED, ACCESS, LINK
+ NONE, CALL, CUSTOM, VARIANT, LIST, LIST_NAMED, ACCESS, LINK, SLAVE
};
struct llvm_array_tag {
};
struct struct_tag {
};
const llvm_array_tag tag_array = llvm_array_tag();
const struct_tag tag_struct = struct_tag();
/**
* \brief Represents type to support type system
*
* This class represents type in denormalized form, i.e. without arguments and aliases substitution
* \sa AST::expandType()
*/
class TypeAnnotation {
public:
TypeAnnotation();
TypeAnnotation(const Atom<Type_t>& typ);
TypeAnnotation(TypePrimitive typ);
TypeAnnotation(llvm_array_tag, TypeAnnotation typ, int size);
TypeAnnotation(TypeOperator op, std::initializer_list<TypeAnnotation> operands);
TypeAnnotation(TypeOperator op, std::vector<TypeAnnotation>&& operands);
void addBindings(std::vector<Atom<Identifier_t>>&& params);
void addFields(std::vector<Atom<Identifier_t>>&& listFields);
bool operator<(const TypeAnnotation& t) const;
// TypeAnnotation (struct_tag, std::initializer_list<TypePrimitive>);
bool isValid() const;
TypeOperator __operator = TypeOperator::NONE;
std::vector<TypeAnnotation> __operands;
TypePrimitive __value;
std::string __valueCustom;
int conjuctionId = -1; //conjunction point id (relevant for recursive types)
uint64_t __size = 0;
std::vector<std::string> fields;
std::vector<std::string> bindings;
private:
};
enum class Operator {
INVALID, UNDEF, ADD, SUB, MUL, DIV,
EQU, NE, NEG, LSS,
LSE, GTR, GTE, LIST,
LIST_RANGE, LIST_NAMED,
CALL, CALL_INTRINSIC,
IMPL/* implication */, MAP,
FOLD, FOLD_INF, INDEX,
IF, SWITCH, SWITCH_VARIANT, SWITCH_LATE,
CASE, CASE_DEFAULT, LOGIC_AND,
CONTEXT_RULE, VARIANT, SEQUENCE
};
class Function;
class AST;
class CodeScope;
class MetaRuleAbstract;
typedef ManagedPtr<Function> ManagedFnPtr;
typedef ManagedPtr<CodeScope> ManagedScpPtr;
typedef ManagedPtr<MetaRuleAbstract> ManagedRulePtr;
const ManagedScpPtr NO_SCOPE = ManagedScpPtr(UINT_MAX, 0);
/**
* \brief Represents every instruction in Xreate's syntax tree
* \attention In case of any changes update xreate::ExpressionHints auxiliary helper as well
*
* Expression is generic building block of syntax tree able to hold node data
* as well as child nodes as operands. Not only instructions use expression for representation in syntax tree
* but annotation as well.
*
* Additionally, `types` as a special kind of annotations use Expression-like data structure TypeAnnotation
* \sa xreate::AST, xreate::TypeAnnotation
*/
//
struct Expression {
friend class CodeScope;
friend class TranscendLayer;
friend class CFAPass;
friend class ExpressionHints;
Expression(const Operator &oprt, std::initializer_list<Expression> params);
Expression(const Atom<Identifier_t>& ident);
Expression(const Atom<Number_t>& number);
Expression(const Atom<String_t>& a);
Expression();
void setOp(Operator oprt);
void addArg(Expression&& arg);
void addBindings(std::initializer_list<Atom<Identifier_t>> params);
void bindType(TypeAnnotation t);
template<class InputIt>
void addBindings(InputIt paramsBegin, InputIt paramsEnd);
void addTags(const std::list<Expression> tags) const;
void addBlock(ManagedScpPtr scope);
const std::vector<Expression>& getOperands() const;
double getValueDouble() const;
void setValueDouble(double value);
const std::string& getValueString() const;
void setValue(const Atom<Identifier_t>&& v);
bool isValid() const;
bool isDefined() const;
bool operator==(const Expression& other) const;
/**
* \brief is it string, number, compound operation and so on
*/
enum {
INVALID, COMPOUND, IDENT, NUMBER, STRING, BINDING
} __state = INVALID;
/**
* \brief Valid for compound State. Holds type of compound operator
*/
Operator op;
/**
* \brief Unique id to identify expression within syntax tree
*/
unsigned int id;
/**
* \brief Exact meaning depends on particular instruction
* \details As an example, named lists/structs hold field names in bindings
*/
std::vector<std::string> bindings;
std::map<std::string, size_t> __indexBindings;
/**
* \brief Holds child instructions as arguments
*/
std::vector<Expression> operands;
/**
* \brief Holds type of instruction's result
*/
TypeAnnotation type;
/**
* \brief Holds additional annotations
*/
mutable std::map<std::string, Expression> tags;
/**
* \brief Child code blocks
* \details For example, If statement holds TRUE-branch as first and FALSE-branch as second block here
*/
std::list<CodeScope*> blocks;
private:
std::string __valueS;
double __valueD;
static unsigned int nextVacantId;
};
bool operator<(const Expression&, const Expression&);
template<class InputIt>
void Expression::addBindings(InputIt paramsBegin, InputIt paramsEnd) {
size_t index = bindings.size();
std::transform(paramsBegin, paramsEnd, std::inserter(bindings, bindings.end()),
[&index, this] (const Atom<Identifier_t> atom) {
std::string key = atom.get();
this->__indexBindings[key] = index++;
return key;
});
}
typedef std::list<Expression> ExpressionList;
enum class TagModifier {
NONE, ASSERT, REQUIRE
};
enum class DomainAnnotation {
FUNCTION, VARIABLE
};
class RuleArguments : public std::vector<std::pair<std::string, DomainAnnotation>>
{
public:
void add(const Atom<Identifier_t>& name, DomainAnnotation typ);
};
class RuleGuards : public std::vector<Expression> {
public:
void add(Expression&& e);
};
class TranscendLayer;
class LLVMLayer;
class MetaRuleAbstract {
public:
MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards);
virtual ~MetaRuleAbstract();
virtual void compile(TranscendLayer& layer) = 0;
protected:
RuleArguments __args;
RuleGuards __guards;
};
class RuleWarning : public MetaRuleAbstract {
friend class TranscendLayer;
public:
RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom<String_t>&& message);
virtual void compile(TranscendLayer& layer);
~RuleWarning();
private:
std::string __message;
Expression __condition;
};
typedef unsigned int VNameId;
namespace versions {
typedef int VariableVersion;
const VariableVersion VERSION_NONE = -2;
const VariableVersion VERSION_INIT = 0;
}
template<>
struct AttachmentsDict<versions::VariableVersion> {
typedef versions::VariableVersion Data;
static const unsigned int key = 6;
};
struct ScopedSymbol {
VNameId id;
versions::VariableVersion version;
static const ScopedSymbol RetSymbol;
};
struct Symbol {
ScopedSymbol identifier;
const CodeScope * scope;
};
struct IdentifierSymbol{};
struct SymbolAlias{};
template<>
struct AttachmentsDict<IdentifierSymbol> {
typedef Symbol Data;
static const unsigned int key = 7;
};
template<>
struct AttachmentsDict<SymbolAlias> {
typedef Symbol Data;
static const unsigned int key = 9;
};
typedef std::pair<Expression, TagModifier> Tag;
bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2);
bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2);
bool operator<(const Symbol& s1, const Symbol& s2);
bool operator==(const Symbol& s1, const Symbol& s2);
/**
* \brief Represents code block and single scope of visibility
*
* Holds single expression as a *body* and set of variable assignments(declarations) used in body's expression
* \sa xreate::AST
*/
class CodeScope {
friend class Function;
friend class PassManager;
public:
CodeScope(CodeScope* parent = 0);
~CodeScope();
/** \brief Set expression as a body */
void setBody(const Expression& body);
/** \brief Returns current code scope body */
const Expression& getBody() const;
/** \brief Adds variable definition to be used in body as well as in other declarations */
Symbol addDefinition(Expression&& var, Expression&& body);
/** \brief Returns symbols' definition */
static const Expression& getDefinition(const Symbol& symbol, bool flagAllowUndefined = false);
const Expression& getDefinition(const ScopedSymbol& symbol, bool flagAllowUndefined = false) const;
/** \brief Adds variable defined elsewhere */
void addBinding(Expression&& var, Expression&& argument);
std::vector<std::string> __bindings;
std::map<std::string, VNameId> __identifiers;
CodeScope* __parent;
//TODO move __definitions to SymbolsAttachments data
//NOTE: definition of return type has index 0
std::unordered_map<ScopedSymbol, Expression> __declarations;
std::vector<Expression> tags;
std::vector<Expression> contextRules;
private:
VNameId __vCounter = 1;
ScopedSymbol registerIdentifier(const Expression& identifier);
public:
bool recognizeIdentifier(const Expression& identifier) const;
ScopedSymbol getSymbol(const std::string& alias);
};
/**
* \brief Represents single function in Xreate's syntax tree
*
* Holds an entry code scope and `guardContext` required for function to operate
* \sa xreate::AST
*/
class Function {
friend class Expression;
friend class CodeScope;
friend class AST;
public:
Function(const Atom<Identifier_t>& name);
/**
* \brief Adds function arguments
*/
void addBinding(Atom <Identifier_t>&& name, Expression&& argument);
/**
* \brief Adds additional function annotations
*/
void addTag(Expression&& tag, const TagModifier mod);
const std::string& getName() const;
const std::map<std::string, Expression>& getTags() const;
CodeScope* getEntryScope() const;
CodeScope* __entry;
std::string __name;
bool isPrefunction = false; //SECTIONTAG adhoc Function::isPrefunction flag
Expression guard;
private:
std::map<std::string, Expression> __tags;
};
class ExternData;
struct ExternEntry {
std::string package;
std::vector<std::string> headers;
};
typedef Expanded<TypeAnnotation> ExpandedType;
struct TypeInferred{};
template<>
struct AttachmentsDict<TypeInferred> {
typedef ExpandedType Data;
static const unsigned int key = 11;
};
enum ASTInterface {
CFA, DFA, Extern, Adhoc
};
struct FunctionSpecialization {
std::string guard;
size_t id;
};
struct FunctionSpecializationQuery {
std::unordered_set<std::string> context;
};
template<>
struct AttachmentsId<Expression>{
static unsigned int getId(const Expression& expression){
return expression.id;
}
};
template<>
struct AttachmentsId<Symbol>{
static unsigned int getId(const Symbol& s){
return s.scope->__declarations.at(s.identifier).id;
}
};
template<>
struct AttachmentsId<ManagedFnPtr>{
static unsigned int getId(const ManagedFnPtr& f){
const Symbol symbolFunction{ScopedSymbol::RetSymbol, f->getEntryScope()};
return AttachmentsId<Symbol>::getId(symbolFunction);
}
};
template<>
struct AttachmentsId<CodeScope*>{
static unsigned int getId(const CodeScope* scope){
const Symbol symbolScope{ScopedSymbol::RetSymbol, scope};
return AttachmentsId<Symbol>::getId(symbolScope);
}
};
template<>
struct AttachmentsId<unsigned int>{
static unsigned int getId(const unsigned int id){
return id;
}
};
class TypesResolver;
namespace details { namespace inconsistent {
/**
* \brief Syntax tree under construction in inconsistent form
*
* Represents Syntax Tree under construction(**inconsistent state**).
* \attention Clients should use rather xreate::AST unless client's code explicitly works with Syntax Tree during construction.
*
* Typically instance only created by xreate::XreateManager and filled in by Parser
* \sa xreate::XreateManager::prepare(std::string&&)
*/
class AST {
friend class xreate::TypesResolver;
public:
AST();
/**
* \brief Adds new function to AST
* \param f Function to register
*/
void add(Function* f);
/**
* \brief Adds new declarative rule to AST
* \param r Declarative Rule
*/
void add(MetaRuleAbstract* r);
/** \brief Registers new code block */
ManagedScpPtr add(CodeScope* scope);
/**
* \brief Add new type to AST
* @param t Type definition
* @param alias Typer name
*/
void add(TypeAnnotation t, Atom<Identifier_t> alias);
/** \brief Current module's name */
std::string getModuleName();
/**
* \brief Looks for function with given name
* \param name Function name to find
* \note Requires that only one function exists under given name
* \return Found function
*/
ManagedPtr<Function> findFunction(const std::string& name);
/** \brief Returns all function in AST */
std::list<ManagedFnPtr> getAllFunctions() const;
/**
* \brief Returns all specializations of a function with a given name
* \param fnName function to find
* \return list of found function specializations
*/
std::list<ManagedFnPtr> getFunctionSpecializations(const std::string& fnName) const;
/**
* \return First element in Functions/Scopes/Rules list depending on template parameter
* \tparam Target either Function or CodeScope or MetaRuleAbstract
*/
template<class Target>
ManagedPtr<Target> begin();
/**
* \brief Performs all necessary steps after AST is built
*
* Performs all finzalisation steps and move AST into consistent state represented by xreate::AST
* \sa xreate::AST
* \return AST in consistent state
*/
xreate::AST* finalize();
typedef std::multimap<std::string, unsigned int> FUNCTIONS_REGISTRY;
std::vector<ExternEntry> __externdata;
std::list<Expression> __dfadata; //TODO move to more appropriate place
std::list<std::string> __rawImports; //TODO move to more appropriate place
std::multimap<ASTInterface, Expression> __interfacesData; //TODO CFA data here.
private:
std::vector<MetaRuleAbstract*> __rules;
std::vector<Function*> __functions;
std::vector<CodeScope*> __scopes;
FUNCTIONS_REGISTRY __indexFunctions;
protected:
std::map<std::string, TypeAnnotation> __indexTypeAliases;
public:
/**
* \brief Stores DFA scheme for later use by DFA Pass
*
* Treats expression as a DFA scheme and feeds to a DFA Pass later
* \paramn Expression DFA Scheme
* \sa xreate::DFAPass
*/
void addDFAData(Expression&& data);
/** \brief Stores data for later use by xreate::ExternLayer */
void addExternData(ExternData&& data);
/**
* \brief Generalized function to store particular data for later use by particular pass
* \param interface Particular Interface
* \param data Particular data
*/
void addInterfaceData(const ASTInterface& interface, Expression&& data);
/**\name Symbols Recognition */
///@{
public:
//TODO revisit enums/variants, move to codescope
/**
* \brief Tries to find out whether expression is Variant constructor
*/
void recognizeVariantConstructor(Expression& function);
Atom<Number_t> recognizeVariantConstructor(Atom<Identifier_t> ident);
private:
std::map<std::string, std::pair<TypeAnnotation, int>> __dictVariants;
public:
std::set<std::pair<CodeScope*, Expression>> bucketUnrecognizedIdentifiers;
public:
/**
* \brief Postpones unrecognized identifier for future second round of recognition
* \param scope Code block identifier is encountered
* \param id Identifier
*/
void postponeIdentifier(CodeScope* scope, const Expression& id);
/** \brief Second round of identifiers recognition done right after AST is fully constructed */
void recognizePostponedIdentifiers();
///@}
};
template<>
ManagedPtr<Function>
AST::begin<Function>();
template<>
ManagedPtr<CodeScope>
AST::begin<CodeScope>();
template<>
ManagedPtr<MetaRuleAbstract>
AST::begin<MetaRuleAbstract>();
} } // namespace details::incomplete
/**
* \brief Xreate's Syntax Tree in consistent state
*
* Syntax Tree has two mutually exclusive possible states:
* - inconsistent state while AST is under construction. Represented by xreate::details::inconsistent::AST
* - consistent state when AST is built and finalize() is done.
*
* This class represents consistent state and should be used everywhere unless client's code explicitly works with AST under construction.
* Consistent AST enables access to additional functions(currently related to type management).
* \sa xreate::details::inconsistent::AST
*/
class AST : public details::inconsistent::AST {
public:
AST() : details::inconsistent::AST() {}
/**
* \brief Computes fully expanded form of type by substituting all arguments and aliases
* \param t Type to expand
* \return Expdanded or normal form of type
* \sa TypeAnnotation
*/
ExpandedType expandType(const TypeAnnotation &t) const;
/**
* Searches type by given name
* \param name Typename to search
* \return Expanded or normal form of desired type
* \note if type name is not found returns new undefined type with this name
*/
ExpandedType findType(const std::string& name);
/**
* Invokes Type Inference Analysis to find out expanded(normal) form expressions's type
* \sa typeinference.h
* \param expression
* \return Type of expression
*/
ExpandedType getType(const Expression& expression);
};
}
#endif // AST_H
diff --git a/cpp/src/attachments.h b/cpp/src/attachments.h
index 643f718..3b82d43 100644
--- a/cpp/src/attachments.h
+++ b/cpp/src/attachments.h
@@ -1,180 +1,202 @@
/* 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
// 11 TypeInferred
-// 12 LateBinding
+// 12 LateBindingT
};
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;
+ virtual void __update(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);
}
+
+ template<class Id>
+ void update(const Id& object, Data data){
+ unsigned int id = AttachmentsId<Id>::getId(object);
+
+ __update(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);
}
+ virtual void __update(const unsigned int id, Data data){
+ assert(__data.count(id));
+ __data.at(id) = data;
+ }
+
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(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(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(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(object, data);
}
+
+ template<class Tag, class Id>
+ static void update(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->update(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/aux/latereasoning.cpp b/cpp/src/aux/latereasoning.cpp
new file mode 100644
index 0000000..8dc3366
--- /dev/null
+++ b/cpp/src/aux/latereasoning.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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>
+ * Created on June 7, 2018, 6:01 PM
+ *
+ * \file latereasoning.cpp
+ * \brief Late reasoninf support
+ */
+
+#include "aux/latereasoning.h"
+#include "ast.h"
+
+namespace xreate {namespace latereasoning {
+
+boost::optional<Gringo::Symbol>
+LateAnnotation::select(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;
+}
+
+}}
+
diff --git a/cpp/src/aux/latereasoning.h b/cpp/src/aux/latereasoning.h
new file mode 100644
index 0000000..5eb2f21
--- /dev/null
+++ b/cpp/src/aux/latereasoning.h
@@ -0,0 +1,113 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * \file latereasoning.h
+ * \brief Late reasoning support
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ *
+ * Created on June 2, 2018, 1:08 PM
+ */
+
+#ifndef LATEREASONING_H
+#define LATEREASONING_H
+
+#include "transcendlayer.h"
+
+namespace xreate {
+ struct LateBindingT;
+
+ template<>
+ struct AttachmentsDict<LateBindingT>{
+ typedef Expression Data;
+ static const unsigned int key = 12;
+ };
+}
+
+namespace xreate{ namespace latereasoning{
+
+struct LateAnnotation{
+ std::list<std::pair<std::list<Expression>, Gringo::Symbol>> guardedSymbols;
+ boost::optional<Gringo::Symbol> select(const std::list<Expression>& keys) const;
+};
+
+struct LateAnnotationsGroup{
+ std::unordered_map<SymbolNode, LateAnnotation> 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)
+template<class Parent>
+class LateReasoningTranscendDecorator: public Parent{
+public:
+ StaticModel queryLate(const std::string& alias, const SymbolNode& symbol) const{
+ StaticModel result;
+ if(!__modelLate.count(alias)) return StaticModel();
+
+ const LateAnnotationsGroup& group = __modelLate.at(alias);
+ assert(group.bindings.count(symbol));
+ const std::list<SymbolPacked>& bindings = group.bindings.at(symbol);
+ std::list<Expression>&& keys = findKeys(bindings);
+
+ const LateAnnotation& annLate = group.annotations.at(symbol);
+ auto ann = annLate.select(keys);
+ if(ann){
+ result.emplace(std::make_pair(alias, *ann));
+ }
+
+ return result;
+ }
+
+protected:
+ virtual bool processSolution(Gringo::Model const &model) override{
+ const std::string& atomLateStatement = "late";
+
+ for(const Gringo::Symbol& atom: model.atoms(clingo_show_type_atoms)){
+ std::string atomName(atom.name().c_str());
+
+ SymbolPacked aaaa;
+ if(atomName == atomLateStatement){
+ //late atom's format: (Symbol, (tuple of keys), (tuple of values), late-annotation)
+ auto atomLate = TranscendLayer::parse<SymbolPacked, std::list<SymbolPacked>, std::list<Expression>, Gringo::Symbol>(atom);
+ const std::string& atomAlias = std::get<3>(atomLate).name().c_str();
+ addLateAtom(atomAlias, std::get<0>(atomLate),
+ std::get<3>(atomLate), std::get<1>(atomLate),
+ std::get<2>(atomLate));
+ }
+ }
+
+ return Parent::processSolution(model);
+ }
+
+private:
+ std::map<std::string, LateAnnotationsGroup> __modelLate;
+
+ void addLateAtom(const std::string& alias, const SymbolNode& symbol,
+ const Gringo::Symbol& atom, const std::list<SymbolPacked>& guardKeys,
+ const std::list<Expression>& guardBindings){
+ LateAnnotationsGroup& group = __modelLate[alias];
+ if(!group.bindings.count(symbol)){
+ group.bindings.emplace(symbol, guardKeys);
+ }
+
+ LateAnnotation& annotation = group.annotations[symbol];
+ annotation.guardedSymbols.push_back(std::make_pair(guardBindings, atom));
+ }
+
+ std::list<Expression> 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<LateBindingT>(Parent::unpack(key));
+ });
+
+ return result;
+ }
+};
+
+}} // end of xreate::latereasoning
+
+#endif /* LATEREASONING_H */
+
diff --git a/cpp/src/aux/transcend-decorators.h b/cpp/src/aux/transcend-decorators.h
new file mode 100644
index 0000000..77a04d6
--- /dev/null
+++ b/cpp/src/aux/transcend-decorators.h
@@ -0,0 +1,27 @@
+/*
+ * 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>
+ * Created on June 7, 2018, 6:47 PM
+ *
+ * \file transcend-decorators.h
+ * \brief TranscendLevel decorators management
+ */
+
+#include "transcendlayer.h"
+#include "aux/latereasoning.h"
+
+#ifndef TRANSCEND_DECORATORS_H
+#define TRANSCEND_DECORATORS_H
+
+namespace xreate {
+ typedef latereasoning::LateReasoningTranscendDecorator<TranscendLayer>
+ DefaultTranscendLayerImpl;
+}
+
+#endif /* TRANSCEND_DECORATORS_H */
+
diff --git a/cpp/src/aux/xreatemanager-decorators.cpp b/cpp/src/aux/xreatemanager-decorators.cpp
index 3e40b1a..2b3a9ba 100644
--- a/cpp/src/aux/xreatemanager-decorators.cpp
+++ b/cpp/src/aux/xreatemanager-decorators.cpp
@@ -1,73 +1,72 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* xreatemanager-decorators.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on July 16, 2017, 4:40 PM
*/
/**
* \file xreatemanager-decorators.h
* \brief \ref xreate::XreateManager decorators to provide various functionality
*/
#include "aux/xreatemanager-decorators.h"
#include "main/Parser.h"
#include "pass/compilepass.h"
#include "pass/cfapass.h"
#include "pass/dfapass.h"
#include "pass/interpretationpass.h"
#include "pass/versionspass.h"
-
namespace xreate {
void
XreateManagerDecoratorBase::prepareCode(std::string&& code){
grammar::main::Scanner scanner(reinterpret_cast<const unsigned char*>(code.c_str()), code.size());
grammar::main::Parser parser(&scanner);
parser.Parse();
assert(!parser.errors->count && "Parser errors");
PassManager::prepare(parser.root->finalize());
}
void
XreateManagerDecoratorBase::prepareCode(FILE* code){
grammar::main::Scanner scanner(code);
grammar::main::Parser parser(&scanner);
parser.Parse();
assert(!parser.errors->count && "Parser errors");
PassManager::prepare(parser.root->finalize());
}
void
XreateManagerDecoratorBase::analyse(){
CompilePass::prepareQueries(transcend);
transcend->run();
}
void
XreateManagerDecoratorFull::initPasses(){
cfa::CFAPass* passCFG = new cfa::CFAPass(this);
//TODO is it really DFGPass needs CFGpass?
- registerPass(new dfa::DFAPass(this), PassId::DFGPass, passCFG);
- registerPass(passCFG, PassId::CFGPass);
+ registerPass(new dfa::DFAPass(this), PassId::DFAPass, passCFG);
+ registerPass(passCFG, PassId::CFAPass);
this->registerPass(new interpretation::InterpretationPass(this), PassId::InterpretationPass);
this->registerPass(new versions::VersionsPass(this), PassId::VersionsPass);
}
void*
XreateManagerDecoratorFull::run() {
std::unique_ptr<CompilePass> compiler(new compilation::CompilePassCustomDecorators<>(this));
compiler->run();
llvm->print();
llvm->initJit();
return llvm->getFunctionPointer(compiler->getEntryFunction());
}
} //namespace xreate
diff --git a/cpp/src/compilation/latereasoning.cpp b/cpp/src/compilation/latereasoning.cpp
index 496a97c..97a7eb6 100644
--- a/cpp/src/compilation/latereasoning.cpp
+++ b/cpp/src/compilation/latereasoning.cpp
@@ -1,53 +1,79 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* latereasoning.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on May 26, 2018, 3:54 PM
*/
#include "compilation/latereasoning.h"
+#include "aux/latereasoning.h"
+#include "compilation/scopedecorators.h"
+#include "analysis/typeinference.h"
+#include <vector>
+
+using namespace xreate::compilation;
+using namespace std;
namespace xreate{ namespace latereasoning {
llvm::Value*
LateReasoningCompiler::compile(const Expression& expr, const std::string& identHint){
-// #define HINT(x) (identHint.empty()? x : hintRetVar)
-//
-// LLVMLayer* llvm = context.pass->man->llvm;
-// compilation::ICodeScopeUnit* scope = context.scope;
-// AST* root = context.pass->man->root;
-// llvm::IRBuilder<>& builder = llvm->builder;
-//
-// const ExpandedType& typCondition = root->getType(expr.operands.at(0));
-// const int countVariants = typCondition->fields.size();
-//
-// llvm::Value * conditionRaw = scope->process(expr.operands.at(0));
-// llvm::Value* variantRaw = builder.CreateExtractValue(conditionRaw, llvm::ArrayRef<unsigned>({0}));
-// llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(variantRaw, nullptr, countVariants);
-// //llvm::BasicBlock* blockProlog = builder.GetInsertBlock();
-//
-// llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "switchLateAfter", function->raw);
-// builder.SetInsertPoint(blockEpilog);
-// llvm::Type* exprSwitchType = llvm->toLLVMType(root->getType(expr));
-// llvm::PHINode *ret = builder.CreatePHI(exprSwitchType, countVariants, HINT("switchLate"));
-// //builder.SetInsertPoint(blockProlog);
-//
-// for (int variantId = 0; variantId<countVariants; ++variantId){
-// llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm::getGlobalContext(),
-// "case" + std::to_string(i), function->raw);
-// builder.SetInsertPoint(blockCase);
-// CodeScope scopeBody = function->getScopeUnit(exp.blocks.back());
-// scopeBody->reset();
-//
-// llvm::Value* resultCase = scopeBody->compile();
-// ret->addIncoming(resultCase, builder.GetInsertBlock());
-// instructionSwitch->addCase(dyn_cast<llvm::ConstantInt>(llvm::ConstantInt::get(typI8, variantId), blockCase);
-//
-// builder.CreateBr(blockEpilog);
-// }
+ #define HINT(x) (identHint.empty()? x : identHint)
+
+ LLVMLayer* llvm = context.pass->man->llvm;
+ compilation::ICodeScopeUnit* scope = context.scope;
+ AST* root = context.pass->man->root;
+ llvm::IRBuilder<>& builder = llvm->builder;
+ compilation::IFunctionUnit* function = context.function;
+ llvm::Type* typI8= llvm::Type::getInt8Ty(llvm->llvmContext);
+ CodeScope* scopeBody = expr.blocks.front();
+ Symbol guardS = Symbol{scopeBody->getSymbol(expr.bindings.front()), scopeBody};
+
+ const ExpandedType& typCondition = root->getType(expr.operands.at(0));
+ vector<Expression> guardVariants = typeinference::getSlaveVariants(typCondition, context.pass->man->transcend);
+ const int countVariants = guardVariants.size();
+ assert(countVariants);
+
+ llvm::Value * conditionRaw = scope->process(expr.operands.at(0));
+ llvm::Value* variantRaw = builder.CreateExtractValue(conditionRaw, llvm::ArrayRef<unsigned>({0}));
+ llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(variantRaw, nullptr, countVariants);
+
+ llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "switchLateAfter", function->raw);
+ builder.SetInsertPoint(blockEpilog);
+ llvm::Type* exprSwitchType = llvm->toLLVMType(root->getType(expr));
+ llvm::PHINode *ret = builder.CreatePHI(exprSwitchType, countVariants, HINT("switchLate"));
+ llvm::BasicBlock* blockDefault = nullptr;
+
+ bool flagFirstPass = true;
+ for (int variantId = 0; variantId<countVariants; ++variantId){
+ //Pass information to the late model
+ flagFirstPass?
+ Attachments::put<LateBindingT>(guardS, guardVariants.at(variantId))
+ : Attachments::update<LateBindingT>(guardS, guardVariants.at(variantId));
+ flagFirstPass = false;
+
+ llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(
+ llvm->llvmContext,
+ "case" + std::to_string(variantId),
+ function->raw);
+ if(variantId == 0) blockDefault = blockCase;
+ builder.SetInsertPoint(blockCase);
+ auto scopeBody = Decorators<CachedScopeDecoratorTag>::getInterface<>(
+ function->getScopeUnit(expr.blocks.back()));
+ scopeBody->reset();
+
+ llvm::Value* resultCase = scopeBody->compile();
+ ret->addIncoming(resultCase, builder.GetInsertBlock());
+ instructionSwitch->addCase(llvm::dyn_cast<llvm::ConstantInt>(llvm::ConstantInt::get(typI8, variantId)), blockCase);
+ builder.CreateBr(blockEpilog);
+ }
+
+ instructionSwitch->setDefaultDest(blockDefault);
+ builder.SetInsertPoint(blockEpilog);
+ return ret;
}
}}
\ No newline at end of file
diff --git a/cpp/src/compilation/latereasoning.h b/cpp/src/compilation/latereasoning.h
index 8a7be74..84adc4f 100644
--- a/cpp/src/compilation/latereasoning.h
+++ b/cpp/src/compilation/latereasoning.h
@@ -1,33 +1,33 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: latereasoning.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on May 26, 2018, 3:44 PM
*/
-#ifndef LATEREASONING_H
-#define LATEREASONING_H
+#ifndef CMPLLATEREASONING_H
+#define CMPLLATEREASONING_H
#include "ast.h"
#include "pass/compilepass.h"
#include "llvmlayer.h"
namespace xreate{ namespace latereasoning {
class LateReasoningCompiler {
public:
LateReasoningCompiler(compilation::Context ctx): context(ctx){}
llvm::Value* compile(const Expression& expr, const std::string& identHint);
private:
compilation::Context context;
};
}}
-#endif /* LATEREASONING_H */
+#endif /* CMPLLATEREASONING_H */
diff --git a/cpp/src/compilation/targetinterpretation.h b/cpp/src/compilation/targetinterpretation.h
index 377993e..7634199 100644
--- a/cpp/src/compilation/targetinterpretation.h
+++ b/cpp/src/compilation/targetinterpretation.h
@@ -1,139 +1,132 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: targetstatic.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on July 2, 2016, 1:25 PM
*/
#ifndef TARGETSTATIC_H
#define TARGETSTATIC_H
#include "ast.h"
#include "pass/compilepass.h"
#include "compilation/targets.h"
#include "pass/interpretationpass.h"
#include "transcendlayer.h"
namespace xreate{ namespace interpretation{
class TargetInterpretation;
class InterpretationScope;
class InterpretationFunction;
}}
namespace xreate{ namespace compilation{
template <>
struct TargetInfo<interpretation::TargetInterpretation> {
typedef Expression Result;
typedef interpretation::InterpretationScope Scope;
typedef interpretation::InterpretationFunction Function;
};
}}
namespace xreate{ namespace interpretation{
/** \brief Encapsulates interpretation of a single Code Scope */
class InterpretationScope: public compilation::Scope<TargetInterpretation>{
typedef Scope<TargetInterpretation> Parent;
public:
InterpretationScope(const CodeScope* scope, compilation::Function<TargetInterpretation>* f): Parent(scope, f) {}
Expression process(const Expression& expression) override;
llvm::Value* compile(const Expression& expression, const compilation::Context& context);
private:
llvm::Value* compileHybrid(const InterpretationOperator& op, const Expression& expression, const compilation::Context& context);
//llvm::Value* compilePartialFnCall(const Expression& expression, const Context& context);
CodeScope* processOperatorIf(const Expression& expression);
CodeScope* processOperatorSwitch(const Expression& expression);
CodeScope* processOperatorSwitchVariant(const Expression& expression);
};
/** \brief Encapsulates interpretation of a single %Function */
class InterpretationFunction: public compilation::Function<TargetInterpretation>{
public:
InterpretationFunction(const ManagedFnPtr& function, compilation::Target<TargetInterpretation>* target);
Expression process(const std::vector<Expression>& args);
};
/** \brief Signature of a partially interpreted function */
struct PIFSignature{
ManagedFnPtr declaration;
std::vector<Expression> bindings;
};
class PIFunctionUnit;
/** \brief Partially interpreted function */
class PIFunction: public InterpretationFunction{
public:
PIFunctionUnit* functionUnit;
PIFSignature signatureInstance;
PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target);
llvm::Function* compile();
};
bool operator<(const PIFSignature& lhs, PIFunction* const rhs);
bool operator<(PIFunction* const lhs, const PIFSignature& rhs);
/** \brief Encapsulates actual [Interpretation](/w/concepts/dfa) based on InterpretationPass analysis results */
class TargetInterpretation: public compilation::Target<TargetInterpretation>{
public:
TargetInterpretation(AST* root, CompilePass* passCompilation): Target<TargetInterpretation>(root), pass(passCompilation){}
//target:
public:
InterpretationFunction* getFunction(compilation::IFunctionUnit* unit);
PIFunction* getFunction(PIFSignature&& sig);
private:
std::map<PIFSignature, PIFunction*> __pifunctions;
std::map<compilation::IFunctionUnit*, InterpretationFunction*> __dictFunctionsByUnit;
//self:
public:
CompilePass* pass;
llvm::Value* compile(const Expression& expression, const compilation::Context& ctx);
private:
InterpretationScope* transformContext(const compilation::Context& c);
};
/**\brief Interpretation-aware Code Scope decorator
* \extends xreate::compilation::ICodeScopeUnit
*/
template<class Parent>
class InterpretationScopeDecorator: public Parent{
public:
InterpretationScopeDecorator(const CodeScope* const codeScope, compilation::IFunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){}
virtual llvm::Value* process(const Expression& expr, const std::string& hintVarDecl){
const InterpretationData& data = Attachments::get<InterpretationData>(expr, {ANY, NONE});
bool flagInterpretationEligible = (data.resolution == INTR_ONLY || data.op != InterpretationOperator::NONE);
if (flagInterpretationEligible){
compilation::Context ctx{this, this->function, this->pass};
return Parent::pass->targetInterpretation->compile(expr, ctx);
}
return Parent::process(expr, hintVarDecl);
}
};
/** \brief translates Logic expression(Gringo::Symbol) into Xreate expression to support intrinsic function `query` */
Expression representAsAnnotation(const Gringo::Symbol& symbol);
}} //end of xreate:: interpretation
-#endif /* TARGETSTATIC_H */
-
-
-//transformers:
-// template<>
-// struct TransformerInfo<TargetInterpretation> {
-// static const int id = 1;
-// };
+#endif /* TARGETSTATIC_H */
\ No newline at end of file
diff --git a/cpp/src/pass/abstractpass.h b/cpp/src/pass/abstractpass.h
index d09f83b..9c8648b 100644
--- a/cpp/src/pass/abstractpass.h
+++ b/cpp/src/pass/abstractpass.h
@@ -1,207 +1,206 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Author: pgess <v.melnychenko@xreate.org>
*/
#ifndef ABSTRACTPASS_H
#define ABSTRACTPASS_H
#include "ast.h"
#include "xreatemanager.h"
#include<iostream>
namespace xreate
{
/** \brief Holds current position in %AST while traversing*/
struct PassContext
{
const CodeScope* scope = 0;
ManagedFnPtr function;
ManagedRulePtr rule;
std::string varDecl;
PassContext()
{}
PassContext updateScope(const CodeScope* scopeNew) {
PassContext context2{*this};
context2.scope = scopeNew;
return context2;
}
~PassContext(){}
};
/** \brief Base class for all passes to inherit */
class IPass {
public:
IPass(PassManager* manager);
virtual ~IPass(){}
/** \brief Executes pass */
virtual void run()=0;
/** \brief Finalizes pass. Empty by default*/
virtual void finish();
PassManager* man;
};
template<class Output>
Output defaultValue();
template<>
void defaultValue<void>();
/** \brief Stores processing results for already visited nodes */
template<class Output>
class SymbolCache: private std::map<Symbol, Output>{
public:
bool isCached(const Symbol& symbol){
return this->count(symbol);
}
Output setCachedValue(const Symbol& symbol, Output&& value){
(*this)[symbol] = value;
return value;
}
Output getCachedValue(const Symbol& symbol){
assert(this->count(symbol));
return this->at(symbol);
}
};
/** \brief Set of already visited nodes */
template<>
class SymbolCache<void>: private std::set<Symbol>{
public:
bool isCached(const Symbol& symbol){
bool result = this->count(symbol) > 0;
return result;
}
void setCachedValue(const Symbol& symbol){
this->insert(symbol);
}
void getCachedValue(const Symbol& symbol){
}
};
/** \brief Minimal useful IPass implementation*/
template<class Output>
class AbstractPass: public IPass {
SymbolCache<Output> __visitedSymbols;
protected:
virtual Output processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol=""){
if (__visitedSymbols.isCached(symbol))
return __visitedSymbols.getCachedValue(symbol);
-
const Expression& declaration = CodeScope::getDefinition(symbol, true);
if (declaration.isDefined()){
PassContext context2 = context.updateScope(symbol.scope);
Output&& result = process(declaration, context2, hintSymbol);
return __visitedSymbols.setCachedValue(symbol, std::move(result));
}
return defaultValue<Output>();
}
Output processExpressionCall(const Expression& expression, PassContext context){
const std::string &calleeName = expression.getValueString();
std::list<ManagedFnPtr> callees = man->root->getFunctionSpecializations(calleeName);
if (callees.size() == 1 && callees.front()){
return processFnCall(callees.front(), context);
} else {
for (const ManagedFnPtr& callee: callees){
processFnCallUncertain(callee, context);
}
return defaultValue<Output>();
}
}
SymbolCache<Output>& getSymbolCache(){
return __visitedSymbols;
}
public:
AbstractPass(PassManager* manager)
: IPass(manager){}
/** \brief Processes function invocation instruction */
virtual Output processFnCall(ManagedFnPtr functionCallee, PassContext context){
return defaultValue<Output>();
}
/** \brief Processes function invocation instruction in uncertain cases
* \details Executed when it's impossible statically determine exact function invocation.
* In this case get executed for all possible candidates
*/
virtual void processFnCallUncertain(ManagedFnPtr functionCallee, PassContext context)
{}
/** \brief Processes Logic Rule */
virtual void process(ManagedRulePtr rule)
{}
/** \brief Processes Function */
virtual Output process(ManagedFnPtr function)
{
PassContext context;
context.function = function;
return process(function->getEntryScope(), context);
}
/** \brief Processes single CodeScope */
virtual Output process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl=""){
context.scope = scope;
return processSymbol(Symbol{ScopedSymbol::RetSymbol, scope}, context);
}
//TODO expose Symbol instead of varDecl. Required by DFAPass.
/** \brief Processes single Expression */
virtual Output process(const Expression& expression, PassContext context, const std::string& varDecl=""){
if (expression.__state == Expression::IDENT){
assert(context.scope);
return processSymbol(Attachments::get<IdentifierSymbol>(expression), context, expression.getValueString());
}
assert(false);
return defaultValue<Output>();
}
/** \brief Executes AST traverse */
void run() {
ManagedRulePtr rule = man->root->begin<MetaRuleAbstract>();
while (rule.isValid()) {
process(rule);
++rule;
}
ManagedFnPtr f = man->root->begin<Function>();
while (f.isValid()) {
process(f);
++f;
}
}
};
template<>
void
AbstractPass<void>::processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol);
template<>
void
AbstractPass<void>::process(const Expression& expression, PassContext context, const std::string& hintSymbol);
}
#endif
diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp
index f39e74c..21d3234 100644
--- a/cpp/src/pass/compilepass.cpp
+++ b/cpp/src/pass/compilepass.cpp
@@ -1,716 +1,720 @@
/* 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 "transcendlayer.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 "aux/latereasoning.h"
#include "compilation/latereasoning.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::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::SWITCH_LATE: {
latereasoning::LateReasoningCompiler compiler({this, function, pass});
return compiler.compile(expr, DEFAULT("switchlate"));
}
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) {
LLVMLayer* llvm = pass->man->llvm;
-
+
if (!hintBlockDecl.empty()) {
llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm->llvmContext, 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() {
+ //Initialization:
managerTransformations = new xreate::compilation::TransformationsManager();
targetInterpretation = new interpretation::TargetInterpretation(this->man->root, this);
+ Attachments::init<LateBindingT>();
- //Find out main function;
+ //Determine entry function:
StaticModel model = man->transcend->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>(TranscendLayer::parse<std::string>(model.begin()->second));
compilation::IFunctionUnit* unitMain = getFunctionUnit(man->root->findFunction(nameMain));
+
+ //Compilation itself:
entry = unitMain->compile();
}
llvm::Function*
CompilePass::getEntryFunction() {
assert(entry);
return entry;
}
void
CompilePass::prepareQueries(TranscendLayer* transcend) {
transcend->registerQuery(new containers::Query(), QueryId::ContainersQuery);
transcend->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:TranscendLayer 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 a4a6747..26ca47b 100644
--- a/cpp/src/pass/dfapass.cpp
+++ b/cpp/src/pass/dfapass.cpp
@@ -1,233 +1,241 @@
/* 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 "transcendlayer.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()}
, transcend(manager->transcend) { }
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.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=transcend->pack(Symbol{symbolFormal, scopeRemote}, nameCalleeFunction+":"+identFormal);
callInstance.args.push_back(std::make_pair(symbolFormalPacked, *nodeActual));
++nodeActual;
}
callInstance.retActual=result;
SymbolNode retFormal=SymbolNode(transcend->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);
}
}
+void
+DFAPass::processAnnotations(const Expression& expression, PassContext context, const SymbolNode& ident){
+ for (const pair<std::string, Expression>& tag : expression.tags){
+ graph->printInplaceAnnotation(ident, tag.second);
+ }
+}
+
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=transcend->pack(varSymbol, varDecl);
} else if(expression.__state==Expression::IDENT&&expression.tags.size()==0){
Symbol varSymbol=Attachments::get<IdentifierSymbol>(expression);
result=transcend->pack(varSymbol, expression.getValueString());
} else {
result=SymbolAnonymous{expression.id};
}
- graph->printInplaceAnnotations(result, expression);
+ processAnnotations(expression, context, result);
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};
transcend->pack(symbRet, hintBlockDecl + ":[ret]");
}
for(const std::string& binding : scope->__bindings) {
- Symbol bindingSymbol{scope->getSymbol(binding), scope};
- SymbolPacked bindingPacked=transcend->pack(bindingSymbol, binding);
+ Symbol bindingSymb{scope->getSymbol(binding), scope};
+ SymbolPacked bindingSymbP=transcend->pack(bindingSymb, binding);
- getSymbolCache().setCachedValue(bindingSymbol, SymbolNode(bindingPacked));
+ getSymbolCache().setCachedValue(bindingSymb, SymbolNode(bindingSymbP));
+ processAnnotations(scope->getDefinition(bindingSymb), context, SymbolNode(bindingSymbP));
}
return AbstractPass<SymbolNode>::process(scope, context, hintBlockDecl);
}
SymbolNode
DFAPass::process(ManagedFnPtr function) {
transcend->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() {
transcend->registerReport(graph);
//Declare symbols:
graph->printSymbols(transcend);
AbstractPass::finish();
}
} //end of namespace dfa
template<>
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/pass/dfapass.h b/cpp/src/pass/dfapass.h
index 09f5538..0626a26 100644
--- a/cpp/src/pass/dfapass.h
+++ b/cpp/src/pass/dfapass.h
@@ -1,51 +1,52 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Author: pgess <v.melnychenko@xreate.org>
*
* dfapass.h
* Data Flow Graph building pass
*/
#ifndef DFGPASS_H
#define DFGPASS_H
#include "abstractpass.h"
#include "analysis/dfagraph.h"
namespace xreate {
class TranscendLayer;
}
namespace xreate { namespace dfa {
struct ProcessingCache {
std::vector<SymbolNode> operands;
std::vector<SymbolNode> blocks;
};
/** \brief Data Flow Analysis Pass(%DFA) */
class DFAPass: public AbstractPass<SymbolNode> {
public:
DFAPass(PassManager* manager);
protected:
+ virtual void processAnnotations(const Expression& expression, PassContext context, const SymbolNode& ident);
virtual SymbolNode process(const Expression& expression, PassContext context, const std::string& varDecl="") override;
virtual SymbolNode process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl="") override;
virtual SymbolNode process(ManagedFnPtr function) override;
void init();
void finish() override;
+ DFAGraph* graph;
+ TranscendLayer* transcend;
+
private:
void processCallInstance(const Expression& expr, PassContext context, const SymbolNode& result);
void processDependencies(const SymbolNode& node, const Expression& expression, PassContext context, ProcessingCache& cache);
-
- DFAGraph* graph;
- TranscendLayer* transcend;
};
}} //end of xreate::dfa namespace
#endif
diff --git a/cpp/src/pass/latereasoningpass.h b/cpp/src/pass/latereasoningpass.h
new file mode 100644
index 0000000..c005673
--- /dev/null
+++ b/cpp/src/pass/latereasoningpass.h
@@ -0,0 +1,179 @@
+/*
+ * 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>
+ * Created on June 7, 2018, 7:20 PM
+ *
+ * \file latereasoningpass.h
+ * \brief latereasoningpass
+ */
+
+#ifndef LATEREASONINGPASS_H
+#define LATEREASONINGPASS_H
+
+#include "pass/dfapass.h"
+
+namespace xreate { namespace latereasoning {
+
+class LateReasoningScope{
+public:
+ LateReasoningScope(LateReasoningScope* parent): __parent(parent){ }
+
+ boost::optional<LateSymbolRecognized>
+ recognizeIdentifier(const std::string& identifier){
+
+ //Search identifier in the current scope
+ if(__identifiers.count(identifier)){
+ return make_pair(identifier, __identifiers.at(identifier));
+ }
+
+ //Search in the parent scope
+ if(__parent){
+ return __parent->recognizeIdentifier(identifier);
+ }
+
+ return boost::none;
+ }
+
+ void
+ addIdentifier(std::string idenName, const SymbolPacked& identSymbol){
+ __identifiers.emplace(idenName, identSymbol);
+ }
+
+private:
+ std::map<std::string, SymbolPacked> __identifiers;
+ LateReasoningScope *__parent;
+};
+
+template<class Parent>
+class LateReasoningDFAPassDecorator: public Parent{
+public:
+ LateReasoningDFAPassDecorator(PassManager* manager): Parent(manager){ }
+
+ void
+ registerLateScope(CodeScope* scope, LateReasoningScope* scopeLate){
+ __dictScopes.emplace(scope, scopeLate);
+ }
+
+private:
+ LateReasoningScope*
+ liftScope(const CodeScope* scope){
+ while(scope){
+ if(__dictScopes.count(scope)) return __dictScopes.at(scope);
+ scope = scope->__parent;
+ }
+
+ return nullptr;
+ }
+
+ std::list<LateSymbolRecognized>
+ recognizeLateIdentifiers(const Expression& expression, LateReasoningScope* scope){
+ std::list<LateSymbolRecognized> result;
+
+ switch(expression.op){
+ case Operator::CALL:
+ {
+ for(const auto& op: expression.operands){
+ std::list<LateSymbolRecognized> opResult = recognizeLateIdentifiers(op, scope);
+ result.insert(result.end(), opResult.begin(), opResult.end());
+ }
+
+ if(!expression.operands.size()){
+ if(auto symbolRecognized = scope->recognizeIdentifier(expression.getValueString())){
+ result.push_back(*symbolRecognized);
+ }
+ }
+ break;
+ }
+
+ case Operator::NEG:
+ {
+ assert(expression.operands.size() == 1);
+
+ const Expression &op = expression.operands.at(0);
+ std::list<LateSymbolRecognized> opResult = recognizeLateIdentifiers(op, scope);
+ result.insert(result.end(), opResult.begin(), opResult.end());
+ };
+
+ case Operator::INVALID:
+ {
+ switch(expression.__state){
+ case Expression::NUMBER:
+ break;
+
+ default:
+ assert(true);
+ }
+ break;
+ }
+
+ default: break;
+ }
+
+ return result;
+ }
+
+protected:
+ virtual SymbolNode process(const Expression& expression, PassContext context, const std::string& varDecl="") override{
+ if(expression.__state == Expression::COMPOUND && expression.op == Operator::SWITCH_LATE){
+ //Reserve late scope:
+ LateReasoningScope* scopeLate = new LateReasoningScope(liftScope(context.scope));
+ CodeScope* scopeBody = expression.blocks.front();
+ registerLateScope(scopeBody, scopeLate);
+
+ //Assign late identifiers
+ for(const std::string& identLate: expression.bindings){
+ ScopedSymbol identLateS = scopeBody->getSymbol(identLate);
+ SymbolPacked identLateSP = Parent::man->transcend->pack(Symbol{identLateS, scopeBody});
+
+ scopeLate->addIdentifier(identLate, identLateSP);
+ }
+ }
+
+ return Parent::process(expression, context, varDecl);
+ }
+
+ virtual void
+ processAnnotations(const Expression& expression,
+ PassContext context,
+ const SymbolNode& ident){
+
+ LateReasoningScope* scopeLate = liftScope(context.scope);
+
+ if(!expression.tags.size() || !scopeLate)
+ return Parent::processAnnotations(expression, context, ident);
+
+ for(const std::pair<std::string, Expression>& tag: expression.tags){
+ std::list<LateSymbolRecognized> symbols = recognizeLateIdentifiers(tag.second, scopeLate);
+ if(!symbols.size()){
+ //Standard compilation
+ Parent::graph->printInplaceAnnotation(ident, tag.second);
+
+ } else{
+ //Late compilation
+ std::list<std::string> domains;
+ for(const auto& symbol: symbols){
+ Symbol symbolUnpacked = Parent::man->transcend->unpack(symbol.second);
+ ExpandedType typSymbol = Parent::man->root->getType(CodeScope::getDefinition(symbolUnpacked));
+ assert(typSymbol->__operator == TypeOperator::SLAVE);
+
+ domains.push_back(typSymbol->__valueCustom);
+ }
+
+ Parent::graph->printLateAnnotation(ident, tag.second, symbols, domains);
+ }
+ }
+ }
+
+private:
+ std::unordered_map<const CodeScope*, LateReasoningScope*> __dictScopes;
+};
+
+}}
+
+#endif /* LATEREASONINGPASS_H */
+
diff --git a/cpp/src/query/polymorph.cpp b/cpp/src/query/polymorph.cpp
index ca9bc4c..794b237 100644
--- a/cpp/src/query/polymorph.cpp
+++ b/cpp/src/query/polymorph.cpp
@@ -1,55 +1,57 @@
/*
* 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"
-
+#include "aux/transcend-decorators.h"
using namespace std;
namespace xreate { namespace polymorph {
const std::string atomPolymorph = "dfa_callguard";
void
PolymorphQuery::init(TranscendLayer* transcend){
__transcend = transcend;
StaticModel queryResult = transcend->query(atomPolymorph);
if (queryResult.size()){
for (auto entry: queryResult){
auto answer = TranscendLayer::parse<SymbolNode, Expression>(entry.second);
SymbolNode symbCaller = std::get<0>(answer);
SymbolGeneralized symbCallerUnpacked = transcend->unpack(symbCaller);
Expression guard = std::get<1>(answer);
__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);
}
+ DefaultTranscendLayerImpl* transcendLate = dynamic_cast<DefaultTranscendLayerImpl*>(__transcend);
SymbolNode symbolPacked = __transcend->pack(symbol, "");
- StaticModel answer = __transcend->queryCompiled().queryLate(atomPolymorph, symbolPacked);
+
+ StaticModel answer = transcendLate->queryLate(atomPolymorph, symbolPacked);
assert(answer.size() && "Can't find a guard");
- Expression result;
- tie(result) = TranscendLayer::parse<Expression>(answer.begin()->second);
- return result;
+ Expression guard;
+ tie(guard) = TranscendLayer::parse<Expression>(answer.begin()->second);
+ return guard;
}
}} //end of xreate::polymorph
diff --git a/cpp/src/transcendlayer.cpp b/cpp/src/transcendlayer.cpp
index 2d86470..3058778 100644
--- a/cpp/src/transcendlayer.cpp
+++ b/cpp/src/transcendlayer.cpp
@@ -1,560 +1,486 @@
/* 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: transcendlayer.cpp
*/
/**
* \file transcendlayer.h
- * \brief Resoner. Wrapper over the external Clasp reasoner library
+ * \brief Reasoner. Wrapper over the external Clasp reasoner library
*/
#include "transcendlayer.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));
- }
+namespace xreate{
- std::size_t operator()(const xreate::SymbolAnonymous& node) const noexcept{
- return 7 * node.id;
- }
- };
+bool operator==(const SymbolAnonymous& s1, const SymbolAnonymous& s2) {
+ return s1.id == s2.id && s1.flagIsUsed == s2.flagIsUsed;
}
-namespace std {
- std::size_t
- hash<xreate::SymbolNode>::operator()(xreate::SymbolNode const& s) const noexcept {
- return boost::apply_visitor(xreate::VisitorSymbolNodeHash(), s);
+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
- hash<xreate::SymbolGeneralized>::operator()(xreate::SymbolGeneralized const& s) const noexcept {
- return xreate::AttachmentsId<xreate::SymbolGeneralized>::getId(s);
+ std::size_t operator()(const xreate::SymbolAnonymous& node) const noexcept {
+ return 7 * node.id;
}
+};
}
-namespace xreate {
+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
TranscendLayer::printWarnings(std::ostream& out) {
const std::string warningTag = "warning";
auto warningsModel = query(warningTag);
if(warningsModel.size())
- for (auto warning: warningsModel) {
- unsigned int warningId;
+ for(auto warning : warningsModel) {
+ unsigned int warningId;
- Gringo::Symbol params;
- std::tie(warningId, params) = parse<unsigned int, Gringo::Symbol>(warning.second);
+ Gringo::Symbol params;
+ std::tie(warningId, params) = parse<unsigned int, Gringo::Symbol>(warning.second);
- cout << "Warning: " << __warnings.at(warningId) << " ";
- params.print(out);
- out<<params;
- }
+ cout << "Warning: " << __warnings.at(warningId) << " ";
+ params.print(out);
+ out << params;
+ }
}
bool
-TranscendLayer::handleSolution(Gringo::Model const &model) {
+TranscendLayer::processSolution(Gringo::Model const &model) {
cout << "Model: " << endl;
const string& atomBindVar = Config::get("transcend.bindings.variable");
const string& atomBindFunc = Config::get("transcend.bindings.function");
const string& atomBindScope = Config::get("transcend.bindings.scope");
- const string& atomLateStatement = "late";
- for (Gringo::Symbol atom : model.atoms(clingo_show_type_atoms)) {
+ for(Gringo::Symbol atom : model.atoms(clingo_show_type_atoms)) {
atom.print(cout);
- cout <<" | "<< endl;
+ cout << " | " << endl;
string atomName(atom.name().c_str());
- if (atomName == atomBindVar || atomName == atomBindFunc || atomName == atomBindScope){
+ 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.emplace(atomAlias, atom);
+ continue;
}
- __model.addStaticAtom(atomName, atom);
+ __model.emplace(atomName, atom);
}
return true;
}
void
-TranscendLayer::registerReport(IAnalysisReport* report){
+TranscendLayer::registerReport(IAnalysisReport * report) {
__reports.push_back(report);
}
void
-TranscendLayer::runReports(){
- for(IAnalysisReport* report: __reports){
+TranscendLayer::runReports() {
+ for(IAnalysisReport* report : __reports) {
report->print(__partGeneral);
delete report;
}
__reports.clear();
}
void
-TranscendLayer::addRuleWarning(const RuleWarning &rule) {
+TranscendLayer::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;
+ 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;
+ list<list < string>> guardsRaw;
std::transform(rule.__guards.begin(), rule.__guards.end(), std::inserter(guardsRaw, guardsRaw.begin()),
- [this](const Expression &guard) {
+ [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) {
+ 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;
+ __partGeneral << formatWarning
+ % (hook)
+ % (boost::algorithm::join(vars, ", "))
+ % (branch)
+ % (guardsJoined)
+ % (boost::algorithm::join(domains, ", "))
+ << endl;
}
}
unsigned int
-TranscendLayer::registerWarning(std::string &&message) {
+TranscendLayer::registerWarning(std::string && message) {
static int warningId = 0;
__warnings.emplace(warningId, message);
- return warningId++;;
+ return warningId++;
}
void
-TranscendLayer::involveImports() {
+TranscendLayer::involveImports() {
ostream &out = __partGeneral;
if(ast)
- for (string fn: ast->__rawImports)
- {
+ for(string fn : ast->__rawImports) {
std::ifstream file(fn);
- if (!file){
+ if(!file) {
std::cout << "Can't process script file: " << fn << std::endl;
assert(false);
}
- while(!file.eof()){
+ while(!file.eof()) {
string line;
std::getline(file, line);
out << line << endl;
}
}
}
void
-TranscendLayer::addRawScript(std::string&& script){
+TranscendLayer::addRawScript(std::string && script) {
__partGeneral << script;
}
void
TranscendLayer::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);
+ ClingoLib ctl(scriptsDefault, 0, args.data(), { }, 0);
+
+ ctl.add("base",{}, program.str());
+ ctl.ground({
+ {"base",
+ {}}}, nullptr);
-// solve
+ // solve
Gringo::SolveResult result = ctl.solve([this](Gringo::Model const &model) {
- this->handleSolution(model);
+ this->processSolution(model);
return true;
}, {});
- if (result.satisfiable() == Gringo::SolveResult::Satisfiable) {
+ if(result.satisfiable() == Gringo::SolveResult::Satisfiable) {
cout << FGRN("SUCCESSFULLY") << endl;
} else {
cout << FRED("UNSUCCESSFULLY") << endl;
}
-// invoke all query plugins to process solution
- for (auto q: __queries)
- {
+ // invoke all query plugins to process solution
+ for(auto q : __queries) {
q.second->init(this);
}
}
-TranscendLayer::TranscendLayer(): __model(this), ast(nullptr){
-}
-
-const ReasoningModel&
-TranscendLayer::queryCompiled() {
- return __model;
-}
+TranscendLayer::TranscendLayer(): ast(nullptr) { }
StaticModel
-TranscendLayer::query(const std::string& atom){
- return __model.queryStatic(atom);
+TranscendLayer::query(const std::string & atom) const{
+ StaticModel result;
+
+ if (! __model.count(atom)){
+ return result;
+ }
+
+ auto currentDataRange = __model.equal_range(atom);
+ std::copy(currentDataRange.first, currentDataRange.second, std::inserter(result, result.end()));
+ return result;
}
ScopePacked
-TranscendLayer::pack(const CodeScope* const scope) {
+TranscendLayer::pack(const CodeScope * const scope) {
auto pos = __indexScopes.emplace(scope, __indexScopes.size());
- if (pos.second)
+ if(pos.second)
__registryScopes.push_back(scope);
return pos.first->second;
}
size_t
-TranscendLayer::getScopesCount() const{
+TranscendLayer::getScopesCount() const {
return __registryScopes.size();
}
SymbolPacked
-TranscendLayer::pack(const Symbol& symbol, std::string hintSymbolName)
-{
+TranscendLayer::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
-TranscendLayer::unpack(const SymbolPacked& symbol)
-{
- return Symbol{ScopedSymbol{symbol.identifier, symbol.version}, __registryScopes[symbol.scope]};
+TranscendLayer::unpack(const SymbolPacked & symbol) const{
+ return Symbol{ScopedSymbol
+ {symbol.identifier, symbol.version}, __registryScopes[symbol.scope]};
};
std::string
-TranscendLayer::getHintForPackedSymbol(const SymbolPacked& symbol){
+TranscendLayer::getHintForPackedSymbol(const SymbolPacked & symbol) {
auto result = __indexSymbolNameHints.find(symbol);
- return (result == __indexSymbolNameHints.end())? "" : result->second;
+ return(result == __indexSymbolNameHints.end()) ? "" : result->second;
}
-IQuery*
-TranscendLayer::registerQuery(IQuery *query, const QueryId& id) {
+IQuery *
+ TranscendLayer::registerQuery(IQuery *query, const QueryId & id) {
return __queries.emplace(id, query).first->second;
}
-IQuery*
-TranscendLayer::getQuery(const QueryId& id){
+IQuery *
+ TranscendLayer::getQuery(const QueryId & id) {
assert(__queries.count(id) && "Undefined query");
return __queries.at(id);
}
-class VisitorUnpackSymbol: public boost::static_visitor<SymbolGeneralized> {
+class VisitorUnpackSymbol : public boost::static_visitor<SymbolGeneralized>{
public:
- VisitorUnpackSymbol(TranscendLayer* transcend): __transcend(transcend) {}
+
+ VisitorUnpackSymbol(const TranscendLayer* transcend) : __transcend(transcend) { }
SymbolGeneralized operator()(const SymbolPacked& symbol) const {
return __transcend->unpack(symbol);
}
SymbolGeneralized operator()(const SymbolAnonymous& symbol) const {
return symbol;
}
private:
- TranscendLayer* __transcend;
+ const TranscendLayer* __transcend;
};
-class VisitorPackSymbol: public boost::static_visitor<SymbolNode> {
+class VisitorPackSymbol : public boost::static_visitor<SymbolNode>{
public:
+
VisitorPackSymbol(TranscendLayer* transcend, const std::string& hintSymbolName)
- : __transcend(transcend), __hint(hintSymbolName) {}
+ : __transcend(transcend), __hint(hintSymbolName) { }
SymbolNode operator()(const Symbol& symbol) const {
return __transcend->pack(symbol, __hint);
}
SymbolNode operator()(const SymbolAnonymous& symbol) const {
return symbol;
}
private:
TranscendLayer* __transcend;
std::string __hint;
};
-SymbolNode TranscendLayer::pack(const SymbolGeneralized& symbol, const std::string& hintSymbolName){
+SymbolNode
+TranscendLayer::pack(const SymbolGeneralized& symbol, const std::string & hintSymbolName) {
return boost::apply_visitor(VisitorPackSymbol(this, hintSymbolName), symbol);
}
-SymbolGeneralized TranscendLayer::unpack(const SymbolNode& symbol)
-{
+SymbolGeneralized
+TranscendLayer::unpack(const SymbolNode & symbol) const{
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) 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->transcend->unpack(key));
- });
-
- return result;
+bool
+operator==(const SymbolPacked& s1, const SymbolPacked & s2) {
+ return s1.identifier == s2.identifier && s1.scope == s2.scope;
}
-void ReasoningModel::addStaticAtom(const std::string& atomAlias, const Gringo::Symbol& atom){
- modelStatic.emplace(atomAlias, atom);
+bool
+operator<(const SymbolPacked& s1, const SymbolPacked & s2) {
+ return s1.scope < s2.scope || (s1.scope == s2.scope && s1.identifier < s2.identifier);
}
-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[alias];
- if(!model.bindings.count(symbol)){
- model.bindings.emplace(symbol, guardKeys);
- }
-
- GuardedAnnotation& annotation = model.annotations[symbol];
- annotation.guardedSymbols.push_back(make_pair(guardBindings, atom));
-}
+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())));
-StaticModel
-ReasoningModel::queryStatic(const std::string& alias) const{
- StaticModel result;
+ 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));
+ }
- 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 SymbolNode& symbol) const{
- StaticModel result;
- if (!modelGuarded.count(alias)) return StaticModel();
-
- const LateModel& model = modelGuarded.at(alias);
- assert(model.bindings.count(symbol));
- const list<SymbolPacked>& bindings = model.bindings.at(symbol);
- list<Expression>&& keys = findKeys(bindings);
-
- const GuardedAnnotation& annGuarded = model.annotations.at(symbol);
- auto ann = annGuarded.get(keys);
- if(ann){
- result.emplace(make_pair(alias, *ann));
+ default:
+ {
+ assert(false);
}
-
- 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;
+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();
+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;
+ default: break;
}
assert(false && "Inappropriate symbol type");
}
SymbolPacked
-ParseImplAtom<SymbolPacked>::get(const Gringo::Symbol& atom) {
+ParseImplAtom<SymbolPacked>::get(const Gringo::Symbol & atom) {
auto result = TranscendLayer::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) {
+ParseImplAtom<Gringo::Symbol>::get(const Gringo::Symbol & atom) {
return atom;
}
SymbolNode
-ParseImplAtom<SymbolNode>::get(const Gringo::Symbol& atom) {
+ParseImplAtom<SymbolNode>::get(const Gringo::Symbol & atom) {
assert(atom.type() == Gringo::SymbolType::Fun
- && "Inappropriate symbol type");
+ && "Inappropriate symbol type");
- if (atom.name() == "a"){
+ if(atom.name() == "a") {
return SymbolAnonymous{(unsigned int) std::get<0>(TranscendLayer::parse<int>(atom))};
- } else if (atom.name() == "s"){
+ } else if(atom.name() == "s") {
return ParseImplAtom<SymbolPacked>::get(atom);
}
assert(false && "Wrong symbol format");
}
-class VisitorSymbolId: public boost::static_visitor<unsigned int> {
+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){
+AttachmentsId<SymbolGeneralized>::getId(const SymbolGeneralized & symbol) {
return boost::apply_visitor(VisitorSymbolId(), symbol);
}
} //end of xreate namespace
/**
* \class xreate::TranscendLayer
* \brief Reasoning and logic Solver.
*
* Wraps external brilliant fantastic tool [Clasp solver](https://potassco.org/clasp/)
*
* For building *logic program* for reasoning TranscendLayer 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 TranscendLayer got input from all providers and logic program is fully constructed
* it runs external Clasp reasoner and receives back desired solutions.
*
* Output of the external 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
*/
diff --git a/cpp/src/transcendlayer.h b/cpp/src/transcendlayer.h
index 5f20f89..e52d91d 100644
--- a/cpp/src/transcendlayer.h
+++ b/cpp/src/transcendlayer.h
@@ -1,316 +1,282 @@
/* 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: transcendlayer.h
*/
#ifndef transcendLAYER_H
#define transcendLAYER_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;
//DEBT use SymbolGeneralized communicating with Analysis rather than Symbol
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(TranscendLayer* transcend) = 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::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(TranscendLayer* transcendLayer): transcend(transcendLayer) {}
- 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) const;
- StaticModel queryLate(const std::string& alias, const SymbolNode& symbol) const;
-
-private:
- TranscendLayer* transcend;
- StaticModel modelStatic;
- 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 TranscendLayer {
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);
- const ReasoningModel& queryCompiled();
-
+ StaticModel query(const std::string& atom) const;
size_t getScopesCount() const;
SymbolPacked pack(const Symbol& symbol, std::string hintSymbolName = "");
ScopePacked pack(const CodeScope * const scope);
- Symbol unpack(const SymbolPacked& symbol);
+ Symbol unpack(const SymbolPacked& symbol) const;
SymbolNode pack(const SymbolGeneralized& symbol, const std::string& hintSymbolName);
- SymbolGeneralized unpack(const SymbolNode& symbol);
+ SymbolGeneralized unpack(const SymbolNode& symbol) const;
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:
TranscendLayer();
/** \brief Executes reasoning */
void run();
///@}
AST *ast;
-private:
+protected:
+ virtual bool processSolution(Gringo::Model const &model);
+private:
+ StaticModel __model;
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);
+ bool flagIsList = (atom.type() == Gringo::SymbolType::Fun) && atom.name().empty();
std::list<ItemType> result;
+ if(!flagIsList) {
+ //treat as degenerate case: list with a single element
+ result.push_back(ParseImplAtom<ItemType>::get(atom));
+ return 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...>
TranscendLayer::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/xreatemanager.cpp b/cpp/src/xreatemanager.cpp
index 1b5cddf..fe81268 100644
--- a/cpp/src/xreatemanager.cpp
+++ b/cpp/src/xreatemanager.cpp
@@ -1,157 +1,156 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* xreatemanager.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on July 3, 2017, 6:03 PM
*/
#include "xreatemanager.h"
#include "pass/abstractpass.h"
-#include "transcendlayer.h"
+#include "aux/transcend-decorators.h"
#include "aux/xreatemanager-decorators.h"
#include "llvmlayer.h"
-#include "main/Parser.h"
#include <assert.h>
#include <list>
namespace xreate {
void
PassManager::registerPass(IPass* pass, const PassId& id, IPass* parent)
{
__passes.emplace(id, pass);
__passDependencies.emplace(parent, pass);
}
IPass*
PassManager::getPassById(const PassId& id){
assert(__passes.count(id));
return __passes[id];
}
bool
PassManager::isPassRegistered(const PassId& id){
return __passes.count(id);
}
void
PassManager::executePasses(){
std::list<IPass*> passes{nullptr};
while (passes.size()){
IPass* parent = passes.front();
auto range = __passDependencies.equal_range(parent);
for (auto i=range.first; i!=range.second; ++i){
IPass* pass = i->second;
pass->run();
pass->finish();
passes.push_back(pass);
}
passes.pop_front();
}
}
void
PassManager::prepare(AST* ast){
root = ast;
- transcend = new TranscendLayer();
+ transcend = new DefaultTranscendLayerImpl();
transcend->ast = ast;
llvm = new LLVMLayer(ast);
}
PassManager::~PassManager(){}
typedef XreateManagerDecoratorFull XreateManagerDecoratorDefault;
namespace details{ namespace tier2{
XreateManager*
XreateManager::prepare(std::string&& code){
auto man = new XreateManagerImpl<XreateManagerDecoratorDefault>;
man->prepareCode(std::move(code));
return man;
}
XreateManager*
XreateManager::prepare(FILE* code){
auto man = new XreateManagerImpl<XreateManagerDecoratorDefault>;
man->prepareCode(code);
return man;
}
}}
namespace details { namespace tier1 {
XreateManager*
XreateManager::prepare(std::string&& code){
auto man = new XreateManagerImpl<XreateManagerDecoratorDefault>;
man->prepareCode(std::move(code));
return man;
}
XreateManager*
XreateManager::prepare(FILE* code){
auto man = new XreateManagerImpl<XreateManagerDecoratorDefault>;
man->prepareCode(code);
return man;
}
}}
/**
* \class xreate::XreateManager
* \brief Entry point of Xreate API
*
* Manages whole Xreate's internal workflow. There are 4 distinctive stages covered by XreateManager:
* - initPasses() To init passes
* - executePasses() To execute passes
* - analyse() To run reasoner
* - run() To run compiler
*
* For adaptability manager comes with several *Frontends*:
* - xreate::details::tier2::XreateManager has all stages accessible by client for full control
* - xreate::details::tier1::XreateManager has only analyse() and run(), where analyse() combines execution of all previous stages
* - xreate::XreateManager has only run() to combine all stages for convenient use
*
* Moreover there are *Backends*:
* - xreate::XreateManagerDecoratorBase Simple backend intended for inheritance without much functionality
* - XreateManagerDecoratorFull Backend intended to initialize all builtin passes
*
* Thus, client's code could combine desired frontend and desired backend as see fit.
* Default xreate::XreateManager connects full backend to init all builtin passes
* to a simplest frontend with only run() available to execute all stages at once
*/
/**
*\brief Constructs XreateManager for a given code
*/
XreateManager*
XreateManager::prepare(std::string&& code) {
auto man = new XreateManagerImpl<XreateManagerDecoratorDefault>;
man->prepareCode(std::move(code));
return man;
}
/**
*\brief Constructs XreateManager for a given script file
*/
XreateManager*
XreateManager::prepare(FILE* code){
auto man = new XreateManagerImpl<XreateManagerDecoratorDefault>;
man->prepareCode(code);
return man;
}
}
diff --git a/cpp/src/xreatemanager.h b/cpp/src/xreatemanager.h
index 1dfdc80..5609a31 100644
--- a/cpp/src/xreatemanager.h
+++ b/cpp/src/xreatemanager.h
@@ -1,141 +1,141 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* xreatemanager.h
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on July 3, 2017, 6:03 PM
*/
/**
* \file
* \brief Entry point of Xreate API.
*
*/
#ifndef PASSMANAGER_H
#define PASSMANAGER_H
#include <string>
#include <map>
//stdio external
struct _IO_FILE;
typedef struct _IO_FILE FILE;
namespace xreate { namespace grammar { namespace main {
class Scanner;
}}}
namespace xreate {
class IPass;
class TranscendLayer;
class LLVMLayer;
class AST;
enum class PassId {
- CFGPass,
+ CFAPass,
CompilePass,
- DFGPass,
+ DFAPass,
EnvironmentTestsPass,
LoggerPass,
RulesPass,
InterpretationPass,
VersionsPass
};
/**
* \class PassManager
* \brief Base class to control passes
*/
class PassManager{
public:
void prepare(AST* ast);
void registerPass(IPass* pass, const PassId& id, IPass* prerequisite=nullptr);
IPass* getPassById(const PassId& id);
bool isPassRegistered(const PassId& id);
void executePasses();
virtual ~PassManager();
TranscendLayer* transcend;
LLVMLayer* llvm;
AST* root;
private:
std::map<PassId, IPass*> __passes;
std::multimap<IPass*, IPass*> __passDependencies;
};
namespace details{ namespace tier2{
class XreateManager: public virtual PassManager{
public:
virtual ~XreateManager(){};
virtual void initPasses()=0;
// virtual void executePasses()=0;
virtual void analyse()=0;
virtual void* run()=0;
static XreateManager* prepare(std::string&& code);
static XreateManager* prepare(FILE* code);
};
template<class Decorator>
class XreateManagerImpl: public Decorator {
public:
};
}} //namespace details::tier2
namespace details{ namespace tier1{
class XreateManager: public virtual PassManager{
public:
virtual void analyse()=0;
virtual void* run()=0;
static XreateManager* prepare(std::string&& code);
static XreateManager* prepare(FILE* code);
};
template<class Decorator>
class XreateManagerImpl: public XreateManager, public details::tier2::XreateManagerImpl<Decorator> {
typedef details::tier2::XreateManagerImpl<Decorator> PARENT;
public:
void analyse(){
PARENT::initPasses();
PARENT::executePasses();
PARENT::analyse();
}
void* run(){
return PARENT::run();
}
};
}} //namespace details::tier1
class XreateManager: public virtual PassManager{
public:
virtual void* run()=0;
static XreateManager* prepare(std::string&& code);
static XreateManager* prepare(FILE* code);
};
template<class Decorator>
class XreateManagerImpl: public XreateManager, public details::tier1::XreateManagerImpl<Decorator>{
typedef details::tier1::XreateManagerImpl<Decorator> PARENT;
public:
void* run(){
PARENT::analyse();
return PARENT::run();
}
};
} //namespace xreate
#endif
diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt
index afac651..8124d0b 100644
--- a/cpp/tests/CMakeLists.txt
+++ b/cpp/tests/CMakeLists.txt
@@ -1,54 +1,55 @@
cmake_minimum_required(VERSION 2.8.11)
project(xreate-tests)
find_package(GTest REQUIRED)
INCLUDE_DIRECTORIES(${GTEST_INCLUDE_DIRS})
INCLUDE_DIRECTORIES("/usr/include/libxml2")
INCLUDE_DIRECTORIES($<TARGET_PROPERTY:xreate,INCLUDE_DIRECTORIES>)
# TESTS
#=========================
FIND_PACKAGE (LLVM REQUIRED)
message("LLVM_LIBRARY_DIRS: " ${LLVM_LIBRARY_DIRS})
link_directories(${LLVM_LIBRARY_DIRS})
set (LIBCLASP_PATH ${POTASSCO_PATH}/build/debug)
link_directories(${LIBCLASP_PATH})
#aux_source_directory(. TEST_FILES)
set(TEST_FILES
+ transcend.cpp
latereasoning.cpp
virtualization.cpp
exploitation.cpp
- communication.cpp
+ effects-communication.cpp
polymorph.cpp
association.cpp
main.cpp
modules.cpp
attachments.cpp
ast.cpp
cfa.cpp
dfa.cpp
compilation.cpp
ExpressionSerializer.cpp
externc.cpp
types.cpp
#vendorsAPI/clangAPI.cpp
#vendorsAPI/xml2.cpp
#vendorsAPI/json.cpp
containers.cpp
interpretation.cpp
loops.cpp
#supplemental/versions-algorithm-data_dependency.cpp
effects-versions.cpp
)
add_executable(${PROJECT_NAME} ${TEST_FILES})
target_link_libraries(${PROJECT_NAME} xreate ${GTEST_LIBRARIES} pthread xml2 gcov)
add_custom_target (coverage
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/src/code-coverage.sh
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
diff --git a/cpp/tests/cfa.cpp b/cpp/tests/cfa.cpp
index 1672da0..002cae2 100644
--- a/cpp/tests/cfa.cpp
+++ b/cpp/tests/cfa.cpp
@@ -1,190 +1,190 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* testsCFG.cpp
*
* Created on: Jul 17, 2015
* Author: pgess <v.melnychenko@xreate.org>
*/
#include "xreatemanager.h"
#include "pass/dfapass.h"
#include "pass/cfapass.h"
#include "analysis/DominatorsTreeAnalysisProvider.h"
#include "analysis/cfagraph.h"
#include "gtest/gtest.h"
#include <boost/scoped_ptr.hpp>
#include <boost/smart_ptr/scoped_array.hpp>
using namespace xreate;
using namespace xreate::cfa;
using namespace std;
TEST(CFA, testFunctionAnnotationstranscend){
string&& program =
"f2 = function::int; annotationF2 {\n"
" 0\n"
"}\n"
"\n"
"f1 = function:: int; entry; annotationF1 {\n"
" f2() + 10\n"
"}";
details::tier1::XreateManager* man = details::tier1::XreateManager::prepare(move(program));
man->analyse();
StaticModel answer = man->transcend->query("annotationF1");
EXPECT_EQ(1, answer.size());
answer = man->transcend->query("annotationF2");
EXPECT_EQ(1, answer.size());
}
TEST(CFA, testLoopContextExists){
details::tier1::XreateManager* man = details::tier1::XreateManager::prepare (
"interface(cfa){\n"
" operator fold:: annotation1.\n"
"}\n"
"\n"
"main = function:: int; entry {\n"
" x = [1..10]:: [int].\n"
" sum = loop fold (x->el:: int, 0->sum):: int {\n"
" el + sum + f1()\n"
" }. \n"
" sum\n"
"}"
"case context:: annotation1 {"
" f1 = function::int {\n"
" x = 0:: int. "
" x\n"
" }"
"}"
);
man->analyse();
StaticModel model = man->transcend->query("annotation1");
ScopePacked scopeIdActual = std::get<0>(TranscendLayer::parse<ScopePacked>(model.begin()->second));
CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope();
const Expression& exprSum = scopeEntry->getDefinition(scopeEntry->getSymbol("sum"));
CodeScope* scopeExpected = exprSum.blocks.front();
ScopePacked scopeIdExpected = man->transcend->pack(scopeExpected);
ASSERT_EQ(scopeIdExpected, scopeIdActual);
}
TEST(CFA, DependenciesFnCall){
details::tier2::XreateManager* man = details::tier2::XreateManager::prepare(
R"Code(
a = function::int{
seq
{x = 0:: int. x}
{x = b():: int. x}::int
}
b = function::int {y = 0. y}
)Code");
CodeScope* scopeSeq1 = man->root->findFunction("a")->getEntryScope()->getBody().blocks.front();
CodeScope* scopeSeq2 = *(++man->root->findFunction("a")->getEntryScope()->getBody().blocks.begin());
CodeScope* scopeB = man->root->findFunction("b")->getEntryScope();
ScopePacked psSeq1 = man->transcend->pack(scopeSeq1);
ScopePacked psSeq2 = man->transcend->pack(scopeSeq2);
ScopePacked psB = man->transcend->pack(scopeB);
CFAPass* pass = new CFAPass(man);
- man->registerPass(pass, PassId::CFGPass);
+ man->registerPass(pass, PassId::CFAPass);
man->executePasses();
- const CFAGraph* report = dynamic_cast<CFAPassBasic*>(man->getPassById(PassId::CFGPass))->getReport();
+ const CFAGraph* report = dynamic_cast<CFAPassBasic*>(man->getPassById(PassId::CFAPass))->getReport();
auto dependencies = report->__dependencyRelations;
delete pass;
ASSERT_EQ(1, dependencies.count(psSeq2));
ASSERT_EQ(1, dependencies.count(psB));
}
TEST(CFA, DependenciesChildScope){
details::tier2::XreateManager* man = details::tier2::XreateManager::prepare(
R"Code(
a = function::int{
seq
{x = 0:: int. x}
{x=0::int. if(x>0)::int{1} else {0}}::int
}
)Code");
CodeScope* scopeSeq1 = man->root->findFunction("a")->getEntryScope()->getBody().blocks.front();
CodeScope* scopeSeq2 = *(++man->root->findFunction("a")->getEntryScope()->getBody().blocks.begin());
CodeScope* scopeIf1 = scopeSeq2->getBody().blocks.front();
CodeScope* scopeIf2 = *(++scopeSeq2->getBody().blocks.begin());
ScopePacked psSeq1 = man->transcend->pack(scopeSeq1);
ScopePacked psSeq2 = man->transcend->pack(scopeSeq2);
ScopePacked psIf1 = man->transcend->pack(scopeIf1);
ScopePacked psIf2 = man->transcend->pack(scopeIf2);
CFAPass* pass = new CFAPass(man);
- man->registerPass(pass, PassId::CFGPass);
+ man->registerPass(pass, PassId::CFAPass);
man->executePasses();
- const CFAGraph* report = dynamic_cast<CFAPassBasic*>(man->getPassById(PassId::CFGPass))->getReport();
+ const CFAGraph* report = dynamic_cast<CFAPassBasic*>(man->getPassById(PassId::CFAPass))->getReport();
auto dependencies = report->__dependencyRelations;
delete pass;
ASSERT_EQ(0, dependencies.count(psSeq1));
ASSERT_EQ(1, dependencies.count(psSeq2));
ASSERT_EQ(1, dependencies.count(psIf1));
ASSERT_EQ(1, dependencies.count(psIf2));
for(auto rec: dependencies)
{
std::cout << rec.first << " " << rec.second << std::endl;
}
}
TEST(CFA, DomReportOneRoot){
std::string program =
R"CODE(
a = function:: int; entry{
seq
{x = 0:: int. x}
{x = 1:: int. x}::int
}
)CODE";
std::unique_ptr<details::tier2::XreateManager> man(details::tier2::XreateManager::prepare(move(program)));
CFAPass* pass = new CFAPass(man.get());
- man->registerPass(pass, PassId::CFGPass);
+ man->registerPass(pass, PassId::CFAPass);
pass->run();
ScopePacked scope1 = man->transcend->pack(man->root->findFunction("a")->getEntryScope()->getBody().blocks.front());
ScopePacked scope2 = man->transcend->pack(*++man->root->findFunction("a")->getEntryScope()->getBody().blocks.begin());
dominators::DominatorsTreeAnalysisProvider* providerDomAnalysis = new dominators::DominatorsTreeAnalysisProvider();
providerDomAnalysis->run(pass->getReport());
dominators::DominatorsTreeAnalysisProvider::Dominators expectedFDom= {
{1, {0, 3}}
,{2, {1, 2}}
};
dominators::DominatorsTreeAnalysisProvider::Dominators expectedPostDom= {
{2, {0, 3}}
,{1, {1, 2}}
};
auto actualFDom = providerDomAnalysis->getForwardDominators();
auto actualPostDom = providerDomAnalysis->getPostDominators();
ASSERT_EQ(expectedFDom, actualFDom);
ASSERT_EQ(expectedPostDom, actualPostDom);
delete providerDomAnalysis;
delete pass;
}
diff --git a/cpp/tests/communication.cpp b/cpp/tests/effects-communication.cpp
similarity index 100%
rename from cpp/tests/communication.cpp
rename to cpp/tests/effects-communication.cpp
diff --git a/cpp/tests/latereasoning.cpp b/cpp/tests/latereasoning.cpp
index 1e3f715..7f307c1 100644
--- a/cpp/tests/latereasoning.cpp
+++ b/cpp/tests/latereasoning.cpp
@@ -1,109 +1,215 @@
/* 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 "transcendlayer.h"
+#include "pass/latereasoningpass.h"
+#include "aux/latereasoning.h"
+#include "pass/dfapass.h"
#include <boost/format.hpp>
#include "gtest/gtest.h"
using namespace xreate;
+using namespace xreate::latereasoning;
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()
+ typedef LateReasoningTranscendDecorator<TranscendLayer> LRTranscend;
- Attachments::init<LateBinding>();
+ Attachments::init<LateBindingT>();
Attachments::init<versions::VariableVersion>();
- std::unique_ptr<TranscendLayer> transcend(new TranscendLayer());
+ std::unique_ptr<LRTranscend> transcend(new LRTranscend());
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 = transcend->pack(symbA, "a");
SymbolPacked symbpB = transcend->pack(symbB, "b");
SymbolPacked symbpC = transcend->pack(symbC, "c");
SymbolPacked symbpTarget = transcend->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
transcend->addRawScript((formatLateAnnotation
% FORMATSYMBOL(symbpTarget)
% FORMATSYMBOL(symbpA) % FORMATSYMBOL(symbpB) % FORMATSYMBOL(symbpC)
% "guard1" % "guard1" % "guard1"
% "result(variant1)"
). str());
//Add `result2` variant
transcend->addRawScript((formatLateAnnotation
% FORMATSYMBOL(symbpTarget)
% FORMATSYMBOL(symbpA) % FORMATSYMBOL(symbpB) % FORMATSYMBOL(symbpC)
% "guard2" % "guard2" % "guard2"
% "result(variant2)"
). str());
transcend->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")}));
+ Attachments::put<LateBindingT>(symbA, Expression(Operator::CALL, {Atom<Identifier_t>("guard2")}));
+ Attachments::put<LateBindingT>(symbB, Expression(Operator::CALL, {Atom<Identifier_t>("guard2")}));
+ Attachments::put<LateBindingT>(symbC, Expression(Operator::CALL, {Atom<Identifier_t>("guard2")}));
//Fetch late annotation
- ReasoningModel model = transcend->queryCompiled();
- StaticModel answer = model.queryLate("result", symbpTarget);
+ StaticModel answer = transcend->queryLate("result", symbpTarget);
ASSERT_EQ(1, answer.size());
std::tuple<std::string> answerParsed = transcend->parse<std::string>(answer.begin()->second);
ASSERT_STREQ("variant2", std::get<0>(answerParsed).c_str());
}
TEST(LateReasoning, Syntax1) {
XreateManager* man = XreateManager::prepare(R"Code(
test = function:: int {
x = 0::int.
y1= switch late (x)::int{0}.
y2= switch late(x+y1->a::int)::int{1}.
y1+y2
}
)Code");
CodeScope* scope = man->root->findFunction("test")->getEntryScope();
Expression y1 = scope->getDefinition(scope->getSymbol("y1"));
Expression y2 = scope->getDefinition(scope->getSymbol("y2"));
ASSERT_EQ(1, y1.bindings.size());
ASSERT_STRCASEEQ("x", y1.bindings.at(0).c_str());
ASSERT_EQ(1, y2.bindings.size());
ASSERT_STRCASEEQ("a", y2.bindings.at(0).c_str());
}
+
+TEST(LateReasoning, Compilation1){
+ XreateManager* man = XreateManager::prepare(R"Code(
+Color = type variant{RED, BLUE, GREEN}.
+
+test = function:: int; entry {
+ x = RED():: Color.
+ y1= switch late (x):: int
+ {0}.
+ y1
+}
+)Code");
+
+ int (*program)() = (int (*)())man->run();
+ int result = program();
+
+ ASSERT_EQ(0, result);
+}
+
+TEST(LateReasoning, LateVariablesRecognition1){
+ typedef LateReasoningTranscendDecorator<TranscendLayer> LRTranscend;
+
+ auto man = details::tier2::XreateManager::prepare(R"Code(
+Dom = type slave dom.
+
+test = function:: int; entry
+{
+ LateIdent = 0:: Dom.
+ 0:: int; ann1(LateIdent)
+}
+)Code");
+
+ CodeScope* scopeEntry = man->root->findFunction("test")->getEntryScope();
+ ScopedSymbol keyS = scopeEntry->getSymbol("LateIdent");
+ SymbolPacked keySP = man->transcend->pack(Symbol{keyS, scopeEntry});
+
+ std::shared_ptr<LateReasoningScope> scopeLateEntry(new LateReasoningScope(nullptr));
+ scopeLateEntry->addIdentifier("LateIdent", keySP);
+
+ //Pass information to the late scope
+ typedef LateReasoningDFAPassDecorator<dfa::DFAPass> LRDFAPass;
+ LRDFAPass* dfaPass = new LRDFAPass(man);
+ dfaPass->registerLateScope(scopeEntry, scopeLateEntry.get());
+
+ //Pass information to the late model
+ Attachments::init<LateBindingT>();
+ man->transcend->addRawScript("dom(guard1; guard2).\n");
+ Attachments::put<LateBindingT>(Symbol{keyS, scopeEntry}, Expression(Operator::CALL, {Atom<Identifier_t>("guard1")}));
+
+ man->registerPass(dfaPass, PassId::DFAPass, nullptr);
+ man->executePasses();
+ man->analyse();
+
+ //Fetch late annotation
+ LRTranscend* transcend = dynamic_cast<LRTranscend*>(man->transcend);
+ SymbolPacked targetSymP = transcend->pack(Symbol{ScopedSymbol::RetSymbol, scopeEntry});
+ StaticModel solution = transcend->queryLate("ann1", targetSymP);
+ ASSERT_EQ(1, solution.size());
+
+ std::tuple<std::string> solutionParsed = man->transcend->parse<std::string>(solution.begin()->second);
+ ASSERT_STREQ("guard1", std::get<0>(solutionParsed).c_str());
+}
+
+TEST(LateReasoning, Compilation2){
+ auto man = details::tier1::XreateManager::prepare(R"Code(
+ DomLow = type variant {guard1, guard2}.
+ Dom = type slave dom.
+
+ guard:: guard1 {
+ compute = function :: int
+ {0}
+ }
+
+ guard:: guard2 {
+ compute = function :: int
+ {1}
+ }
+
+ test = function:: int; entry
+ {
+ xLate = guard2():: DomLow.
+ y1= switch late ((xLate::Dom):: Dom; alias(xLate)):: int
+ {
+ compute():: int; guardkey(xLate)
+ }.
+ y1
+ }
+ )Code");
+
+ man->transcend->addRawScript(R"RAW(
+ dom(guard1; guard2).
+ late(Target, Key, Variant, dfa_callguard(Variant)):-
+ bind(Target, guardkey(Alias));
+ bind(Key, alias(Alias));
+ dom(Variant).
+ )RAW");
+ man->analyse();
+ int (*program)() = (int (*)())man->run();
+ int result = program();
+
+ ASSERT_EQ(1, result);
+}
diff --git a/cpp/tests/main.cpp b/cpp/tests/main.cpp
index 5ab9a9b..2df18c6 100644
--- a/cpp/tests/main.cpp
+++ b/cpp/tests/main.cpp
@@ -1,24 +1,24 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* main.cpp
*
- * Created on: -
+ * Created on: 00:00 Xreate Epoch
* Author: pgess <v.melnychenko@xreate.org>
*/
#include "utils.h"
#include <gtest/gtest.h>
using namespace std;
using namespace xreate;
int main(int argc, char **argv) {
testing::GTEST_FLAG(color) = "yes";
string testsTemplate = Config::get("tests.template");
string testsFilter = Config::get(string("tests.templates.") + testsTemplate);
testing::GTEST_FLAG(filter) = testsFilter;
testing::InitGoogleTest(&argc, argv);
-
+
return RUN_ALL_TESTS();
}
diff --git a/cpp/tests/polymorph.cpp b/cpp/tests/polymorph.cpp
index 226218f..9dd13f5 100644
--- a/cpp/tests/polymorph.cpp
+++ b/cpp/tests/polymorph.cpp
@@ -1,106 +1,108 @@
/* 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 "transcendlayer.h"
+#include "aux/latereasoning.h"
#include <list>
#include "gtest/gtest.h"
-#include "transcendlayer.h"
-using namespace std;
using namespace xreate;
+using namespace xreate::latereasoning;
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, 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>();
+ Attachments::init<LateBindingT>();
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->transcend->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")}));
+ Attachments::put<LateBindingT>(symbKey, Expression(Operator::CALL, {Atom<Identifier_t>("b")}));
int (*main)() = (int (*)()) man->run();
ASSERT_EQ(1, main());
}
diff --git a/cpp/tests/transcend.cpp b/cpp/tests/transcend.cpp
new file mode 100644
index 0000000..5ad0ef3
--- /dev/null
+++ b/cpp/tests/transcend.cpp
@@ -0,0 +1,43 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ * Created on June 7, 2018, 3:35 PM
+ *
+ * \file transcend.cpp
+ * \brief Transcend's tests
+ */
+
+#include "xreatemanager.h"
+#include "transcendlayer.h"
+#include <gtest/gtest.h>
+
+using namespace xreate;
+using namespace std;
+
+TEST(Transcend, Parse1) {
+ std::string script =
+R"Code(
+)Code";
+
+ std::unique_ptr<details::tier1::XreateManager> man(details::tier1::XreateManager::prepare(std::move(script)));
+
+ std::string scriptTranscend =
+R"Code(
+ test1((1)).
+ test2((1, 2)).
+)Code";
+
+ man->transcend->addRawScript(move(scriptTranscend));
+ man->analyse();
+
+ StaticModel solution = man->transcend->query("test1");
+ Gringo::Symbol symbTest1 = solution.begin()->second;
+ auto answer1 = man->transcend->parse<list<int>>(symbTest1);
+ ASSERT_EQ(1, get<0>(answer1).size());
+
+ solution = man->transcend->query("test2");
+ Gringo::Symbol symbTest2 = solution.begin()->second;
+ auto answer2 = get<0>(man->transcend->parse<list<int>>(symbTest2));
+ ASSERT_EQ(2, answer2.size());
+}
\ No newline at end of file
diff --git a/git-commit-template b/git-commit-template
new file mode 100644
index 0000000..94da945
--- /dev/null
+++ b/git-commit-template
@@ -0,0 +1,12 @@
+<Changeset description>
+
+Syntax: <syntax changes>
+Transcend: <any changes related to reasoning>
+Compilation: <any changes on compilation side>
+Documentation: <...>
+<component, AST, DFAPass etc>: <...>
+
+Malfunctions: <what is broken after commit, broken/disabled tests>
+
+Tests: <tests that cover commited changes>
+
diff --git a/grammar/xreate.ATG b/grammar/xreate.ATG
index 77cf607..4947344 100644
--- a/grammar/xreate.ATG
+++ b/grammar/xreate.ATG
@@ -1,664 +1,676 @@
//TODO add ListLiteral
//TODO ExprTyped: assign default(none) type
#include "ast.h"
#include "ExternLayer.h"
#include <string>
#include <stack>
#define wprintf(format, ...) \
char __buffer[100]; \
wcstombs(__buffer, format, 100); \
fprintf(stderr, __buffer, __VA_ARGS__)
using namespace std;
COMPILER Xreate
details::inconsistent::AST* root = nullptr; // current program unit
void ensureInitalizedAST(){
if (root == nullptr) root = new details::inconsistent::AST();
}
struct {
std::stack<CodeScope*> scopesOld;
CodeScope* scope = nullptr;
} context;
void pushContextScope(CodeScope* scope){
context.scopesOld.push(context.scope);
context.scope = scope;
}
void popContextScope(){
context.scope = context.scopesOld.top();
context.scopesOld.pop();
}
int nextToken()
{
scanner->ResetPeek();
return scanner->Peek()->kind;
}
bool checkTokenAfterIdent(int key){
if (la->kind != _ident) return false;
return nextToken() == key;
}
bool checkParametersList()
{
return la->kind == _ident && nextToken() == _lparen;
}
bool checkInfix()
{
return la->kind == _ident && nextToken() == _ident;
}
bool checkIndex()
{
return la->kind == _ident && nextToken() == _lbrack;
}
bool checkFuncDecl()
{
if (la->kind != _ident) return false;
int token2 = nextToken();
int token3 = scanner->Peek()->kind;
return token2 == _assign && (token3 == _function || token3 == _pre);
}
bool checkAssignment()
{
if (la->kind != _ident) return false;
scanner->ResetPeek();
int token2 = scanner->Peek()->kind;
if (token2 == _lcurbrack) {
scanner->Peek();
int token3 = scanner->Peek()->kind;
if (token3 != _rcurbrack) return false;
int token4 = scanner->Peek()->kind;
return token4 == _assign;
}
return token2 == _assign;
}
void recognizeIdentifier(Expression& i){
if (!context.scope->recognizeIdentifier(i)){
root->postponeIdentifier(context.scope, i);
}
}
enum SwitchKind{SWITCH_NORMAL, SWITCH_META};
CHARACTERS
letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".
any = ANY - '"'.
digit = "0123456789".
cr = '\r'.
lf = '\n'.
tab = '\t'.
TOKENS
ident = (letter | '_') {letter | digit | '_'}.
number = (digit | '-' digit) {digit}.
string = '"' { any } '"'.
function = "function".
pre = "pre".
+ comma = ','.
+ period = '.'.
lparen = '('.
rparen = ')'.
lbrack = '['.
rbrack = ']'.
lcurbrack = '{'.
rcurbrack = '}'.
equal = "==".
assign = '='.
implic = '-' '>'.
colon = ':'.
context = "context".
tagcolon = "::".
lse = "<=".
lss = "<".
gte = ">=".
gtr = ">".
ne1 = "!=".
ne2= "<>".
COMMENTS FROM "/*" TO "*/" NESTED
COMMENTS FROM "//" TO lf
IGNORE cr + lf + tab
PRODUCTIONS
Xreate = (. Function* function; ensureInitalizedAST(); .)
{( RuleDecl
| InterfaceData | Imprt | GuardSection
| IF(checkFuncDecl()) FDecl<function> (. root->add(function); .)
| TDecl
| SkipModulesSection
)} (. .)
.
Ident<std::wstring& name>
= ident (. name = t->val; .).
VarIdent<Expression& e>
= ident (. e = Expression(Atom<Identifier_t>(t->val)); .)
[ lcurbrack (
ident (. SemErr(coco_string_create("var version as ident is not implemented yet")); .)
| number (. Attachments::put<versions::VariableVersion>(e, Atom<Number_t>(t->val).get()); .)
) rcurbrack ]
.
FDecl<Function*& f> = (. std::wstring fname; std::wstring argName; TypeAnnotation typIn; TypeAnnotation typOut; bool flagIsPrefunct = false; Expression binding; .)
Ident<fname> assign
[pre (. flagIsPrefunct = true; .)]
function (. f = new Function(fname); f->isPrefunction = flagIsPrefunct; CodeScope* entry = f->getEntryScope(); .)
-['(' Ident<argName> tagcolon ExprAnnotations<binding> (. f->addBinding(Atom<Identifier_t>(argName), move(binding)); .)
-{',' Ident<argName> tagcolon ExprAnnotations<binding> (. f->addBinding(Atom <Identifier_t>(argName), move(binding));.)
-} ')']
+[lparen Ident<argName> tagcolon ExprAnnotations<binding> (. f->addBinding(Atom<Identifier_t>(argName), move(binding)); .)
+{comma Ident<argName> tagcolon ExprAnnotations<binding> (. f->addBinding(Atom <Identifier_t>(argName), move(binding));.)
+} rparen]
[ tagcolon
( IF(flagIsPrefunct) FnTag<f>
| Type<typOut>
)
{';' FnTag<f> }]
BDecl<entry> (. const_cast<Expression&>(entry->getBody()).bindType(move(typOut));.)
.
GuardSection<>= (. Expression guard; Function* f; .)
"guard" tagcolon MetaSimpExpr<guard>
lcurbrack { FDecl<f> (. f->guard = guard; root->add(f); .)
} rcurbrack.
/**
* TYPES
*
*/
TypeTerm<TypePrimitive& typ> = (. std::wstring tid; .)
("string" (. typ = TypePrimitive::String;.)
| "num" (. typ = TypePrimitive::Num;.)
| "int" (. typ = TypePrimitive::Int;.)
| "float" (. typ = TypePrimitive::Float;.)
| "bool" (. typ = TypePrimitive::Bool; .)
| "i8" (. typ = TypePrimitive::I8; .)
| "i32" (. typ = TypePrimitive::I32; .)
| "i64" (. typ = TypePrimitive::I64; .)
).
Type<TypeAnnotation& typ> = (. TypeAnnotation typ2; TypePrimitive typ3; std::wstring tid, field; .)
(
TList<typ>
| TStruct<typ>
| TVariant<typ>
+| TSlave<typ>
| TypeTerm<typ3> (. typ = typ3; .)
| IF (checkIndex()) Ident<tid> lbrack
Ident<field> (. typ = TypeAnnotation(TypeOperator::ACCESS, {}); typ.__valueCustom = Atom<Identifier_t>(tid).get(); typ.fields.push_back(Atom<Identifier_t>(field).get()); .)
- {',' Ident<field> (. typ.fields.push_back(Atom<Identifier_t>(field).get()); .)
+ {comma Ident<field> (. typ.fields.push_back(Atom<Identifier_t>(field).get()); .)
} rbrack
| Ident<tid> (. typ = TypeAnnotation(TypeOperator::CUSTOM, {}); typ.__valueCustom = Atom<Identifier_t>(tid).get(); .)
- ['(' Type<typ2> (. typ.__operator = TypeOperator::CALL; typ.__operands.push_back(typ2); .)
- {',' Type<typ2> (. typ.__operands.push_back(typ2); .)
- } ')']
+ [lparen Type<typ2> (. typ.__operator = TypeOperator::CALL; typ.__operands.push_back(typ2); .)
+ {comma Type<typ2> (. typ.__operands.push_back(typ2); .)
+ } rparen]
) .
TList<TypeAnnotation& typ> = (. TypeAnnotation ty; .)
- '[' Type<ty> ']' (. typ = TypeAnnotation(TypeOperator::LIST, {ty}); .)
+ lbrack Type<ty> rbrack (. typ = TypeAnnotation(TypeOperator::LIST, {ty}); .)
.
TStruct<TypeAnnotation& typ> = (. TypeAnnotation t; std::wstring key; size_t keyCounter=0; .)
lcurbrack
(
IF(checkTokenAfterIdent(_tagcolon)) Ident<key> tagcolon Type<t>
| Type<t> (. key = to_wstring(keyCounter++); .)
) (. typ = TypeAnnotation(TypeOperator::LIST_NAMED, {t}); typ.fields.push_back(Atom<Identifier_t>(key).get()); .)
- {',' (
+ {comma (
IF(checkTokenAfterIdent(_tagcolon)) Ident<key> tagcolon Type<t>
| Type<t> (. key = to_wstring(keyCounter++); .)
) (. typ.__operands.push_back(t); typ.fields.push_back(Atom<Identifier_t>(key).get()); .)
} rcurbrack.
TVariant<TypeAnnotation& typ>= (. TypeAnnotation t, typVoid(TypeOperator::LIST_NAMED, {}); std::vector<TypeAnnotation> operands; std::vector<Atom<Identifier_t>> keys; std::wstring variant; .)
"variant" lcurbrack
Ident<variant> (. t=typVoid; .)
[tagcolon Type<t>] (. keys.push_back(Atom<Identifier_t>(variant)); operands.push_back(t); .)
- {',' Ident<variant> (. t=typVoid; .)
+ {comma Ident<variant> (. t=typVoid; .)
[tagcolon Type<t>] (. keys.push_back(Atom<Identifier_t>(variant)); operands.push_back(t); .)
}
rcurbrack (. typ = TypeAnnotation(TypeOperator::VARIANT, {}); typ.__operands = operands; typ.addFields(std::move(keys)); .)
-.
+.
- TDecl = (. TypeAnnotation t; std::wstring tname, arg; std::vector<Atom<Identifier_t>> args; .)
- Ident<tname> assign "type"
- ['(' Ident<arg> (. args.push_back(Atom<Identifier_t>(arg)); .)
- {',' Ident<arg> (. args.push_back(Atom<Identifier_t>(arg)); .)
- } ')']
- Type<t>'.' (. t.addBindings(move(args)); root->add(move(t), Atom<Identifier_t>(tname)); .)
- .
+TSlave<TypeAnnotation& typ>= (. std::wstring identMaster; .)
+ "slave" Ident<identMaster> (. typ = TypeAnnotation(TypeOperator::SLAVE, {}); typ.__valueCustom = Atom<Identifier_t>(identMaster).get(); .)
+.
+
+TDecl = (. TypeAnnotation t; std::wstring tname, arg; std::vector<Atom<Identifier_t>> args; .)
+ Ident<tname> assign "type"
+ [lparen Ident<arg> (. args.push_back(Atom<Identifier_t>(arg)); .)
+ {comma Ident<arg> (. args.push_back(Atom<Identifier_t>(arg)); .)
+ } rparen]
+ Type<t>period (. t.addBindings(move(args)); root->add(move(t), Atom<Identifier_t>(tname)); .)
+ .
ContextDecl<CodeScope * scope> = (. Expression tag; .)
context tagcolon
MetaSimpExpr<tag> (. scope->tags.push_back(tag); .)
{';' MetaSimpExpr<tag> (. scope->tags.push_back(tag); .)
}.
VDecl<CodeScope* f> = (. std::wstring vname; Expression var, value;.)
VarIdent<var> assign ExprTyped<value> (. Symbol identSymbol = f->addDefinition(move(var), move(value));
Attachments::put<SymbolAlias>(value, identSymbol);
.)
.
BDecl<CodeScope* scope> = lcurbrack (. Expression body; pushContextScope(scope); .)
- {(IF(checkAssignment()) VDecl<scope> '.'
+ {(IF(checkAssignment()) VDecl<scope> period
| RuleContextDecl<scope>
- | ContextDecl<scope>'.'
+ | ContextDecl<scope>period
| ExprTyped<body> (. scope->setBody(body); Attachments::put<SymbolAlias>(body, Symbol{ScopedSymbol::RetSymbol, scope});.)
)}
rcurbrack (. popContextScope(); .)
.
IfDecl<Expression& e> = (. Expression cond; ManagedScpPtr blockTrue = root->add(new CodeScope(context.scope)); ManagedScpPtr blockFalse = root->add(new CodeScope(context.scope)); .)
-"if" '(' Expr<cond> ')' (. e = Expression(Operator::IF, {cond}); .)
+"if" lparen Expr<cond> rparen (. e = Expression(Operator::IF, {cond}); .)
tagcolon ExprAnnotations<e>
BDecl<&*blockTrue> "else" BDecl<&*blockFalse> (. e.addBlock(blockTrue); e.addBlock(blockFalse); .)
.
LoopDecl<Expression& e> =
(. Expression eIn, eAcc, eFilters; std::wstring varEl, varAcc, contextClass; Expression tagsEl;
ManagedScpPtr block = root->add(new CodeScope(context.scope)); .)
"loop"
- ("map" '(' Expr<eIn> implic Ident<varEl> (. e = Expression(Operator::MAP, {eIn}); .)
- tagcolon ExprAnnotations<tagsEl> ')' tagcolon ExprAnnotations<e>
+ ("map" lparen Expr<eIn> implic Ident<varEl> (. e = Expression(Operator::MAP, {eIn}); .)
+ tagcolon ExprAnnotations<tagsEl> rparen tagcolon ExprAnnotations<e>
(.
e.addBindings({Atom<Identifier_t>(varEl)});
block->addBinding(Atom<Identifier_t>(varEl), move(tagsEl));
.)
BDecl<&*block>
(. e.addBlock(block); .)
|"fold"
- ("inf" '(' Expr<eAcc> implic Ident<varAcc> ')'
+ ("inf" lparen Expr<eAcc> implic Ident<varAcc> rparen
(.
e = Expression(Operator::FOLD_INF, {eAcc});
e.addBindings({Atom<Identifier_t>(varAcc)});
block->addBinding(Atom<Identifier_t>(varAcc), Expression());
.)
tagcolon ExprAnnotations<e> BDecl<&*block>
(. e.addBlock(block); .)
- | '(' Expr<eIn> implic Ident<varEl> tagcolon ExprAnnotations<tagsEl> ['|' Expr<eFilters> ] ',' Expr<eAcc> implic Ident<varAcc>')'
+ | lparen Expr<eIn> implic Ident<varEl> tagcolon ExprAnnotations<tagsEl> ['|' Expr<eFilters> ] comma Expr<eAcc> implic Ident<varAcc>rparen
(.
e = Expression(Operator::FOLD, {eIn, eAcc});
e.addBindings({Atom<Identifier_t>(varEl), Atom<Identifier_t>(varAcc)});
.)
tagcolon ExprAnnotations<e>
(.
block->addBinding(Atom<Identifier_t>(varEl), move(tagsEl));
block->addBinding(Atom<Identifier_t>(varAcc), Expression());
.)
BDecl<&*block>
(. e.addBlock(block); .)
)
).
// Switches
SwitchDecl<Expression& eSwitch, SwitchKind flagSwitchKind> = (. TypeAnnotation typ; eSwitch = Expression(Operator::SWITCH, {}); Expression eCondition; Expression tag;.)
"switch"
(
SwitchVariantDecl<eSwitch>
| SwitchLate<eSwitch>
| lparen ExprTyped<eCondition> rparen tagcolon ExprAnnotations<eSwitch> (. eSwitch.operands.push_back(eCondition);.)
CaseDecl<eSwitch, flagSwitchKind> {CaseDecl<eSwitch, flagSwitchKind>}
)
.
CaseDecl<Expression& outer, SwitchKind flagSwitchKind> = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); Expression condition; .)
"case"
( IF(flagSwitchKind == SWITCH_META)
lparen MetaSimpExpr<condition> rparen BDecl<&*scope> (. Expression exprCase(Operator::CASE, {}); exprCase.addTags({condition}); exprCase.addBlock(scope); outer.addArg(move(exprCase));.)
| "default" BDecl<&*scope> (. Expression exprCase(Operator::CASE_DEFAULT, {});
exprCase.addBlock(scope);
outer.operands.insert(++outer.operands.begin(), exprCase); .)
| lparen CaseParams<&*scope> rparen (. ManagedScpPtr scopeBody = root->add(new CodeScope(&*scope)); Expression exprCase(Operator::CASE, {}); .)
BDecl<&*scopeBody> (. exprCase.addBlock(scope); exprCase.addBlock(scopeBody); outer.addArg(move(exprCase)); .)
).
CaseParams<CodeScope* scope> = (. Expression condition; Expression guard(Operator::LOGIC_AND, {}); pushContextScope(scope); .)
ExprTyped<condition> (. guard.addArg(Expression(condition)); .)
- {',' ExprTyped<condition> (. guard.addArg(Expression(condition)); .)
+ {comma ExprTyped<condition> (. guard.addArg(Expression(condition)); .)
} (. scope->setBody(guard); popContextScope(); .)
.
SwitchLate<Expression& expr> =
(.
- std::wstring aliasCondition; Expression exprCondition;
+ std::wstring aliasCondition; Expression exprCondition, aliasAnns;
expr = Expression(Operator::SWITCH_LATE, {});
ManagedScpPtr scope = root->add(new CodeScope(context.scope));
.)
- "late" lparen Expr<exprCondition> [implic Ident<aliasCondition>] [tagcolon ExprAnnotations<exprCondition>] rparen
+ "late" lparen Expr<exprCondition> [implic Ident<aliasCondition>] [tagcolon ExprAnnotations<aliasAnns>] rparen
tagcolon ExprAnnotations<expr> BDecl<&*scope>
(.
- expr.addArg(Expression(exprCondition));
+ expr.addArg(Expression(exprCondition));
+ expr.addBlock(scope);
+ std::string alias;
if(aliasCondition.empty()){
if(exprCondition.__state != Expression::IDENT){
SemErr(coco_string_create("An identifier expected in the short form"));
return;
}
- //Use exprCondition as id
- expr.addBindings({Atom<Identifier_t>(string(exprCondition.getValueString()))});
+ //Use exprCondition as identifier
+ alias = exprCondition.getValueString();
} else {
//Use aliasCondition
- expr.addBindings({Atom<Identifier_t>(aliasCondition)});
+ alias = Atom<String_t>(move(aliasCondition)).get();
}
+
+ expr.addBindings({Atom<Identifier_t>(string(alias))});
+ scope->addBinding(Atom<Identifier_t>(move(alias)), move(aliasAnns));
.)
.
SwitchVariantDecl<Expression& expr> =
(. Expression varTested; std::wstring varAlias; bool flagAliasFound = false; expr = Expression(Operator::SWITCH_VARIANT, {}); .)
"variant" lparen Expr<varTested> [implic Ident<varAlias>
(. flagAliasFound = true; .)
] [tagcolon ExprAnnotations<varTested>] rparen tagcolon ExprAnnotations<expr>
(. expr.addArg(std::move(varTested));
if (flagAliasFound) {
expr.addBindings({Atom<Identifier_t>(varAlias)});
} else {
if(varTested.__state == Expression::IDENT){
expr.addBindings({Atom<Identifier_t>(string(varTested.getValueString()))});
}
}
.)
CaseVariantDecl<expr> {CaseVariantDecl<expr>}
.
CaseVariantDecl<Expression& expr> = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); std::wstring key; scope->addBinding(Atom<Identifier_t>(string(expr.bindings.front())), Expression()); .)
"case" lparen Ident<key> rparen (. expr.addArg(root->recognizeVariantConstructor(Atom<Identifier_t>(std::move(key)))); .)
BDecl<&*scope> (. expr.addBlock(scope); .)
.
IntrinsicDecl<Expression& outer>= (. std::wstring name; .)
"intrinsic" Ident< name> (. outer = Expression(Operator::CALL_INTRINSIC, {}); outer.setValue(Atom<Identifier_t>(name)); .)
lparen [CalleeParams<outer>] rparen .
SequenceDecl<Expression& sequence> = (. sequence = Expression(); sequence.setOp(Operator::SEQUENCE); ManagedScpPtr scope = root->add(new CodeScope(context.scope)); .)
"seq" BDecl<&*scope> (. sequence.blocks.push_back(&*scope); scope = root->add(new CodeScope(&*scope)); .)
{ (. scope = root->add(new CodeScope(&*scope)); .)
BDecl<&*scope> (. sequence.blocks.push_back(&*scope); .)
}.
/*============================ INTERFACES ===============================*/
Imprt<> =
"import" "raw" lparen string (. root->__rawImports.push_back(Atom<String_t>(t->val).get()); .)
-rparen '.'.
+rparen period.
-InterfaceData<> = "interface" '('
- ( "dfa" ')' InterfaceDFA
- | "extern-c" ')' InterfaceExternC
- | "cfa" ')' InterfaceCFA
+InterfaceData<> = "interface" lparen
+ ( "dfa" rparen InterfaceDFA
+ | "extern-c" rparen InterfaceExternC
+ | "cfa" rparen InterfaceCFA
).
InterfaceExternC<> = (. ExternData data; .)
- '{' {IncludeExternDecl<data> | LibExternDecl<data> } '}'
+ lcurbrack {IncludeExternDecl<data> | LibExternDecl<data> } rcurbrack
(. root->addExternData(move(data)); .)
.
LibExternDecl<ExternData& data> = (. std::wstring pkgname, libname; .)
Ident<libname> assign "library" tagcolon "pkgconfig"
- '(' string (. pkgname = t->val; .)
- ')' '.' (. data.addLibrary(Atom<Identifier_t>(libname), Atom<String_t>(pkgname)); .)
+ lparen string (. pkgname = t->val; .)
+ rparen period (. data.addLibrary(Atom<Identifier_t>(libname), Atom<String_t>(pkgname)); .)
.
IncludeExternDecl<ExternData& data> = (. Expression inc; .)
- "include" StructLiteral<inc> '.' (. data.addIncludeDecl(move(inc)); .)
+ "include" StructLiteral<inc> period (. data.addIncludeDecl(move(inc)); .)
.
-InterfaceDFA<> = '{' { InstructDecl } '}' .
+InterfaceDFA<> = lcurbrack { InstructDecl } rcurbrack .
InstructDecl = (.Operator op; Expression tag;
Expression scheme;
std::vector<Expression>& tags = scheme.operands;
tags.push_back(Expression()); /* return value */ .)
-"operator" InstructAlias<op> tagcolon '(' (.scheme.setOp(op); .)
+"operator" InstructAlias<op> tagcolon lparen (.scheme.setOp(op); .)
[
MetaSimpExpr<tag> (. tags.push_back(tag); .)
{
- ',' MetaSimpExpr<tag> (. tags.push_back(tag); .)
+ comma MetaSimpExpr<tag> (. tags.push_back(tag); .)
}
-] ')' [ implic MetaSimpExpr<tag> (. tags[0] = tag; .)
+] rparen [ implic MetaSimpExpr<tag> (. tags[0] = tag; .)
] (. root->addDFAData(move(scheme)); .)
-'.'.
+period.
InstructAlias<Operator& op> =
(
"map" (. op = Operator::MAP; .)
| "list_range" (. op = Operator::LIST_RANGE; .)
| "list" (. op = Operator::LIST; .)
| "fold" (. op = Operator::FOLD; .)
| "index" (. op = Operator::INDEX; .)
).
-InterfaceCFA<> = '{' { InstructCFADecl } '}' .
+InterfaceCFA<> = lcurbrack { InstructCFADecl } rcurbrack .
InstructCFADecl<> = (.Operator op; Expression tag;
Expression scheme;
std::vector<Expression>& tags = scheme.operands; .)
"operator" InstructAlias<op> tagcolon (. scheme.setOp(op); .)
[
MetaSimpExpr<tag> (. tags.push_back(tag); .)
{
- ',' MetaSimpExpr<tag> (. tags.push_back(tag); .)
+ comma MetaSimpExpr<tag> (. tags.push_back(tag); .)
}
-] '.' (. root->addInterfaceData(CFA, move(scheme)); .).
+] period (. root->addInterfaceData(CFA, move(scheme)); .).
/*============================ METAPROGRAMMING ===============================*/
// TagsDecl<CodeScope* f> = (. Expression tag; TagModifier mod = TagModifier::NONE; .)
// ':' { MetaSimpExpr<tag> (. /*f.addTag(std::move(tag), mod); */ .)
// }.
FnTag<Function* f> = (. Expression tag; TagModifier mod = TagModifier::NONE; .)
MetaSimpExpr<tag>
['-' TagMod<mod>] (. f->addTag(std::move(tag), mod); .).
TagMod<TagModifier& mod> =
( "assert" (. mod = TagModifier::ASSERT; .)
| "require" (. mod = TagModifier::REQUIRE; .)
).
RuleDecl<> =
"rule" tagcolon (. RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg; .)
-'(' Ident<arg> tagcolon Domain<typ> (. args.add(arg, typ); .)
-{',' Ident<arg> tagcolon Domain<typ> (. args.add(arg, typ); .)
-} ')'
-["case" RGuard<guards> {',' RGuard<guards>}]
-'{' RBody<args, guards> '}' .
+lparen Ident<arg> tagcolon Domain<typ> (. args.add(arg, typ); .)
+{comma Ident<arg> tagcolon Domain<typ> (. args.add(arg, typ); .)
+} rparen
+["case" RGuard<guards> {comma RGuard<guards>}]
+lcurbrack RBody<args, guards> rcurbrack .
/* - TODO use RGuard for guards-*/
RuleContextDecl<CodeScope* scope> = (.Expression eHead, eGuards, eBody; .)
"rule" "context" tagcolon MetaSimpExpr<eHead>
"case" lparen MetaSimpExpr<eGuards> rparen
-'{' MetaSimpExpr<eBody> '}' (.scope->contextRules.push_back(Expression(Operator::CONTEXT_RULE, {eHead, eGuards, eBody})); .).
+lcurbrack MetaSimpExpr<eBody> rcurbrack (.scope->contextRules.push_back(Expression(Operator::CONTEXT_RULE, {eHead, eGuards, eBody})); .).
Domain<DomainAnnotation& dom> =
(
"function" (. dom = DomainAnnotation::FUNCTION; .)
| "variable" (. dom = DomainAnnotation::VARIABLE; .)
).
RGuard<RuleGuards& guards>= (. Expression e; .)
MetaExpr<e> (. guards.add(std::move(e)); .).
MetaExpr<Expression& e>= (.Operator op; Expression e2; .)
MetaExpr2<e>
[MetaOp<op> MetaExpr2<e2> (. e = Expression(op, {e, e2}); .)
].
MetaExpr2<Expression& e>=
(
-'(' MetaExpr<e> ')'
+lparen MetaExpr<e> rparen
| MetaSimpExpr<e>
).
MetaSimpExpr<Expression& e>= (. std::wstring i1, infix; Expression e2; .)
( '-' MetaSimpExpr<e2> (. e = Expression(Operator::NEG, {e2}); .)
| IF(checkParametersList()) Ident<i1> (. e = Expression(Operator::CALL, {Expression(Atom<Identifier_t>(i1))}); .)
-'(' [ MetaCalleeParams<e> ] ')'
+lparen [ MetaCalleeParams<e> ] rparen
| IF(checkInfix()) Ident<i1> Ident<infix> MetaSimpExpr<e2>
(. e = Expression(Operator::CALL, {Expression(Atom<Identifier_t>(infix))});
e.addArg(Expression(Atom<Identifier_t>(i1)));
e.addArg(std::move(e2));
.)
| Ident<i1> (. e = Expression(Operator::CALL, {Atom<Identifier_t>(i1)}); .)
).
MetaCalleeParams<Expression& e> = (. Expression e2; .)
MetaSimpExpr<e2> (. e.addArg(Expression(e2)); .)
- {',' MetaSimpExpr<e2> (. e.addArg(Expression(e2)); .)
+ {comma MetaSimpExpr<e2> (. e.addArg(Expression(e2)); .)
}.
RBody<const RuleArguments& args, const RuleGuards& guards> =
(. Expression e; std::wstring msg; .)
"warning" MetaExpr<e> ["message" string (. msg = t->val; .)
] (. root->add(new RuleWarning(RuleArguments(args), RuleGuards(guards), std::move(e), Atom<String_t>(msg))); .)
.
MetaOp< Operator& op> =
implic (. op = Operator::IMPL; .)
.
/*============================ Expressions ===============================*/
ExprAnnotations<Expression& e> = (. TypeAnnotation typ; std::list<Expression> tags; Expression tag; e.tags.clear();.)
Type<typ> (. e.bindType(move(typ)); .)
{';' MetaSimpExpr<tag> (. tags.push_back(tag); .)
} (. e.addTags(tags); .)
.
ExprTyped<Expression&e> = Expr<e> [tagcolon ExprAnnotations<e>].
Expr< Expression& e> (. Operator op; Expression e2; .)
= ExprArithmAdd<e>
[ RelOp<op>
ExprArithmAdd<e2> (. e = Expression(op, {e, e2}); .)
].
ExprArithmAdd< Expression& e>= (. Operator op; Expression e2; .)
ExprArithmMul< e>
[ AddOp< op>
ExprArithmAdd< e2> (. e = Expression(op, {e, e2});.)
].
ExprArithmMul< Expression& e> (. Operator op; Expression e2; .)
= ExprPostfix< e>
[ MulOp< op>
ExprArithmMul< e2> (. e = Expression(op, {e, e2}); .)
].
ExprPostfix<Expression& e>
= Term<e>
[ (. e = Expression(Operator::INDEX, {e}); .)
{lbrack CalleeParams<e> rbrack }
].
Term< Expression& e> (. std::wstring name; e = Expression(); .)
=
(IF (checkParametersList()) Ident< name>
(. e = Expression(Operator::CALL, {Atom<Identifier_t>(name)}); root->recognizeVariantConstructor(e); .)
- '(' [CalleeParams<e>] ')'
+ lparen [CalleeParams<e>] rparen
| VarIdent<e> (. recognizeIdentifier(e); .)
| ListLiteral<e> (. /* tuple */.)
| StructLiteral<e> (. /* struct */.)
| LoopDecl<e>
| IfDecl<e>
| SwitchDecl<e, SWITCH_NORMAL>
| IntrinsicDecl<e>
| SequenceDecl<e>
| number (. e = Expression(Atom<Number_t>(t->val)); .)
| string (. e = Expression(Atom<String_t>(t->val)); .)
| "true" (. e = Expression(Atom<Number_t>(1)); e.bindType(TypePrimitive::Bool); .)
| "false" (. e = Expression(Atom<Number_t>(0)); e.bindType(TypePrimitive::Bool); .)
| "undef" (. e = Expression(Operator::UNDEF, {}); .)
| '-' Term<e> (. e = Expression(Operator::NEG, {e}); .)
- | '(' ExprTyped<e> ')'
+ | lparen ExprTyped<e> rparen
).
StructLiteral<Expression& e> = (. std::wstring key; Expression val; std::list<Atom<Identifier_t>> keys; size_t keyCounter=0; .)
lcurbrack
- (IF(checkTokenAfterIdent(_assign)) Ident<key> '=' Expr<val>
+ (IF(checkTokenAfterIdent(_assign)) Ident<key> assign Expr<val>
| Expr<val> (. key = to_wstring(keyCounter++); .)
) (. keys.push_back(Atom<Identifier_t>(key)); e = Expression(Operator::LIST_NAMED, {val}); .)
- {',' (IF(checkTokenAfterIdent(_assign)) Ident<key> '=' Expr<val>
+ {comma (IF(checkTokenAfterIdent(_assign)) Ident<key> assign Expr<val>
| Expr<val> (. key = to_wstring(keyCounter++); .)
) (. e.addArg(Expression(val)); keys.push_back(Atom<Identifier_t>(key)); .)
} rcurbrack (. e.addBindings(keys.begin(), keys.end()); .)
.
ListLiteral<Expression& e> = (. Expression eFrom, eTo; .)
-'[' (. e.setOp(Operator::LIST); .)
+lbrack (. e.setOp(Operator::LIST); .)
[ Expr<eFrom> (. e.addArg(Expression(eFrom)); .)
( ".." Expr<eTo> (. e.addArg(Expression(eTo)); e.setOp(Operator::LIST_RANGE); .)
- |{',' Expr<eFrom> (. e.addArg(Expression(eFrom)); .)
+ |{comma Expr<eFrom> (. e.addArg(Expression(eFrom)); .)
}
)
]
-']'.
+rbrack.
CalleeParams<Expression& e> = (. Expression e2; .)
ExprTyped<e2> (. e.addArg(Expression(e2)); .)
- {',' ExprTyped<e2> (. e.addArg(Expression(e2)); .)
+ {comma ExprTyped<e2> (. e.addArg(Expression(e2)); .)
}.
AddOp< Operator& op>
= (. op = Operator::ADD; .)
( '+'
| '-' (. op = Operator::SUB; .)
).
MulOp< Operator& op>
= (. op = Operator::MUL; .)
( '*'
| '/' (. op = Operator::DIV; .)
).
RelOp< Operator& op>
= (. op = Operator::EQU; .)
( equal
| (ne1 | ne2) (. op = Operator::NE; .)
| lse (. op = Operator::LSE; .)
| lss (. op = Operator::LSS; .)
| gte (. op = Operator::GTE; .)
| gtr (. op = Operator::GTR; .)
).
-SkipModulesSection = "module" '{' {ANY} '}'.
+SkipModulesSection = "module" lcurbrack {ANY} rcurbrack.
END Xreate.

Event Timeline