No OneTemporary

File Metadata

Created
Sun, Feb 15, 11:42 PM
diff --git a/config/default.json b/config/default.json
index d5965dd..4f05447 100644
--- a/config/default.json
+++ b/config/default.json
@@ -1,73 +1,74 @@
{
"containers": {
"id": {
"implementations": "impl_fulfill_cluster",
"clusters": "var_cluster",
"prototypes": "proto_cluster",
"linkedlist": "linkedlist"
},
"impl": {
"solid": "solid",
"onthefly": "on_the_fly"
}
},
"logging": {
"id": "logging"
},
"function-entry": "entry",
"clasp": {
"bindings" : {
"variable": "bind",
"function": "bind_func",
"scope": "bind_scope",
"function_demand" : "bind_function_demand",
"scope_decision": "bind_scope_decision"
},
"context" : {
"decisions":{
"dependent": "resolution_dependency"
}
},
"nonevalue": "nonevalue",
"ret": {
"symbol": "retv",
"tag": "ret"
}
},
"tests": {
- "template": "default",
+ "template": "virtualization",
"templates": {
"current-fix":"*",
- "default": "*-Adhoc.*:Containers.*:Compilation.full_IFStatementWithVariantType:Types.full_VariantType_Switch1:Context.full_LateContext:Context.pathDependentContext",
+ "default": "*-Adhoc.*:Containers.*:Compilation.full_IFStatementWithVariantType:Types.full_VariantType_Switch1:Context.full_LateContext:Context.pathDependentContext:Virtualization.test1",
"ast": "AST.*",
"adhocs": "Adhoc.*",
"effects": "Effects.*",
"basic": "Attachments.*",
"context": "Context.*",
"compilation": "Compilation.*-Compilation.full_IFStatementWithVariantType",
"communication": "Communication.*",
"cfa": "CFA.*",
"containers": "Containers.*",
"dfa": "DFA.*",
"diagnostic": "Diagnostic.*",
- "dsl": "Association.*:Interpretation.SwitchVariantAlias",
+ "dsl": "Association.*:Interpretation.*",
"exploitation": "Exploitation.*",
"ExpressionSerializer": "ExpressionSerializer.*",
"externc": "InterfaceExternC.*",
"loops": "Loop.*",
"modules": "Modules.*",
"polymorphs": "Polymorphs.call1",
- "types": "Types.*",
+ "types": "Types.*",
+ "virtualization": "Virtualization.test2",
"vendorsAPI/clang": "ClangAPI.*",
"vendorsAPI/xml2": "libxml2*"
}
}
}
diff --git a/core/control-context.lp b/core/control-context.lp
deleted file mode 120000
index f0191b9..0000000
--- a/core/control-context.lp
+++ /dev/null
@@ -1 +0,0 @@
-/private/prg/code/xreate/core/control-context-v3.lp
\ No newline at end of file
diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt
index 0f5feae..d1084db 100644
--- a/cpp/CMakeLists.txt
+++ b/cpp/CMakeLists.txt
@@ -1,35 +1,34 @@
project(Xreate)
cmake_minimum_required(VERSION 2.8.11)
-set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -Wall -fprofile-arcs -ftest-coverage -O0")
+set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -fprofile-arcs -ftest-coverage -O0")
set(CMAKE_BUILD_TYPE Debug)
-
# BUILD OPTIONS
#======================
set(XREATE_DEFINITIONS
-D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DWITH_THREADS=1
)
add_definitions(${XREATE_DEFINITIONS})
add_compile_options(-Winvalid-pch -fPIC -std=c++14)
# XREATE
#======================
add_subdirectory(src)
# XREATE-TESTS
#======================
if (BUILD_XREATE_TESTS)
message ("Building xreate tests")
add_subdirectory(tests)
endif ()
# XREATE-SERVER
#======================
if (BUILD_XREATE_SERVER)
message ("Building xreate server")
add_subdirectory(../tools/execution-server execution-server)
endif ()
diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt
index 6c98f92..22def64 100644
--- a/cpp/src/CMakeLists.txt
+++ b/cpp/src/CMakeLists.txt
@@ -1,230 +1,229 @@
cmake_minimum_required(VERSION 2.8.11)
project(xreate)
cmake_policy(SET CMP0022 NEW)
message("MODULES" ${CMAKE_MODULE_PATH})
# LLVM
#======================
FIND_PACKAGE (LLVM REQUIRED)
set(LLVM_VERSION ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR})
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message("LLVM LIB PATH:" ${LLVM_LIBRARY_DIRS})
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
INCLUDE_DIRECTORIES(${LLVM_INCLUDE_DIRS})
message(STATUS "INCLUDE DIR: ${LLVM_INCLUDE_DIRS}")
add_definitions(${LLVM_DEFINITIONS})
message("LLVM DEFS: " ${LLVM_DEFINITIONS})
llvm_map_components_to_libnames(LLVM_LIBS core nativecodegen native executionengine mcjit support option)
message("LLVM LIBS: " ${LLVM_LIBS})
# CLANG
#======================
set(CLANG_LIBS
clangCodeGen
clangASTMatchers
clangQuery
clangTooling
clangFrontend
clangSerialization
clangDriver
clangParse
clangSema
clangAnalysis
clangAST
clangEdit
clangLex
clangBasic
)
# POTASSCO
#======================
set(POTASSCO_PATH "/opt/potassco/clingo" CACHE PATH "Path to potassco sources")
set(POTASSCO_INCLUDE_PATH
${POTASSCO_PATH}/libgringo
${POTASSCO_PATH}/libclasp
${POTASSCO_PATH}/libclingo
${POTASSCO_PATH}/libprogram_opts
${POTASSCO_PATH}/liblp
)
INCLUDE_DIRECTORIES(${POTASSCO_INCLUDE_PATH})
set(LIBCLASP_LIBS
clingo
clasp
gringo
program_opts
reify
lp
)
message("CLASP LIBS: " ${LIBCLASP_LIBS})
# OTHER DEPENDENCIES
#===========================
set(JEAYESON_INCLUDE_PATH
${CMAKE_HOME_DIRECTORY}/../vendors/jeayeson/include/
)
INCLUDE_DIRECTORIES(${JEAYESON_INCLUDE_PATH})
# COCO
#===========================
set(COCO_EXECUTABLE "" CACHE PATH "Path to coco executable")
set(COCO_FRAMES_PATH "" CACHE PATH "Path to coco frames")
set(COCO_GRAMMAR_PATH ${CMAKE_HOME_DIRECTORY}/../grammar/)
set(COCO_SOURCE_FILES_MAIN
${COCO_GRAMMAR_PATH}/main/Parser.cpp
${COCO_GRAMMAR_PATH}/main/Scanner.cpp
)
set(COCO_SOURCE_FILES_MODULES
${COCO_GRAMMAR_PATH}/modules/Parser.cpp
${COCO_GRAMMAR_PATH}/modules/Scanner.cpp
)
set(COCO_SOURCE_FILES ${COCO_SOURCE_FILES_MODULES} ${COCO_SOURCE_FILES_MAIN})
INCLUDE_DIRECTORIES(${COCO_GRAMMAR_PATH})
add_custom_command(OUTPUT ${COCO_SOURCE_FILES_MAIN}
COMMAND ${COCO_GRAMMAR_PATH}/gen-grammar main ${COCO_EXECUTABLE} ${COCO_FRAMES_PATH}
WORKING_DIRECTORY ${COCO_GRAMMAR_PATH}
MAIN_DEPENDENCY ${COCO_GRAMMAR_PATH}/xreate.ATG
)
add_custom_command(OUTPUT ${COCO_SOURCE_FILES_MODULES}
COMMAND ${COCO_GRAMMAR_PATH}/gen-grammar modules ${COCO_EXECUTABLE} ${COCO_FRAMES_PATH}
WORKING_DIRECTORY ${COCO_GRAMMAR_PATH}
MAIN_DEPENDENCY ${COCO_GRAMMAR_PATH}/modules.ATG
)
message(STATUS "COCO GRAMMAR BUILD STATUS:" ${COCO_OUTPUT})
# XREATE
#======================
set(SOURCE_FILES
query/polymorph.cpp
analysis/dfagraph.cpp
pass/dfapass.cpp
compilation/targetinterpretation.cpp
pass/interpretationpass.cpp
ast.cpp
xreatemanager.cpp
analysis/typeinference.cpp
aux/xreatemanager-decorators.cpp
compilation/operators.cpp
compilation/transformations.cpp
compilation/transformersaturation.cpp
pass/compilepass.cpp
pass/versionspass.cpp
attachments.cpp
ExternLayer.cpp
analysis/cfagraph.cpp
analysis/aux.cpp
compilation/containers.cpp
compilation/advancedinstructions.cpp
clasplayer.cpp
- compilation/latecontextcompiler2.cpp
query/context.cpp
llvmlayer.cpp
utils.cpp
pass/abstractpass.cpp
pass/cfapass.cpp
pass/adhocpass.cpp
contextrule.cpp
query/containers.cpp
analysis/DominatorsTreeAnalysisProvider.cpp
aux/serialization/expressionserializer.cpp
modules.cpp
)
set(XREATE_INCLUDE_DIRS
${CMAKE_CURRENT_SOURCE_DIR}/
)
INCLUDE_DIRECTORIES(${XREATE_INCLUDE_DIRS})
set(XREATE_PRIVATE_INCLUDE_DIRS
${XREATE_INCLUDE_DIRS}
${COCO_GRAMMAR_PATH}
${JEAYESON_INCLUDE_PATH}
${LLVM_INCLUDE_DIRS}
${POTASSCO_INCLUDE_PATH}
)
add_library(${PROJECT_NAME} SHARED ${COCO_SOURCE_FILES} ${SOURCE_FILES})
target_link_libraries(${PROJECT_NAME})
target_include_directories(${PROJECT_NAME} INTERFACE
${XREATE_INCLUDE_DIRS}
${COCO_GRAMMAR_PATH}
${JEAYESON_INCLUDE_PATH}
${LLVM_INCLUDE_DIRS}
${POTASSCO_INCLUDE_PATH}
)
get_directory_property(DEFINITIONS_ALL DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_DEFINITIONS)
message("definitions all: " ${DEFINITIONS_ALL})
target_compile_definitions(${PROJECT_NAME} INTERFACE ${DEFINITIONS_ALL})
get_directory_property(COMPILATION_OPTIONS_ALL DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_OPTIONS)
message("compilations all: " ${COMPILATION_OPTIONS_ALL})
target_compile_options(${PROJECT_NAME} INTERFACE ${COMPILATION_OPTIONS_ALL})
SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY
INTERFACE_LINK_LIBRARIES ${LIBCLASP_LIBS} ${CLANG_LIBS} ${LLVM_LIBS} tbb boost_system boost_filesystem
)
#${CLANG_LIBS}
#set (LINK_INTERFACE_LIBRARIES "")
# FUNCTION(PREPEND var prefix)
# SET(listVar "")
# FOREACH(f ${ARGN})
# LIST(APPEND listVar "${prefix}/${f}")
# ENDFOREACH(f)
# SET(${var} "${listVar}" PARENT_SCOPE)
# ENDFUNCTION(PREPEND)
#set(COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "-j4")
#cotire(xreate)
# MACRO (ADD_PCH_RULE _header_filename _src_list)
# SET(_gch_filename "${_header_filename}.gch")
# LIST(APPEND ${_src_list} ${_gch_filename})
# SET (_args ${CMAKE_CXX_FLAGS})
# LIST(APPEND _args -c ${_header_filename} -o ${_gch_filename})
# GET_DIRECTORY_PROPERTY(DIRINC INCLUDE_DIRECTORIES)
# foreach (_inc ${DIRINC})
# LIST(APPEND _args "-I" ${_inc})
# endforeach(_inc ${DIRINC})
# SEPARATE_ARGUMENTS(_args)
# add_custom_command(OUTPUT ${_gch_filename}
# COMMAND rm -f ${_gch_filename}
# COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1} ${_args}
# DEPENDS ${_header_filename})
# ENDMACRO(ADD_PCH_RULE _header_filename _src_list)
# ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/ast.h SOURCE_FILES)
# ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/llvmlayer.h SOURCE_FILES)
# ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/clasplayer.h SOURCE_FILES)
# ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/pass/abstractpass.h SOURCE_FILES)
diff --git a/cpp/src/analysis/cfagraph.cpp b/cpp/src/analysis/cfagraph.cpp
index 3ca5e39..f4b8292 100644
--- a/cpp/src/analysis/cfagraph.cpp
+++ b/cpp/src/analysis/cfagraph.cpp
@@ -1,204 +1,204 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: CFAGraph.cpp
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on June 27, 2016, 2:09 PM
*/
/**
* \file cfagraph.h
* \brief Control Flow Analysis(CFA) graph data
*
*/
#include "analysis/cfagraph.h"
#include "analysis/aux.h"
using namespace xreate::cfa;
using namespace std;
void
CFAGraph::print(std::ostringstream& output) const {
const std::string& atomBinding = Config::get("clasp.bindings.function");
const std::string& atomBindingScope = Config::get("clasp.bindings.scope");
//show function tags
int counterTags = 0;
std::ostringstream bufFunctionNames;
boost::format formatFunction("function(%1%).");
boost::format formatBind(atomBinding + "(%1%, %2%).");
for (auto function: this->__nodesFunction.left) {
const auto tags = this->__functionTags.equal_range(function.first);
if (tags.first == tags.second) {
//no tags
bufFunctionNames << "; " << function.second ;
continue;
}
output << formatFunction % (function.second) << std::endl;
for (const auto& tag_: boost::make_iterator_range(tags)){
const Expression& tag = tag_.second;
list<string> tagRaw = xreate::analysis::compile(tag);
assert(tagRaw.size() == 1);
output << formatBind
% (function.second)
% (tagRaw.front())
<< endl;
++counterTags;
}
}
if (bufFunctionNames.tellp()){
output << formatFunction % (bufFunctionNames.str().substr(2)) << std::endl;
}
if (counterTags == 0) {
output << "%no functtion tags at all" << endl;
}
//declare scopes
boost::format formatScope("scope(0..%1%).");
output << formatScope % (__clasp->getScopesCount() - 1) << std::endl;
//show context rules:
for (auto rule: this->__contextRules) {
output << ContextRule(rule.second).compile(rule.first) << std::endl;
};
//show scope tags:
counterTags = 0;
boost::format formatScopeBind(atomBindingScope + "(%1%, %2%, strong).");
for (auto entry: this->__scopeTags) {
ScopePacked scopeId = entry.first;
const Expression& tag = entry.second;
list<string> tagRaw = xreate::analysis::compile(tag);
assert(tagRaw.size() == 1);
output << formatScopeBind % scopeId %(tagRaw.front()) << endl;
++counterTags;
}
if (counterTags == 0) {
output << "%scope tags: no tags at all" << endl;
}
output << endl << "%\t\tStatic analysis: CFA" << endl;
//parent connections
//TOTEST CFG parent function
boost::format formatFunctionParent("cfa_parent(%1%, function(%2%)).");
for (const auto &relation: this->__parentFunctionRelations) {
const string& function = this->__nodesFunction.left.at(relation.right);
output << formatFunctionParent % relation.left % function << endl;
}
//TOTEST CFG parent scope
boost::format formatScopeParent("cfa_parent(%1%, scope(%2%)).");
for (const auto &relation: this->__parentScopeRelations) {
output << formatScopeParent % relation.first % relation.second << endl;
}
//call connections
boost::format formatCall("cfa_call(%1%, %2%).");
for (const auto &relation: this->__callRelations) {
const ScopePacked scopeFrom = relation.left;
const string& functionTo = this->__nodesFunction.left.at(relation.right);
output << formatCall % (scopeFrom) % (functionTo) << endl;
}
//function specializations descrtiption
//SECTIONTAG late-context cfa_function_specializations
boost::format formatSpecializations("cfa_function_specializations(%1%, %2%).");
const list<ManagedFnPtr>& functions = __clasp->ast->getAllFunctions();
for (auto f: functions){
- if (f->guardContext.isValid()){
- list<string> guardRaw = xreate::analysis::compile(f->guardContext);
+ if (f->guard.isValid()){
+ list<string> guardRaw = xreate::analysis::compile(f->guard);
assert(guardRaw.size() == 1);
output << formatSpecializations % (f->getName()) % (guardRaw.front()) << endl;
}
}
//Dependencies
boost::format formatDependencies("cfa_scope_depends(%1%, %2%).");
for(const auto relation: __dependencyRelations){
output << formatDependencies % relation.first % relation.second << endl;
}
std::multimap<ScopePacked, ScopePacked> __dependencyRelations;
}
void
CFAGraph::addFunctionAnnotations(const std::string& function, const std::map<std::string, Expression>& tags) {
unsigned int fid = registerNodeFunction(function);
for (auto& tag: tags){
__functionTags.emplace(fid, tag.second);
}
}
void
CFAGraph::addScopeAnnotations(const ScopePacked& scope, const std::vector<Expression>& tags){
for (Expression tag: tags){
__scopeTags.emplace(scope, tag);
}
}
void
CFAGraph::addContextRules(const ScopePacked& scope, const std::vector<Expression>& rules){
for (Expression rule: rules){
__contextRules.emplace(scope, rule);
}
}
void
CFAGraph::addCallConnection(const ScopePacked& scopeFrom, const std::string& functionTo) {
unsigned int idFuncTo = registerNodeFunction(functionTo);
__callRelations.insert(CALL_RELATIONS::value_type(scopeFrom, idFuncTo));
}
void
CFAGraph::addParentConnection(const ScopePacked& scope, const std::string& functionParent){
__parentFunctionRelations.insert(PARENT_FUNCTION_RELATIONS::value_type(scope, registerNodeFunction(functionParent)));
}
void
CFAGraph::addParentConnection(const ScopePacked& scope, const ScopePacked& scopeParent){
__parentScopeRelations.emplace(scope, scopeParent);
}
unsigned int
CFAGraph::registerNodeFunction(const std::string& fname){
auto pos = __nodesFunction.left.insert(make_pair(__nodesFunction.size(), fname));
return pos.first->first;
}
void
CFAGraph::addDependency(const ScopePacked& scope, const ScopePacked& scopeDependency){
__dependencyRelations.emplace(scope, scopeDependency);
}
bool CFAGraph::isDependent(const ScopePacked& scope) const{
return __dependencyRelations.count(scope) > 0;
}
void CFAGraph::transmitDependencies(const ScopePacked& scopeTo, const ScopePacked& scopeFrom){
auto range = __dependencyRelations.equal_range(scopeFrom);
std::list<ScopePacked> dependencies;
for (auto pairI = range.first; pairI != range.second; ++pairI){
dependencies.push_back(pairI->second);
}
for(auto dep: dependencies){
__dependencyRelations.emplace(scopeTo, dep);
}
}
diff --git a/cpp/src/ast.h b/cpp/src/ast.h
index cdb0515..57a4c2a 100644
--- a/cpp/src/ast.h
+++ b/cpp/src/ast.h
@@ -1,734 +1,733 @@
/* 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
};
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, LOOP_CONTEXT,
INDEX, IF, SWITCH, SWITCH_ADHOC, SWITCH_VARIANT,
CASE, CASE_DEFAULT, LOGIC_AND,
ADHOC, 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 ClaspLayer;
friend class CFAPass;
friend class ExpressionHints;
Expression(const Operator &oprt, std::initializer_list<Expression> params);
Expression(const Atom<Identifier_t>& ident);
Expression(const Atom<Number_t>& number);
Expression(const Atom<String_t>& a);
Expression();
void setOp(Operator oprt);
void addArg(Expression&& arg);
void addBindings(std::initializer_list<Atom<Identifier_t>> params);
void bindType(TypeAnnotation t);
template<class InputIt>
void addBindings(InputIt paramsBegin, InputIt paramsEnd);
void addTags(const std::list<Expression> tags) const;
void addBlock(ManagedScpPtr scope);
const std::vector<Expression>& getOperands() const;
double getValueDouble() const;
void setValueDouble(double value);
const std::string& getValueString() const;
void setValue(const Atom<Identifier_t>&& v);
bool isValid() const;
bool isDefined() const;
bool operator==(const Expression& other) const;
/**
* \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 ClaspLayer;
class LLVMLayer;
class MetaRuleAbstract {
public:
MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards);
virtual ~MetaRuleAbstract();
virtual void compile(ClaspLayer& layer) = 0;
protected:
RuleArguments __args;
RuleGuards __guards;
};
class RuleWarning : public MetaRuleAbstract {
friend class ClaspLayer;
public:
RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom<String_t>&& message);
virtual void compile(ClaspLayer& layer);
~RuleWarning();
private:
std::string __message;
Expression __condition;
};
typedef unsigned int VNameId;
namespace versions {
typedef int VariableVersion;
const VariableVersion VERSION_NONE = -2;
const VariableVersion VERSION_INIT = 0;
}
template<>
struct AttachmentsDict<versions::VariableVersion> {
typedef versions::VariableVersion Data;
static const unsigned int key = 6;
};
struct ScopedSymbol {
VNameId id;
versions::VariableVersion version;
static const ScopedSymbol RetSymbol;
};
struct Symbol {
ScopedSymbol identifier;
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 guardContext;
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<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/compilation/latecontextcompiler2.cpp b/cpp/src/compilation/latecontextcompiler2.cpp
deleted file mode 100644
index 6715761..0000000
--- a/cpp/src/compilation/latecontextcompiler2.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- *
- * LateContextCompiler2.cpp
- *
- * Created on: 02/10, 2016
- * Author: pgess <v.melnychenko@xreate.org>
- *
- * \file latecontextcompiler2.h
- * \brief Late context compilation. See more on [Late Context](/w/concepts/context#late-context)
- */
-
-//TOTEST default variants - do not enable specialization context in order to check default variant invocation
-
-#include "latecontextcompiler2.h"
-#include "llvmlayer.h"
-#include "pass/compilepass.h"
-#include "query/context.h"
-#include <iostream>
-
-using namespace std;
-
-namespace xreate {namespace context{
-
-const string topicSpecializationAtom = "specialization";
-const string topicDependencyAtom = "dependency";
-
-typedef ExpressionSerialization<RequirementIntegralCode>::Code DomainId;
-typedef ExpressionSerialization<RequirementIntegralCode>::Serializer Domain;
-
-//TODO implement variantDefault;
-llvm::Value* compileDecisionSelector(llvm::IRBuilder<>& builder, llvm::Value* selector, std::vector<llvm::Value*> vectorVariants, llvm::Value* variantDefault=nullptr){
- assert(vectorVariants.size()>0);
- llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext());
-
- llvm::Type* tyElement = vectorVariants[0]->getType();
- llvm::Type* tyVariants = llvm::VectorType::get(tyElement, vectorVariants.size());
- llvm::Value* vectorRaw = llvm::ConstantVector::getNullValue(tyVariants);
-
-
- for(DomainId i=0; i<vectorVariants.size(); ++i){
- vectorRaw = builder.CreateInsertElement(vectorRaw, vectorVariants[i], llvm::ConstantInt::get(ty32, i));
- }
-
- return builder.CreateExtractElement(vectorRaw, selector);
-}
-
-LateContextCompiler2::LateContextCompiler2(compilation::IFunctionUnit* f, CompilePass* p)
- : function(f), pass(p){
-
- ContextQuery* context = pass->queryContext;
- __sizeOfDemand = context->getFunctionDemand(function->function->getName()).size();
-}
-
-llvm::Value*
-LateContextCompiler2::findFunction(const std::string& calleeName, llvm::Function* specializationDefault, ScopePacked scopeCaller){
- const string& functionName = function->function->getName();
- ContextQuery* context = pass->queryContext;
- llvm::IRBuilder<>& builder = pass->man->llvm->builder;
-
- const FunctionDemand& demand = context->getFunctionDemand(functionName);
- const std::list<ManagedFnPtr>& specializations = pass->man->root->getFunctionSpecializations(calleeName);
-
- //independent decision:
- Expression topic(Operator::CALL, {(Atom<Identifier_t>(string(topicSpecializationAtom))),
- Expression(Operator::CALL, {Atom<Identifier_t>(string(calleeName))}),
- Atom<Number_t>(scopeCaller)});
- assert(demand.right.count(topic) && "Can't determine specialization for the function");
- size_t topicId = demand.right.at(topic);
- llvm::Value* topicDecisionRaw = builder.CreateExtractValue(this->rawContextArgument, llvm::ArrayRef<unsigned>{(unsigned) topicId});
-
- const Domain& specializationsDomain= context->getTopicDomain(topic);
-
- std::vector<llvm::Function*> vectorVariants;
- vectorVariants.reserve(specializationsDomain.size());
- for (const ManagedFnPtr& f: specializations){
- if (!f->guardContext.isValid()) continue;
- const auto& variantId = specializationsDomain.getIdOptional(f->guardContext);
- if (variantId){
- if (vectorVariants.size() < *variantId + 1) {
- vectorVariants.resize(*variantId + 1);
- }
-
- vectorVariants[*variantId] = pass->getFunctionUnit(f)->compile();
- }
- }
-
- return compileDecisionSelectorAsSwitch(topicDecisionRaw, vectorVariants, specializationDefault);
-}
-
-llvm::Value*
-LateContextCompiler2::compileContextArgument(const std::string& callee, ScopePacked scopeCaller){
- const std::string& atomDependentDecision = Config::get("clasp.context.decisions.dependent");
- llvm::IRBuilder<>& builder = pass->man->llvm->builder;
- ContextQuery* context = pass->queryContext;
-
- const string& functionName = function->function->getName();
- const Decisions& dictStaticDecisions = context->getFinalDecisions(scopeCaller);
-
- const FunctionDemand& demandCallee = context->getFunctionDemand(callee);
- const FunctionDemand& demandSelf = context->getFunctionDemand(functionName);
-
- llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext());
- llvm::Type* tyDemand = llvm::ArrayType::get(ty32, demandCallee.size());
-
- //builder.CreateAlloca(tyDemand, llvm::ConstantInt::get(ty32, 1));
- llvm::Value* res = llvm::ConstantArray::getNullValue(tyDemand);
-
- for (size_t i=0, size = demandCallee.size(); i<size; ++i){
- const Expression& topic = demandCallee.left.at(i);
- llvm::Value* decisionRaw;
-
- if (demandSelf.right.count(topic)){
- //TOTEST decision propagation
- //propagate decision
- const size_t& topicId = demandSelf.right.at(topic);
- decisionRaw = builder.CreateExtractValue(this->rawContextArgument, llvm::ArrayRef<unsigned>{(unsigned) topicId});
-
- } else if (dictStaticDecisions.count(topic)){
- //static final decision:
- const Expression& decision = dictStaticDecisions.at(topic);
- const Domain& domainOfTopic = context->getTopicDomain(topic);
- const DomainId& decisionCode = domainOfTopic.getId(decision);
- decisionRaw = llvm::ConstantInt::get(ty32, decisionCode);
-
- } else {
- //dependent decision
- decisionRaw = compileDependentDecision(topic, scopeCaller);
- }
-
- res = builder.CreateInsertValue(res, decisionRaw, llvm::ArrayRef<unsigned>{(unsigned) i});
- }
-
- return res;
-}
-
-llvm::Value*
-LateContextCompiler2::compileDependentDecision(const Expression& topic, ScopePacked scopeCaller){
- const string& functionName = function->function->getName();
- ContextQuery* context = pass->queryContext;
- llvm::IRBuilder<>& builder = pass->man->llvm->builder;
- llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext());
-
- const FunctionDemand& demandSelf = context->getFunctionDemand(functionName);
- const Expression topicDependency = Expression(Operator::CALL, {Atom<Identifier_t>(string(topicDependencyAtom)), topic, Atom<Number_t>(scopeCaller)});
-
- const Domain& demandOfTopic = context->getTopicDomain(topic);
- const Domain& domainOfTopicDependency = context->getTopicDomain(topicDependency);
-
- //dependent decision
- vector<llvm::Value*> vectorDecisions(domainOfTopicDependency.size(), llvm::UndefValue::get(ty32));
- for (const std::pair<Expression, Expression>& entry: context->getDependentDecision(scopeCaller,topic)){
- vectorDecisions[domainOfTopicDependency.getId(entry.first)]= llvm::ConstantInt::get(ty32, demandOfTopic.getId(entry.second));
- }
-
- size_t topicDependencyId = demandSelf.right.at(topicDependency);
- llvm::Value* decisionRaw = builder.CreateExtractValue(this->rawContextArgument, llvm::ArrayRef<unsigned>{(unsigned) topicDependencyId});
-
- auto result = compileDecisionSelector(pass->man->llvm->builder, decisionRaw, vectorDecisions);
-
- return result;
-}
-
-
-
-llvm::Value*
-LateContextCompiler2::compileDecisionSelectorAsSwitch(llvm::Value* selector, std::vector<llvm::Function*> vectorVariants, llvm::Function* variantDefault){
- llvm::IRBuilder<>& builder = pass->man->llvm->builder;
- llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext());
-
- llvm::BasicBlock* blockDefault = llvm::BasicBlock::Create(llvm::getGlobalContext(), "caseDefault", this->function->raw);
- llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "VariantDeterminationEnd", this->function->raw);
-
- llvm::SwitchInst* instrSwitch = builder.CreateSwitch(selector, blockDefault, vectorVariants.size());
-
- builder.SetInsertPoint(blockEpilog);
- llvm::PHINode *result = builder.CreatePHI(variantDefault->getType(), vectorVariants.size(), "callee");
-
- for (size_t i=0; i<vectorVariants.size(); ++i){
- llvm::BasicBlock* blockCase = llvm::BasicBlock::Create(llvm::getGlobalContext(), "", this->function->raw);
- builder.SetInsertPoint(blockCase);
- builder.CreateBr(blockEpilog);
- result->addIncoming(vectorVariants[i], blockCase);
- instrSwitch->addCase(llvm::ConstantInt::get(ty32, i), blockCase);
- }
-
- builder.SetInsertPoint(blockDefault);
- builder.CreateBr(blockEpilog);
- result->addIncoming(variantDefault, blockDefault);
-
- builder.SetInsertPoint(blockEpilog);
- return result;
-}
-
-size_t
-LateContextCompiler2::getFunctionDemandSize() const {
- return __sizeOfDemand;
-}
-
-}} /* namespace xreate::context */
diff --git a/cpp/src/compilation/latecontextcompiler2.h b/cpp/src/compilation/latecontextcompiler2.h
deleted file mode 100644
index faa33b2..0000000
--- a/cpp/src/compilation/latecontextcompiler2.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- *
- * LateContextCompiler2.h
- *
- * Created on: 02/10, 2016
- * Author: pgess <v.melnychenko@xreate.org>
- */
-
-//TOTEST compile several context arguments
-#ifndef LATECONTEXTCOMPILER2_H_
-#define LATECONTEXTCOMPILER2_H_
-
-#include "serialization.h"
-
-namespace llvm {
- class Value;
- class Function;
-}
-
-namespace xreate {
- class CompilePass;
-
-namespace compilation {
- class IFunctionUnit;
-}}
-
-namespace xreate {namespace context{
-
-typedef unsigned int ScopePacked;
-
-/** \brief Encapsulates compilation of Late Context
- * \sa xreate::context::ContextQuery, xreate::compilation::BasicCodeScopeUnit
- */
-class LateContextCompiler2 {
-public:
- llvm::Value* rawContextArgument = nullptr;
-
- LateContextCompiler2(compilation::IFunctionUnit* f, CompilePass* p);
-
- /** \brief Finds function with regard to late context*/
- llvm::Value* findFunction(const std::string& calleeName, llvm::Function* specializationDefault, ScopePacked scopeCaller);
- llvm::Value* compileContextArgument(const std::string& callee, ScopePacked scopeCaller);
- size_t getFunctionDemandSize() const;
-
-private:
- //boost::bimap<size_t, std::string> __decisions;
- //std::vector<Domain> __scheme;
-
- compilation::IFunctionUnit* function;
- CompilePass* pass;
- size_t __sizeOfDemand;
-
- llvm::Value* compileDependentDecision(const Expression& topic, ScopePacked scopeCaller);
- llvm::Value* compileDecisionSelectorAsSwitch(llvm::Value* selector, std::vector<llvm::Function*> vectorVariants, llvm::Function* variantDefault);
-};
-}} /* namespace xreate::context */
-
-#endif /* LATECONTEXTCOMPILER2_H_ */
diff --git a/cpp/src/compilation/polymorphcompiler.h b/cpp/src/compilation/polymorphcompiler.h
index 1d61e1d..0d29cae 100644
--- a/cpp/src/compilation/polymorphcompiler.h
+++ b/cpp/src/compilation/polymorphcompiler.h
@@ -1,68 +1,63 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: polymorphcompiler.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on October 7, 2017
*/
#ifndef POLYMORPHCOMPILER_H
#define POLYMORPHCOMPILER_H
#include "pass/compilepass.h"
#include "query/polymorph.h"
namespace xreate { namespace polymorph {
typedef Expression Guard;
template <class Parent>
class PolymorphCodeScopeUnit: public Parent{
public:
PolymorphCodeScopeUnit(const CodeScope* const codeScope, compilation::IFunctionUnit* f, CompilePass* compilePass)
: Parent(codeScope, f, compilePass) {}
protected:
compilation::ICallStatement* findFunction(const Expression& opCall) override {
//Check does invocation require guards
const std::string& nameCallee = opCall.getValueString();
const std::list<ManagedFnPtr>& specializations = Parent::pass->man->root->getFunctionSpecializations(nameCallee);
//Extern function
if (specializations.size() == 0){
return Parent::findFunction(opCall);
}
//No other specializations. Check if it has no guard
if (specializations.size() == 1){
if (!specializations.front()->guard.isValid()) {
return Parent::findFunction(opCall);
}
}
- //TODO There are overlapping guards and contexts. For now, skip if context found.
- if (specializations.front()->guardContext.isValid()){
- return Parent::findFunction(opCall);
- }
-
//Several specializations
assert(Attachments::exists<PolymorphGuard>(opCall) && "Guard required");
const Expression& guardSelected = Attachments::get<PolymorphGuard>(opCall);
std::map<Guard, ManagedFnPtr> indexSpecs;
for(ManagedFnPtr specialization: specializations){
indexSpecs.emplace(specialization->guard, specialization);
}
assert(indexSpecs.count(guardSelected) && "Can't found appropriate guard");
return new compilation::CallStatementRaw(Parent::pass->getFunctionUnit(indexSpecs.at(guardSelected))->compile(), Parent::pass->man->llvm);
}
};
} } //end of xreate::polymorph
#endif /* POLYMORPHCOMPILER_H */
diff --git a/cpp/src/compilation/scopedecorators.h b/cpp/src/compilation/scopedecorators.h
index 3fbf541..adf7c72 100644
--- a/cpp/src/compilation/scopedecorators.h
+++ b/cpp/src/compilation/scopedecorators.h
@@ -1,151 +1,157 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: scopedecorators.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on February 24, 2017, 11:35 AM
*/
/**
* \file scopedecorators.h
* \brief Basic code block compilation xreate::compilation::ICodeScopeUnit decorators
*/
#ifndef SCOPEDECORATORS_H
#define SCOPEDECORATORS_H
#include "ast.h"
#include "compilation/targetinterpretation.h"
#include "compilation/versions.h"
#include "compilation/transformations.h"
#include "compilation/polymorphcompiler.h"
+#include <list>
namespace xreate {
class CompilePass;
namespace compilation {
class ICodeScopeUnit;
class IFunctionUnit;
/**\brief Caching ability for code scope compilation
* \extends xreate::compilation::ICodeScopeUnit
*/
template<class Parent>
class CachedScopeDecorator: public Parent{
typedef CachedScopeDecorator<Parent> SELF;
public:
CachedScopeDecorator(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){}
Symbol bindArg(llvm::Value* value, std::string&& alias)
{
//ensure existence of an alias
assert(Parent::scope->__identifiers.count(alias));
//memorize new value for an alias
ScopedSymbol id{Parent::scope->__identifiers.at(alias), versions::VERSION_NONE};
__rawVars[id] = value;
return Symbol{id, Parent::scope};
}
void bindArg(llvm::Value* value, const ScopedSymbol& s) {
__rawVars[s] = value;
}
llvm::Value* compile(const std::string& hintBlockDecl="") override{
if (__rawVars.count(ScopedSymbol::RetSymbol)){
return __rawVars[ScopedSymbol::RetSymbol];
}
return Parent::compile(hintBlockDecl);
}
llvm::Value*
processSymbol(const Symbol& s, std::string hintRetVar) override{
const CodeScope* scope = s.scope;
SELF* self = dynamic_cast<SELF*>(Parent::function->getScopeUnit(scope));
if (self->__rawVars.count(s.identifier)){
return self->__rawVars[s.identifier];
}
//Declaration could be overriden
/*
Expression declaration = CodeScope::getDefinition(s, true);
if (!declaration.isDefined()){
assert(__declarationsOverriden.count(s.identifier));
declaration = __declarationsOverriden[s.identifier];
} else {
(false); //in case of binding there should be raws provided.
}
}
*/
llvm::Value* resultRaw = Parent::processSymbol(s, hintRetVar);
self->__rawVars.emplace(s.identifier, resultRaw);
return resultRaw;
}
void
- overrideDeclaration(const Symbol binding, Expression&& declaration){
- SELF* self = dynamic_cast<SELF*>(Parent::function->getScopeUnit(binding.scope));
-
- self->__declarationsOverriden.emplace(binding.identifier, std::move(declaration));
+ overrideDeclarations(std::list<std::pair<Symbol, Expression>> bindings){
+ reset();
+
+ for (auto entry: bindings){
+ SELF* self = dynamic_cast<SELF*>(Parent::function->getScopeUnit(entry.first.scope));
+ assert(self == this);
+
+ self->__declarationsOverriden.emplace(entry.first.identifier, entry.second);
+ }
}
void registerChildScope(std::shared_ptr<ICodeScopeUnit> scope){
__childScopes.push_back(scope);
}
void reset(){
__rawVars.clear();
__declarationsOverriden.clear();
__childScopes.clear();
}
private:
std::unordered_map<ScopedSymbol, Expression> __declarationsOverriden;
std::unordered_map<ScopedSymbol,llvm::Value*> __rawVars;
std::list<std::shared_ptr<ICodeScopeUnit>> __childScopes;
};
/**\brief Default code scope compilation functionality*/
typedef CachedScopeDecorator<
polymorph::PolymorphCodeScopeUnit<
::xreate::compilation::TransformationsScopeDecorator<
interpretation::InterpretationScopeDecorator<
versions::VersionsScopeDecorator<compilation::BasicCodeScopeUnit>>>>>
DefaultCodeScopeUnit;
} //end of compilation namespace
struct CachedScopeDecoratorTag;
struct VersionsScopeDecoratorTag;
template<>
struct DecoratorsDict<CachedScopeDecoratorTag>{
typedef compilation::CachedScopeDecorator<
polymorph::PolymorphCodeScopeUnit<
compilation::TransformationsScopeDecorator<
interpretation::InterpretationScopeDecorator<
versions::VersionsScopeDecorator<compilation::BasicCodeScopeUnit>>>>> result;
};
template<>
struct DecoratorsDict<VersionsScopeDecoratorTag>{
typedef versions::VersionsScopeDecorator<
compilation::BasicCodeScopeUnit> result;
};
} //end of xreate
#endif /* SCOPEDECORATORS_H */
diff --git a/cpp/src/compilation/targetinterpretation.cpp b/cpp/src/compilation/targetinterpretation.cpp
index 6b61305..ae9237f 100644
--- a/cpp/src/compilation/targetinterpretation.cpp
+++ b/cpp/src/compilation/targetinterpretation.cpp
@@ -1,595 +1,644 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: targetinterpretation.cpp
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on June 29, 2016, 6:45 PM
*/
/**
* \file targetinterpretation.h
* \brief Interpretation support. See more [details on Interpretation](/w/concepts/dsl/)
*/
#include "compilation/targetinterpretation.h"
#include "pass/interpretationpass.h"
#include "analysis/typeinference.h"
#include "llvmlayer.h"
#include "compilation/scopedecorators.h"
#include <boost/scoped_ptr.hpp>
#include <iostream>
#include <clang/AST/DeclBase.h>
+#include <csignal>
using namespace std;
using namespace xreate::compilation;
namespace xreate{ namespace interpretation{
-
const Expression EXPRESSION_FALSE = Expression(Atom<Number_t>(0));
const Expression EXPRESSION_TRUE = Expression(Atom<Number_t>(1));
Expression
representAsAnnotation(const Gringo::Symbol& atom){
switch (atom.type()) {
case Gringo::SymbolType::Num: {
Expression result(Operator::VARIANT, {Expression(atom.num())});
result.setValueDouble(0);
return result;
}
case Gringo::SymbolType::Str: {
Expression result(Operator::VARIANT, {Expression(Atom<String_t>(std::string(atom.string().c_str())))});
result.setValueDouble(1);
return result;
}
- case Gringo::SymbolType::Fun:
- {
+ case Gringo::SymbolType::Fun: {
Expression fnDescription(Operator::LIST_NAMED, {});
std::list<Atom<Identifier_t>> bindings{Atom<Identifier_t>("name"), Atom<Identifier_t>("arguments")};
fnDescription.addBindings(bindings.begin(), bindings.end());
-
fnDescription.addArg(Expression(Atom<String_t>(std::string(atom.name().c_str()))));
Expression args(Operator::LIST, {});
for (const Gringo::Symbol& arg : atom.args()) {
args.addArg(representAsAnnotation(arg));
}
fnDescription.addArg(std::move(args));
Expression result(Operator::VARIANT, {fnDescription});
result.setValueDouble(2);
return result;
}
- default:
- {
+ default: {
assert(false);
}
}
}
CodeScope*
InterpretationScope::processOperatorIf(const Expression& expression){
const Expression& exprCondition = process(expression.getOperands()[0]);
if (exprCondition == EXPRESSION_TRUE){
return expression.blocks.front();
}
return expression.blocks.back();
}
CodeScope*
InterpretationScope::processOperatorSwitch(const Expression& expression) {
const Expression& exprCondition = process(expression.operands[0]);
bool flagHasDefault = expression.operands[1].op == Operator::CASE_DEFAULT;
//TODO check that one and only one case variant is appropriate
for (size_t size = expression.operands.size(), i= flagHasDefault? 2: 1; i<size; ++i){
const Expression& exprCase = process(expression.operands[i]);
if (function->getScope((const CodeScope*) exprCase.blocks.front())->processScope() == exprCondition){
return exprCase.blocks.back();
}
}
if (flagHasDefault){
const Expression& exprCaseDefault = expression.operands[1];
return exprCaseDefault.blocks.front();
}
assert(false && "Switch has no appropriate variant");
return nullptr;
}
CodeScope*
InterpretationScope::processOperatorSwitchVariant(const Expression& expression){
const Expression& condition = process(expression.operands.at(0));
assert(condition.op == Operator::VARIANT);
const string& identCondition = expression.bindings.front();
Expression opExpected(Atom<Number_t>(condition.getValueDouble()));
auto itFoundValue = std::find(++expression.operands.begin(), expression.operands.end(), opExpected);
assert(itFoundValue != expression.operands.end());
int indexBlock = itFoundValue - expression.operands.begin() -1;
auto blockFound = expression.blocks.begin();
std::advance(blockFound, indexBlock);
InterpretationScope* scopeI12n = function->getScope(*blockFound);
- if (condition.operands.size()) {
- const Expression& value = condition.operands.at(0);
- scopeI12n->overrideBinding(value, identCondition);
- }
+ if(condition.operands.size()){
+ const Expression& value=condition.operands.at(0);
+ scopeI12n->overrideBindings({
+ {value, identCondition}});
+ }
return *blockFound;
}
llvm::Value*
InterpretationScope::compileHybrid(const InterpretationOperator& op, const Expression& expression, const Context& context){
switch(op){
case IF_INTERPRET_CONDITION: {
CodeScope* scopeResult = processOperatorIf(expression);
llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile();
return result;
}
case SWITCH_INTERPRET_CONDITION:{
CodeScope* scopeResult = processOperatorSwitch(expression);
llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile();
return result;
}
case SWITCH_VARIANT: {
CodeScope* scopeResult = processOperatorSwitchVariant(expression);
const Expression& condition = expression.operands.at(0);
const Expression& valueCondition = process(condition);
const string identCondition = expression.bindings.front();
auto scopeCompilation = Decorators<CachedScopeDecoratorTag>::getInterface(context.function->getScopeUnit(scopeResult));
if(valueCondition.operands.size()){
//override value
Symbol symbCondition{ScopedSymbol{scopeResult->__identifiers.at(identCondition), versions::VERSION_NONE}, scopeResult};
- scopeCompilation->overrideDeclaration(symbCondition, Expression(valueCondition.operands.at(0)));
+ scopeCompilation->overrideDeclarations(
+ {{symbCondition, Expression(valueCondition.operands.at(0))}}
+ );
//set correct type for binding:
TypeAnnotation typeVariant = typeinference::getType(condition, *function->man->ast);
int conditionIndex = valueCondition.getValueDouble();
ScopedSymbol symbolInternal = scopeResult->getSymbol(identCondition);
scopeResult->__declarations[symbolInternal].bindType(typeVariant.__operands.at(conditionIndex));
}
llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile();
return result;
}
case FOLD_INTERPRET_INPUT: {
//initialization
const Expression& exprInput = process(expression.getOperands()[0]);
assert(exprInput.op == Operator::LIST);
CodeScope* scopeBody = expression.blocks.front();
const string& nameEl = expression.bindings[0];
Symbol symbEl{ScopedSymbol{scopeBody->__identifiers.at(nameEl), versions::VERSION_NONE}, scopeBody};
const std::string& idAccum = expression.bindings[1];
llvm::Value* rawAccum = context.scope->process(expression.getOperands()[1]);
InterpretationScope* intrBody = function->getScope(scopeBody);
auto unitBody = Decorators<CachedScopeDecoratorTag>::getInterface(context.function->getScopeUnit(scopeBody));
const std::vector<Expression> elementsInput= exprInput.getOperands();
- for (size_t i=0; i<elementsInput.size(); ++i){
- intrBody->reset();
- unitBody->reset();
+ for(size_t i=0; i<elementsInput.size(); ++i) {
+ const Expression& exprElement=elementsInput[i];
- Expression exprElement = elementsInput[i];
+ intrBody->overrideBindings({
+ {exprElement, nameEl}});
+ unitBody->overrideDeclarations({
+ {symbEl, exprElement}}); //resets unitBody
+ unitBody->bindArg(rawAccum, string(idAccum));
- intrBody->overrideBinding(exprElement, nameEl);
- unitBody->overrideDeclaration(symbEl, move(exprElement));
- unitBody->bindArg(rawAccum, string(idAccum));
-
- rawAccum = unitBody->compile();
+ rawAccum=unitBody->compile();
}
return rawAccum;
}
/*
case FOLD_INF_INTERPRET_INOUT{
}
*/
//TODO refactor as InterpretationCallStatement class
case CALL_INTERPRET_PARTIAL: {
const std::string &calleeName = expression.getValueString();
ICodeScopeUnit* scopeUnitSelf = context.scope;
ManagedFnPtr callee = this->function->man->ast->findFunction(calleeName);
const FunctionInterpretationData& calleeData = FunctionInterpretationHelper::getSignature(callee);
std::vector<llvm::Value *> argsActual;
PIFSignature sig;
sig.declaration = callee;
for(size_t no=0, size = expression.operands.size(); no < size; ++no){
const Expression& op = expression.operands[no];
if (calleeData.signature.at(no) == INTR_ONLY){
sig.bindings.push_back(process(op));
continue;
}
argsActual.push_back(scopeUnitSelf->process(op));
}
TargetInterpretation* man = dynamic_cast<TargetInterpretation*>(this->function->man);
PIFunction* pifunction = man->getFunction(move(sig));
llvm::Function* raw = pifunction->compile();
boost::scoped_ptr<CallStatementRaw> statement(new CallStatementRaw(raw, man->pass->man->llvm));
return (*statement)(move(argsActual));
}
default: break;
}
assert(false&& "Unknown hybrid operator");
return nullptr;
}
llvm::Value*
InterpretationScope::compile(const Expression& expression, const Context& context){
const InterpretationData& data = Attachments::get<InterpretationData>(expression);
if (data.op != InterpretationOperator::NONE){
return compileHybrid(data.op, expression, context);
}
Expression result = process(expression);
return context.scope->process(result);
}
Expression
-InterpretationScope::process(const Expression& expression){
+InterpretationScope::process(const Expression& expression) {
+#ifndef NDEBUG
+ if (expression.tags.count("bpoint")){
+ std::raise(SIGINT);
+ }
+#endif
+
+ PassManager* man = (static_cast<TargetInterpretation*> (function->man))->pass->man;
+
switch (expression.__state){
case Expression::INVALID:
assert(false);
case Expression::NUMBER:
case Expression::STRING:
return expression;
case Expression::IDENT:{
Symbol s = Attachments::get<IdentifierSymbol>(expression);
return Parent::processSymbol(s);
}
case Expression::COMPOUND:
break;
default: assert(false);
}
switch (expression.op) {
case Operator::EQU: {
const Expression& left = process(expression.operands[0]);
const Expression& right = process(expression.operands[1]);
if (left == right) return EXPRESSION_TRUE;
return EXPRESSION_FALSE;
}
case Operator::NE: {
const Expression& left = process(expression.operands[0]);
const Expression& right = process(expression.operands[1]);
if (left == right) return EXPRESSION_FALSE;
return EXPRESSION_TRUE;
}
case Operator::LOGIC_AND: {
assert(expression.operands.size() == 1);
return process (expression.operands[0]);
}
// case Operator::LOGIC_OR:
case Operator::CALL: {
const std::string &fnName = expression.getValueString();
ManagedFnPtr fnAst = this->function->man->ast->findFunction(fnName);
InterpretationFunction* fnUnit = this->function->man->getFunction(fnAst);
vector<Expression> args;
args.reserve(expression.getOperands().size());
for(size_t i=0, size = expression.getOperands().size(); i<size; ++i) {
args.push_back(process(expression.getOperands()[i]));
}
return fnUnit->process(args);
}
case Operator::CALL_INTRINSIC: {
std::string nameFunction = expression.getValueString();
if(nameFunction=="query"){
assert(expression.operands.size() == 1);
assert(expression.operands.front().__state == Expression::STRING);
std::string namePredicate = expression.operands.front().getValueString();
ClaspLayer::ModelFragment model = (static_cast<TargetInterpretation*>(function->man))->pass->man->clasp->query(namePredicate);
Expression result(Operator::LIST, {});
if(model)
for (const auto& row: boost::make_iterator_range(model.get())) {
result.addArg(representAsAnnotation(std::get<1>(row)));
}
- return result;
+ return result;
+
+ } else if(nameFunction=="query_scope"){
+ ScopePacked scopeId = man->clasp->pack(scope);
+ Expression result(Operator::VARIANT, {Expression(scopeId)});
+ result.setValueDouble(0);
+ return result;
} else {
assert(false && "Unknown intrinsic");
}
}
case Operator::IF:{
CodeScope* scopeResult = processOperatorIf(expression);
return function->getScope(scopeResult)->processScope();
}
case Operator::SWITCH: {
CodeScope* scopeResult = processOperatorSwitch(expression);
return function->getScope(scopeResult)->processScope();
}
case Operator::SWITCH_VARIANT: {
CodeScope* scopeResult = processOperatorSwitchVariant(expression);
return function->getScope(scopeResult)->processScope();
}
+ case Operator::VARIANT: {
+ if(!expression.operands.size()) return expression;
+
+ Expression variantData = process(expression.operands[0]);
+ Expression result{Operator::VARIANT, {variantData}};
+ result.setValueDouble(expression.getValueDouble());
+ return result;
+ }
+
case Operator::INDEX: {
Expression exprData = process(expression.operands[0]);
for (size_t keyId=1; keyId<expression.operands.size(); ++keyId){
const Expression& exprKey = process(expression.operands[keyId]);
if (exprKey.__state == Expression::STRING){
const string& key = exprKey.getValueString();
assert(exprData.__indexBindings.count(key));
size_t idxKey = exprData.__indexBindings.at(key);
exprData = Expression(exprData.operands.at(idxKey));
continue;
}
if (exprKey.__state == Expression::NUMBER){
int key = exprKey.getValueDouble();
exprData = Expression(exprData.operands[key]);
continue;
}
assert(false && "Inappropriate key");
}
return exprData;
}
case Operator::FOLD: {
const Expression& exprInput = process(expression.getOperands()[0]);
const Expression& exprInit = process(expression.getOperands()[1]);
const std::string& argEl = expression.bindings[0];
const std::string& argAccum = expression.bindings[1];
InterpretationScope* body = function->getScope(expression.blocks.front());
Expression accum = exprInit;
for(size_t size=exprInput.getOperands().size(), i=0; i<size; ++i){
- body->overrideBinding(exprInput.getOperands()[i], argEl);
- body->overrideBinding(accum, argAccum);
+ body->overrideBindings({
+ {exprInput.getOperands()[i], argEl},
+ {accum, argAccum}
+ });
accum = body->processScope();
}
return accum;
- }
+ }
+
+ case Operator::LIST:
+ case Operator::LIST_NAMED:
+ case Operator::LIST_RANGE:
+ {
+ Expression result(expression.op,{});
+ result.operands.resize(expression.operands.size());
+ result.bindings=expression.bindings;
+ result.__indexBindings=expression.__indexBindings;
+
+ int keyId=0;
+ for(const Expression& opCurrent : expression.operands) {
+ result.operands[keyId++]=process(opCurrent);
+ }
+
+ return result;
+ }
// case Operator::MAP: {
// break;
// }
default: break;
}
return expression;
}
InterpretationFunction*
TargetInterpretation::getFunction(IFunctionUnit* unit){
if (__dictFunctionsByUnit.count(unit)) {
return __dictFunctionsByUnit.at(unit);
}
InterpretationFunction* f = new InterpretationFunction(unit->function, this);
__dictFunctionsByUnit.emplace(unit, f);
assert(__functions.emplace(unit->function.id(), f).second);
return f;
}
PIFunction*
TargetInterpretation::getFunction(PIFSignature&& sig){
auto f = __pifunctions.find(sig);
if (f != __pifunctions.end()){
return f->second;
}
PIFunction* result = new PIFunction(PIFSignature(sig), __pifunctions.size(), this);
__pifunctions.emplace(move(sig), result);
assert(__dictFunctionsByUnit.emplace(result->functionUnit, result).second);
return result;
}
InterpretationScope*
TargetInterpretation::transformContext(const Context& c){
return this->getFunction(c.function)->getScope(c.scope->scope);
}
llvm::Value*
TargetInterpretation::compile(const Expression& expression, const Context& ctx){
return transformContext(ctx)->compile(expression, ctx);
}
InterpretationFunction::InterpretationFunction(const ManagedFnPtr& function, Target<TargetInterpretation>* target)
: Function<TargetInterpretation>(function, target)
{}
Expression
InterpretationFunction::process(const std::vector<Expression>& args){
InterpretationScope* body = getScope(__function->__entry);
- for(size_t i=0, size = args.size(); i<size; ++i) {
- body->overrideBinding(args.at(i), string(body->scope->__bindings.at(i)));
+ list<pair<Expression, string>> bindings;
+ for(size_t i=0, size=args.size(); i<size; ++i) {
+ bindings.push_back(make_pair(args.at(i), body->scope->__bindings.at(i)));
}
+ body->overrideBindings(bindings);
return body->processScope();
}
// Partial function interpretation
typedef BasicFunctionUnit PIFunctionUnitParent;
-class PIFunctionUnit: public PIFunctionUnitParent{
+
+class PIFunctionUnit : public PIFunctionUnitParent {
public:
PIFunctionUnit(ManagedFnPtr f, std::set<size_t>&& arguments, size_t id, CompilePass* p)
- : PIFunctionUnitParent(f, p), argumentsActual(move(arguments)), __id(id)
- {}
+ : PIFunctionUnitParent(f, p), argumentsActual(move(arguments)), __id(id) { }
protected:
std::vector<llvm::Type*> prepareArguments(){
LLVMLayer* llvm = PIFunctionUnitParent::pass->man->llvm;
AST* ast = PIFunctionUnitParent::pass->man->root;
CodeScope* entry = PIFunctionUnitParent::function->__entry;
std::vector<llvm::Type*> signature;
for(size_t no: argumentsActual){
VNameId argId = entry->__identifiers.at(entry->__bindings.at(no));
ScopedSymbol arg{argId, versions::VERSION_NONE};
signature.push_back(llvm->toLLVMType(ast->expandType(entry->__declarations.at(arg).type)));
}
return signature;
}
llvm::Function::arg_iterator prepareBindings(){
CodeScope* entry = PIFunctionUnitParent::function->__entry;
ICodeScopeUnit* entryCompilation = PIFunctionUnitParent::getScopeUnit(entry);
llvm::Function::arg_iterator fargsI = PIFunctionUnitParent::raw->arg_begin();
for(size_t no: argumentsActual){
ScopedSymbol arg{entry->__identifiers.at(entry->__bindings.at(no)), versions::VERSION_NONE};
entryCompilation->bindArg(&*fargsI, arg);
fargsI->setName(entry->__bindings.at(no));
++fargsI;
}
return fargsI;
}
virtual std::string prepareName(){
return PIFunctionUnitParent::prepareName() + "_" + std::to_string(__id);
}
private:
std::set<size_t> argumentsActual;
size_t __id;
};
PIFunction::PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target)
- : InterpretationFunction(sig.declaration, target), signatureInstance(move(sig))
-{
+: InterpretationFunction(sig.declaration, target), signatureInstance(move(sig)) {
const FunctionInterpretationData& functionData = FunctionInterpretationHelper::getSignature(signatureInstance.declaration);
std::set<size_t> argumentsActual;
for (size_t no=0, size=functionData.signature.size(); no < size; ++no){
if (functionData.signature.at(no) != INTR_ONLY){
argumentsActual.insert(no);
}
}
functionUnit = new PIFunctionUnit(signatureInstance.declaration, move(argumentsActual), id, target->pass);
CodeScope* entry = signatureInstance.declaration->__entry;
auto entryUnit = Decorators<CachedScopeDecoratorTag>::getInterface<>(functionUnit->getEntry());
InterpretationScope* entryIntrp = InterpretationFunction::getScope(entry);
- for(size_t no=0, sigNo=0, size = entry->__bindings.size(); no < size; ++no){
- if (functionData.signature.at(no) == INTR_ONLY){
- entryIntrp->overrideBinding(signatureInstance.bindings[sigNo], entry->__bindings[no]);
+ list<pair<Expression, std::string>> bindingsPartial;
+ list<pair<Symbol, Expression>> declsPartial;
- VNameId argId = entry->__identifiers.at(entry->__bindings[no]);
- Symbol argSymbol{ScopedSymbol{argId, versions::VERSION_NONE}, entry};
- entryUnit->overrideDeclaration(argSymbol, Expression(signatureInstance.bindings[sigNo]));
+ for(size_t no=0, sigNo=0, size=entry->__bindings.size(); no<size; ++no) {
+ if(functionData.signature.at(no)==INTR_ONLY){
+ bindingsPartial.push_back({signatureInstance.bindings[sigNo], entry->__bindings[no]});
+
+ VNameId argId=entry->__identifiers.at(entry->__bindings[no]);
+ Symbol argSymbol{ScopedSymbol
+ {argId, versions::VERSION_NONE}, entry};
+ declsPartial.push_back({argSymbol, signatureInstance.bindings[sigNo]});
++sigNo;
}
}
+
+ entryIntrp->overrideBindings(bindingsPartial);
+ entryUnit->overrideDeclarations(declsPartial);
}
llvm::Function*
PIFunction::compile(){
llvm::Function* raw = functionUnit->compile();
return raw;
}
bool operator<(const PIFSignature& lhs, const PIFSignature& rhs){
if (lhs.declaration.id() != rhs.declaration.id()) {
return lhs.declaration.id() < rhs.declaration.id();
}
return lhs.bindings < rhs.bindings;
}
bool operator<(const PIFSignature& lhs, PIFunction* const rhs){
return lhs < rhs->signatureInstance;
}
bool operator<(PIFunction* const lhs, const PIFSignature& rhs){
return lhs->signatureInstance < rhs;
}
}}
/** \class xreate::interpretation::InterpretationFunction
*
* Holds list of xreate::interpretation::InterpretationScope 's focused on interpretation of individual code scopes
*
* There is particulat subclass PIFunction intended to represent partially interpreted functions
*\sa TargetInterpretation, [Interpretation Concept](/w/concepts/dfa)
*/
/** \class xreate::interpretation::TargetInterpretation
*
* Executed during compilation and intented to preprocess eligible parts of code.
* Established on [Targets Infrastructure](\ref compilation::Target)
*
* Holds list of InterpretationFunction / PIFunction to represent interpretation process for individual functions
*
* In order to be activated during compilation process there is
* InterpretationScopeDecorator implementation of ICodeScopeUnit
* \sa InterpretationPass, compilation::Target, [Interpretation Concept](/w/concepts/dfa)
*
*/
\ No newline at end of file
diff --git a/cpp/src/compilation/targets.h b/cpp/src/compilation/targets.h
index 1b86b31..dee23be 100644
--- a/cpp/src/compilation/targets.h
+++ b/cpp/src/compilation/targets.h
@@ -1,201 +1,198 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: targetabstract.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on July 2, 2016, 1:25 PM
*/
/**
* \file
* \brief Compilation targets infrastructure
*/
#ifndef TARGETABSTRACT_H
#define TARGETABSTRACT_H
-#include "ast.h"
+#include "ast.h"
#include <boost/optional.hpp>
#include <map>
+#include <list>
namespace xreate{ namespace compilation {
template <typename ConcreteTarget>
struct TargetInfo{
//typedef Result
//typedef Function
//typedef Scope
};
template<typename ConcreteTarget>
class Function;
template<typename ConcreteTarget>
class Target;
template<typename ConcreteTarget>
class Scope{
typedef typename TargetInfo<ConcreteTarget>::Scope Self;
public:
const CodeScope* scope;
typename TargetInfo<ConcreteTarget>::Result
processSymbol(const Symbol& s){
const CodeScope* scope = s.scope;
Self* self = function->getScope(scope);
if (self->__bindings.count(s.identifier)) {
return self->__bindings[s.identifier];
}
const Expression& declaration = CodeScope::getDefinition(s, true);
if (!declaration.isDefined()){
assert(false); //for bindings there should be result already
}
return self->__bindings[s.identifier] = self->process(declaration);
}
typename TargetInfo<ConcreteTarget>::Result
processScope() {
- if (raw) return *raw;
-
- raw = process(scope->getBody());
- return *raw;
+ return process(scope->getBody());
}
// typename TargetInfo<ConcreteTarget>::Result
// processFunction(typename TargetInfo<ConcreteTarget>::Function* fnRemote, const std::vector<typename TargetInfo<ConcreteTarget>::Result>& args){
// Scope<ConcreteTarget> scopeRemote = fnRemote->getScope(fnRemote->__function->__entry);
//
// if (scopeRemote->raw){
// return scopeRemote->raw;
// }
//
// return fnRemote->process(args);
// }
virtual typename TargetInfo<ConcreteTarget>::Result
process(const Expression& expression)=0;
Scope(const CodeScope* codeScope, Function<ConcreteTarget>* f)
: scope(codeScope), function(f) {}
virtual ~Scope(){}
void
- overrideBinding(typename TargetInfo<ConcreteTarget>::Result arg, const std::string& name){
- assert(scope->__identifiers.count(name));
+ overrideBindings(std::list<std::pair<typename TargetInfo<ConcreteTarget>::Result, std::string>> bindings){
+ reset();
- ScopedSymbol id{scope->__identifiers.at(name), versions::VERSION_NONE};
- __bindings[id] = arg;
-
- //reset the result if any:
- raw.reset();
+ for (auto entry: bindings){
+ assert(scope->__identifiers.count(entry.second));
+ ScopedSymbol id{scope->__identifiers.at(entry.second), versions::VERSION_NONE};
+
+ __bindings[id] = entry.first;
+ }
}
void registerChildScope(std::shared_ptr<Self> scope){
__childScopes.push_back(scope);
}
void reset(){
__bindings.clear();
__childScopes.clear();
- raw.reset();
}
protected:
Function<ConcreteTarget>* function=0;
std::map<ScopedSymbol, typename TargetInfo<ConcreteTarget>::Result> __bindings;
std::list<std::shared_ptr<Self>> __childScopes;
- typename boost::optional<typename TargetInfo<ConcreteTarget>::Result> raw;
};
template<typename ConcreteTarget>
class Function{
typedef typename TargetInfo<ConcreteTarget>::Result Result;
typedef typename TargetInfo<ConcreteTarget>::Scope ConcreteScope;
public:
Function(const ManagedFnPtr& function, Target<ConcreteTarget>* target)
: man(target), __function(function) {}
virtual ~Function(){};
ConcreteScope*
getScope(const CodeScope* const scope){
if (__scopes.count(scope)) {
auto result = __scopes.at(scope).lock();
if (result){
return result.get();
}
}
std::shared_ptr<ConcreteScope> unit(new ConcreteScope(scope, this));
if (scope->__parent != nullptr){
getScope(scope->__parent)->registerChildScope(unit);
} else {
assert(!__entryScope);
__entryScope = unit;
}
if (!__scopes.emplace(scope, unit).second){
__scopes[scope] = unit;
}
return unit.get();
}
virtual Result
process(const std::vector<Result>& args)=0;
Target<ConcreteTarget>* man=0;
ManagedFnPtr __function;
protected:
std::map<const CodeScope*, std::weak_ptr<ConcreteScope>> __scopes;
std::shared_ptr<ConcreteScope> __entryScope;
};
/** \brief Similar to xreate::IPass */
template<typename ConcreteTarget>
class Target {
typedef typename TargetInfo<ConcreteTarget>::Function ConcreteFunction;
public:
Target(AST* root): ast(root){}
ConcreteFunction*
getFunction(const ManagedFnPtr& function){
unsigned int id = function.id();
if (!__functions.count(id)){
ConcreteFunction* unit = new ConcreteFunction(function, this);
__functions.emplace(id, unit);
return unit;
}
return __functions.at(id);
}
AST* ast;
virtual ~Target(){
for (const auto& entry: __functions){
delete entry.second;
}
}
protected:
std::map<unsigned int, ConcreteFunction*> __functions;
};
}}
#endif /* TARGETABSTRACT_H */
diff --git a/cpp/src/contextrule.h b/cpp/src/contextrule.h
index 2c70f8e..8d7227b 100644
--- a/cpp/src/contextrule.h
+++ b/cpp/src/contextrule.h
@@ -1,34 +1,34 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* contextrule.h
*
* Created on: Jan 2, 2016
* Author: pgess <v.melnychenko@xreate.org>
*/
#ifndef SRC_CONTEXTRULE_H_
#define SRC_CONTEXTRULE_H_
#include "ast.h"
#include <string>
namespace xreate {
typedef unsigned int ScopePacked;
class ContextRule {
- public:
- ContextRule(const Expression& rule);
- std::string compile(const ScopePacked& scopeId) const;
-
- private:
- Expression head;
- Expression guards;
- Expression body;
+public:
+ ContextRule(const Expression& rule);
+ std::string compile(const ScopePacked& scopeId) const;
+
+private:
+ Expression head;
+ Expression guards;
+ Expression body;
};
}
#endif /* SRC_CONTEXTRULE_H_ */
diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp
index 6c173ed..b66b7d5 100644
--- a/cpp/src/pass/compilepass.cpp
+++ b/cpp/src/pass/compilepass.cpp
@@ -1,873 +1,740 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Author: pgess <v.melnychenko@xreate.org>
*
* compilepass.cpp
*/
/**
* \file compilepass.h
* \brief Compilation pass
*/
#include "compilepass.h"
#include "clasplayer.h"
#include <ast.h>
#include "llvmlayer.h"
#include "query/containers.h"
#include "query/context.h"
#include "compilation/containers.h"
-#include "compilation/latecontextcompiler2.h"
#include "ExternLayer.h"
#include "pass/adhocpass.h"
#include "compilation/targetinterpretation.h"
#include "pass/versionspass.h"
#include "compilation/scopedecorators.h"
#include "compilation/adhocfunctiondecorator.h"
#include "compilation/operators.h"
#include "analysis/typeinference.h"
#include <boost/optional.hpp>
#include <memory>
#include <iostream>
using namespace std;
using namespace llvm;
-//TODO use Scope<TargetLlvm>
-
- //SECTIONTAG late-context FunctionDecorator
-
-namespace xreate{namespace context{
-
-/** \brief Late Context enabled decorator for IFunctionUnit
- * \extends IFunctionUnit
- */
-template<class Parent>
-class LateContextFunctionDecorator : public Parent {
-public:
- LateContextFunctionDecorator(ManagedFnPtr f, CompilePass* p)
- : Parent(f, p), contextCompiler(this, p) {
- }
-
-protected:
- std::vector<llvm::Type*> prepareArguments() {
- std::vector<llvm::Type*>&& arguments = Parent::prepareArguments();
-
- size_t sizeLateContextDemand = contextCompiler.getFunctionDemandSize();
- if (sizeLateContextDemand) {
- llvm::Type* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext());
- llvm::Type* tyDemand = llvm::ArrayType::get(ty32, sizeLateContextDemand);
-
- arguments.push_back(tyDemand);
- }
-
- return arguments;
- }
-
- llvm::Function::arg_iterator prepareBindings() {
- llvm::Function::arg_iterator fargsI = Parent::prepareBindings();
-
- size_t sizeLateContextDemand = contextCompiler.getFunctionDemandSize();
- if (sizeLateContextDemand) {
- fargsI->setName("latecontext");
- contextCompiler.rawContextArgument = &*fargsI;
- ++fargsI;
- }
-
- return fargsI;
- }
-
-public:
- context::LateContextCompiler2 contextCompiler;
-};
-
-}} //end of namespace xreate::context
-
namespace xreate { namespace compilation{
std::string
BasicFunctionUnit::prepareName(){
AST* ast = IFunctionUnit::pass->man->root;
string name = ast->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 context::LateContextFunctionDecorator<
- adhoc::AdhocFunctionDecorator<
- BasicFunctionUnit>> DefaultFunctionUnit;
+typedef adhoc::AdhocFunctionDecorator<
+ 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;
}
-//TASK Isolate out context functionalty in decorator
-//TOTEST static late context decisions
-//TOTEST dynamic late context decisions
ICallStatement*
BasicCodeScopeUnit::findFunction(const Expression& opCall) {
const std::string& calleeName = opCall.getValueString();
LLVMLayer* llvm = pass->man->llvm;
- ClaspLayer* clasp = pass->man->clasp;
- DefaultFunctionUnit* function = dynamic_cast<DefaultFunctionUnit*> (this->function);
- context::ContextQuery* queryContext = pass->queryContext;
-
const std::list<ManagedFnPtr>& specializations = pass->man->root->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);
}
- //no decisions required
- if (specializations.size() == 1) {
- if (!specializations.front()->guardContext.isValid()) {
- return new CallStatementRaw(pass->getFunctionUnit(specializations.front())->compile(), llvm);
- }
- }
-
- //TODO move dictSpecialization over to a separate function in order to perform cache, etc.
- //prepare specializations dictionary
- std::map<Expression, ManagedFnPtr> dictSpecializations;
-
- boost::optional<ManagedFnPtr> variantDefault;
- boost::optional<ManagedFnPtr> variant;
-
- for (const ManagedFnPtr& f : specializations) {
- const Expression& guard = f->guardContext;
-
- //default case:
- if (!guard.isValid()) {
- variantDefault = f;
- continue;
- }
-
- assert(dictSpecializations.emplace(guard, f).second && "Found several identical specializations");
- }
-
- //check static context
- ScopePacked scopeCaller = clasp->pack(this->scope);
- const string atomSpecialization = "specialization";
- const Expression topicSpecialization(Operator::CALL,{(Atom<Identifier_t>(string(atomSpecialization))),
- Expression(Operator::CALL,
- {Atom<Identifier_t>(string(calleeName))}),
- Atom<Number_t>(scopeCaller)});
-
- const context::Decisions& decisions = queryContext->getFinalDecisions(scopeCaller);
- if (decisions.count(topicSpecialization)) {
- variant = dictSpecializations.at(decisions.at(topicSpecialization));
- }
-
- //TODO check only demand for this particular topic.
- size_t sizeDemand = function->contextCompiler.getFunctionDemandSize();
-
- //decision made if static context found or no late context exists(and there is default variant)
- bool flagHasStaticDecision = variant || (variantDefault && !sizeDemand);
-
- //if no late context exists
- if (flagHasStaticDecision) {
- IFunctionUnit* calleeUnit = pass->getFunctionUnit(variant ? *variant : *variantDefault);
-
- //inlining possible based on static decision only
- // if (calleeUnit->isInline()) {
- // return new CallStatementInline(function, calleeUnit);
- // }
-
- return new CallStatementRaw(calleeUnit->compile(), llvm);
- }
-
- //require default variant if no static decision made
- assert(variantDefault);
-
- llvm::Function* functionVariantDefault = this->pass->getFunctionUnit(*variantDefault)->compile();
- llvm::Value* resultFn = function->contextCompiler.findFunction(calleeName, functionVariantDefault, scopeCaller);
- llvm::PointerType *resultPTy = cast<llvm::PointerType>(resultFn->getType());
- llvm::FunctionType *resultFTy = cast<llvm::FunctionType>(resultPTy->getElementType());
- return new CallStatementRaw(resultFn, resultFTy, llvm);
+ //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);
}
);
- ScopePacked outerScopeId = pass->man->clasp->pack(this->scope);
-
- //TASK a) refactor CALL/ADHOC/find function
- //SECTIONTAG late-context propagation arg
- size_t calleeDemandSize = pass->queryContext->getFunctionDemand(nameCallee).size();
- if (calleeDemandSize) {
- DefaultFunctionUnit* function = dynamic_cast<DefaultFunctionUnit*> (this->function);
- llvm::Value* argLateContext = function->contextCompiler.compileContextArgument(nameCallee, outerScopeId);
- args.push_back(argLateContext);
- }
-
return (*callee)(move(args), DEFAULT("res_" + nameCallee));
}
case Operator::IF:
{
return instructions.compileIf(expr, DEFAULT("tmp_if"));
}
case Operator::SWITCH:
{
return instructions.compileSwitch(expr, DEFAULT("tmp_switch"));
}
case Operator::LOOP_CONTEXT:
{
assert(false);
return nullptr;
//return instructions.compileLoopContext(expr, DEFAULT("tmp_loop"));
}
case Operator::LOGIC_AND:
{
assert(expr.operands.size() == 1);
return process(expr.operands[0]);
}
case Operator::LIST:
{
return instructions.compileListAsSolidArray(expr, DEFAULT("tmp_list"));
};
case Operator::LIST_RANGE:
{
assert(false); //no compilation phase for a range list
// return InstructionList(this).compileConstantArray(expr, l, hintRetVar);
};
case Operator::LIST_NAMED:
{
typedef Expanded<TypeAnnotation> ExpandedType;
ExpandedType tyStructLiteral = l.ast->getType(expr);
const std::vector<string> fieldsFormal = (tyStructLiteral.get().__operator == TypeOperator::CUSTOM) ?
l.layerExtern->getStructFields(l.layerExtern->lookupType(tyStructLiteral.get().__valueCustom))
: tyStructLiteral.get().fields;
std::map<std::string, size_t> indexFields;
for (size_t i = 0, size = fieldsFormal.size(); i < size; ++i) {
indexFields.emplace(fieldsFormal[i], i);
}
llvm::StructType* tyLiteralRaw = llvm::cast<llvm::StructType>(l.toLLVMType(tyStructLiteral));
llvm::Value* record = llvm::UndefValue::get(tyLiteralRaw);
for (size_t i = 0; i < expr.operands.size(); ++i) {
const Expression& operand = expr.operands.at(i);
unsigned int fieldId = indexFields.at(expr.bindings.at(i));
llvm::Value* result = 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);
}
};
//SECTIONTAG adhoc actual compilation
//TODO a) make sure that it's correct: function->adhocImplementation built for Entry scope and used in another scope
case Operator::ADHOC:
{
DefaultFunctionUnit* function = dynamic_cast<DefaultFunctionUnit*> (this->function);
assert(function->adhocImplementation && "Adhoc implementation not found");
const Expression& comm = adhoc::AdhocExpression(expr).getCommand();
CodeScope* scope = function->adhocImplementation->getCommandImplementation(comm);
ICodeScopeUnit* unitScope = function->getScopeUnit(scope);
//SECTIONTAG types/convert ADHOC ret convertation
llvm::Type* resultTy = l.toLLVMType(pass->man->root->expandType(function->adhocImplementation->getResultType()));
return typeinference::doAutomaticTypeConversion(unitScope->compile(), resultTy, l.builder);
};
case Operator::CALL_INTRINSIC:
{
const std::string op = expr.getValueString();
if (op == "copy") {
llvm::Value* result = process(expr.getOperands().at(0));
auto decoratorVersions = Decorators<VersionsScopeDecoratorTag>::getInterface(this);
llvm::Value* storage = decoratorVersions->processIntrinsicInit(result->getType());
decoratorVersions->processIntrinsicCopy(result, storage);
return l.builder.CreateLoad(storage, hintVarDecl);
}
assert(false && "undefined intrinsic");
}
case Operator::VARIANT:
{
const ExpandedType& typVariant = pass->man->root->getType(expr);
llvm::Type* typVariantRaw = l.toLLVMType(typVariant);
llvm::Type* typIdRaw = llvm::cast<llvm::StructType>(typVariantRaw)->getElementType(0);
uint64_t id = expr.getValueDouble();
llvm::Value* variantRaw = llvm::UndefValue::get(typVariantRaw);
variantRaw = l.builder.CreateInsertValue(variantRaw, llvm::ConstantInt::get(typIdRaw, id), llvm::ArrayRef<unsigned>({0}));
const bool flagDoReference = expr.operands.size();
if (flagDoReference){
const ExpandedType& subtyp = ExpandedType(typVariant->__operands.at(id));
llvm::Type* subtypRaw = l.toLLVMType(subtyp);
Attachments::put<TypeInferred>(expr.operands.at(0), subtyp);
llvm::Value* subtypValue = process(expr.operands.at(0));
llvm::Type* typStorageRaw = llvm::cast<llvm::StructType>(typVariantRaw)->getElementType(1);
llvm::Value* addrAsStorage = l.builder.CreateAlloca(typStorageRaw);
llvm::Value* addrAsSubtyp = l.builder.CreateBitOrPointerCast(addrAsStorage, subtypRaw->getPointerTo());
l.builder.CreateStore(subtypValue, addrAsSubtyp);
llvm::Value* storageRaw = l.builder.CreateLoad(typStorageRaw, addrAsStorage);
variantRaw = l.builder.CreateInsertValue(variantRaw, storageRaw, llvm::ArrayRef<unsigned>({1}));
}
return variantRaw;
}
case Operator::SWITCH_VARIANT:
{
return instructions.compileSwitchVariant(expr, DEFAULT("tmpswitch"));
}
case Operator::SEQUENCE: {
return instructions.compileSequence(expr);
}
case Operator::UNDEF: {
llvm::Type* typExprUndef = l.toLLVMType(typeinference::getType(expr, *pass->man->root));
return llvm::UndefValue::get(typExprUndef);
}
case Operator::INVALID:
assert(expr.__state != Expression::COMPOUND);
switch (expr.__state) {
case Expression::IDENT:
{
Symbol s = Attachments::get<IdentifierSymbol>(expr);
return processSymbol(s, expr.getValueString());
}
case Expression::NUMBER:
{
llvm::Type* typConst = l.toLLVMType(typeinference::getType(expr, *pass->man->root));
int literal = expr.getValueDouble();
return llvm::ConstantInt::get(typConst, literal);
}
case Expression::STRING:
{
return instructions.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str"));
};
default:
{
break;
}
};
break;
default: break;
}
assert(false && "Can't compile expression");
return 0;
}
llvm::Value*
BasicCodeScopeUnit::compile(const std::string& hintBlockDecl) {
if (!hintBlockDecl.empty()) {
llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm::getGlobalContext(), hintBlockDecl, function->raw);
pass->man->llvm->builder.SetInsertPoint(block);
}
currentBlockRaw = pass->man->llvm->builder.GetInsertBlock();
Symbol symbScope = Symbol{ScopedSymbol::RetSymbol, scope};
return processSymbol(symbScope);
}
ICodeScopeUnit::~ICodeScopeUnit() {
}
IFunctionUnit::~IFunctionUnit() {
}
llvm::Function*
IFunctionUnit::compile() {
if (raw != nullptr) return raw;
LLVMLayer* llvm = pass->man->llvm;
llvm::IRBuilder<>& builder = llvm->builder;
string&& functionName = prepareName();
std::vector<llvm::Type*>&& types = prepareArguments();
llvm::Type* expectedResultType = prepareResult();
llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false);
raw = llvm::cast<llvm::Function>(llvm->module->getOrInsertFunction(functionName, ft));
prepareBindings();
const std::string&blockName = "entry";
llvm::BasicBlock* blockCurrent = builder.GetInsertBlock();
llvm::Value* result = getScopeUnit(function->__entry)->compile(blockName);
assert(result);
//SECTIONTAG types/convert function ret value
builder.CreateRet(typeinference::doAutomaticTypeConversion(result, expectedResultType, llvm->builder));
if (blockCurrent) {
builder.SetInsertPoint(blockCurrent);
}
llvm->moveToGarbage(ft);
return raw;
}
ICodeScopeUnit*
IFunctionUnit::getScopeUnit(const CodeScope * const scope) {
if (__scopes.count(scope)) {
auto result = __scopes.at(scope).lock();
if (result) {
return result.get();
}
}
std::shared_ptr<ICodeScopeUnit> unit(pass->buildCodeScopeUnit(scope, this));
if (scope->__parent != nullptr) {
auto parentUnit = Decorators<CachedScopeDecoratorTag>::getInterface(getScopeUnit(scope->__parent));
parentUnit->registerChildScope(unit);
} else {
__orphanedScopes.push_back(unit);
}
if (!__scopes.emplace(scope, unit).second) {
__scopes[scope] = unit;
}
return unit.get();
}
ICodeScopeUnit*
IFunctionUnit::getScopeUnit(ManagedScpPtr scope) {
return getScopeUnit(&*scope);
}
ICodeScopeUnit*
IFunctionUnit::getEntry() {
return getScopeUnit(function->getEntryScope());
}
template<>
compilation::IFunctionUnit*
CompilePassCustomDecorators<void, void>::buildFunctionUnit(const ManagedFnPtr& function){
return new DefaultFunctionUnit(function, this);
}
template<>
compilation::ICodeScopeUnit*
CompilePassCustomDecorators<void, void>::buildCodeScopeUnit(const CodeScope* const scope, IFunctionUnit* function){
return new DefaultCodeScopeUnit(scope, function, this);
}
} // emf of compilation
IFunctionUnit*
CompilePass::getFunctionUnit(const ManagedFnPtr& function) {
unsigned int id = function.id();
if (!functions.count(id)) {
IFunctionUnit* unit = buildFunctionUnit(function);
functions.emplace(id, unit);
return unit;
}
return functions.at(id);
}
void
CompilePass::run() {
managerTransformations = new TransformationsManager();
targetInterpretation = new interpretation::TargetInterpretation(this->man->root, this);
queryContext = reinterpret_cast<context::ContextQuery*> (man->clasp->getQuery(QueryId::ContextQuery));
//Find out main function;
ClaspLayer::ModelFragment model = man->clasp->query(Config::get("function-entry"));
assert(model && "Error: No entry function found");
assert(model->first != model->second && "Error: Ambiguous entry function");
string nameMain = std::get<0>(ClaspLayer::parse<std::string>(model->first->second));
IFunctionUnit* unitMain = getFunctionUnit(man->root->findFunction(nameMain));
entry = unitMain->compile();
}
llvm::Function*
CompilePass::getEntryFunction() {
assert(entry);
return entry;
}
void
CompilePass::prepareQueries(ClaspLayer* clasp) {
clasp->registerQuery(new containers::Query(), QueryId::ContainersQuery);
clasp->registerQuery(new context::ContextQuery(), QueryId::ContextQuery);
Attachments::init<PolymorphGuard>();
clasp->registerQuery(new polymorph::PolymorphQuery(), QueryId::PolymorphQuery);
}
} //end of namespace xreate
/**
* \class xreate::CompilePass
* \brief Encapsulates all compilation activities
*
* xreate::CompilePass iterates over xreate::AST tree and produces executable code fed by data(via xreate::Attachments) gathered by previous passes as well as data via queries(xreate::IQuery) from xreate:ClaspLayer reasoner.
* Compilation's done using xreate::LLVMLayer(wrapper over LLVM toolchain) and based on following aspects:
* - Containers support. See \ref compilation/containers.h
* - Late Conext compilation. See xreate::context::LateContextCompiler2
* - Interpretation support. See xreate::interpretation::TargetInterpretation
* - Loop saturation support. See xreate::compilation::TransformerSaturation
* - External Code access. See xreate::ExternLayer(wrapper over Clang library)
*
* \section adaptability_sect Adaptability
* xreate::CompilePass's architecture provides adaptability by employing:
* - %Function Decorators to alter function-level compilation. See xreate::compilation::IFunctionUnit
* - Code Block Decorators to alter code block level compilation. See xreate::compilation::ICodeScopeUnit
* Default functionality defined by \ref xreate::compilation::DefaultCodeScopeUnit
* - Targets to allow more versitile extensions.
* Currently only xreate::interpretation::TargetInterpretation use Targets infrastructure. See xreate::compilation::Target
* - %Altering Function invocation. xreate::compilation::ICallStatement
*
* Client able to construct compiler with desired decorators using xreate::compilation::CompilePassCustomDecorators.
* As a handy alias, `CompilePassCustomDecorators<void, void>` constructs default compiler
*
*/
diff --git a/cpp/src/pass/dfapass.cpp b/cpp/src/pass/dfapass.cpp
index 8958eb0..c1b34c0 100644
--- a/cpp/src/pass/dfapass.cpp
+++ b/cpp/src/pass/dfapass.cpp
@@ -1,242 +1,234 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Author: pgess <v.melnychenko@xreate.org>
*
* dfapass.cpp
*/
/**
* \file dfapass.h
* \brief Data Flow Analysis(DFA)
*/
//DEBT DFA represent VersionaPass in declarative form using applyDependencies
// applyDependencies(expression, context, cache, decl);
//DEBT DFA prepare static annotations and represent InterpretationPass in declarative form
// applyStaticAnnotations(expression, context, cache, decl);
//DEBT DFA Eliminate dfa schemes
#include "pass/dfapass.h"
#include "xreatemanager.h"
#include "clasplayer.h"
#include <boost/format.hpp>
#include <boost/variant/variant.hpp>
using namespace std;
namespace xreate {namespace dfa {
DFAPass::DFAPass(PassManager* manager)
: AbstractPass(manager)
, graph{new DFAGraph()}
, clasp(manager->clasp) { }
void
DFAPass::processCallInstance(const Expression& expr, PassContext context, const SymbolNode& result) {
const string &nameCalleeFunction=expr.getValueString();
//TODO implement processFnCall/Uncertain
list<ManagedFnPtr> variantsCalleeFunction=man->root->getFunctionSpecializations(nameCalleeFunction);
vector<SymbolNode> operands;
operands.reserve(expr.getOperands().size());
for(const Expression& arg : expr.getOperands()) {
operands.push_back(process(arg, context));
}
//Set calling relations:
DFACallInstanceType type=variantsCalleeFunction.size()>1?WEAK:STRONG;
for(ManagedFnPtr function : variantsCalleeFunction) {
CodeScope *scopeRemote=function->getEntryScope();
DFACallInstance callInstance;
callInstance.id=expr.id;
callInstance.fnName=function->getName();
callInstance.type=type;
std::vector<SymbolNode>::const_iterator nodeActual=operands.begin();
for(const std::string &identFormal : scopeRemote->__bindings) {
const ScopedSymbol symbolFormal{scopeRemote->__identifiers.at(identFormal), versions::VERSION_NONE};
SymbolPacked symbolFormalPacked=clasp->pack(Symbol{symbolFormal, scopeRemote}, nameCalleeFunction+":"+identFormal);
callInstance.args.push_back(std::make_pair(symbolFormalPacked, *nodeActual));
++nodeActual;
}
callInstance.retActual=result;
SymbolNode retFormal=SymbolNode(clasp->pack(Symbol{ScopedSymbol::RetSymbol, scopeRemote}, nameCalleeFunction+":[ret]"));
graph->addCallInstance(std::move(callInstance));
}
}
void
DFAPass::processDependencies(const SymbolNode& node, const Expression& expression, PassContext context, ProcessingCache& cache) {
cache.operands.reserve(expression.getOperands().size());
for(const Expression &op : expression.getOperands()) {
const SymbolNode& subnodeOperand=process(op, context);
cache.operands.push_back(subnodeOperand);
graph->addDependency(node, subnodeOperand);
}
cache.blocks.reserve(expression.blocks.size());
for(CodeScope* block : expression.blocks) {
const SymbolNode& subnodeBlock=process(block, context);
cache.blocks.push_back(subnodeBlock);
graph->addDependency(node, subnodeBlock);
}
}
SymbolNode
DFAPass::process(const Expression& expression, PassContext context, const std::string& varDecl) {
SymbolNode result;
if(Attachments::exists<SymbolAlias>(expression)){
Symbol varSymbol=Attachments::get<SymbolAlias>(expression);
result=clasp->pack(varSymbol, varDecl);
} else if(expression.__state==Expression::IDENT&&expression.tags.size()==0){
Symbol varSymbol=Attachments::get<IdentifierSymbol>(expression);
result=clasp->pack(varSymbol, expression.getValueString());
} else {
result=SymbolAnonymous{expression.id};
}
graph->printInplaceAnnotations(result, expression);
switch(expression.__state) {
- case Expression::COMPOUND:
- {
+ case Expression::COMPOUND: {
switch(expression.op) {
- case Operator::CALL:
- {
+ case Operator::CALL: {
processCallInstance(expression, context, result);
break;
}
- case Operator::IF:
- {
+ 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:
- {
+ 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:
- {
+ default: {
ProcessingCache cache;
processDependencies(result, expression, context, cache);
break;
}
}
break;
}
- case Expression::IDENT:
- {
+ 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:
- {
+ case Expression::STRING: {
break;
}
case Expression::INVALID:
- case Expression::BINDING:
- {
+ case Expression::BINDING: {
assert(false);
break;
}
}
return result;
}
SymbolNode
DFAPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl) {
if (!hintBlockDecl.empty()) {
Symbol symbRet{ScopedSymbol::RetSymbol, scope};
clasp->pack(symbRet, hintBlockDecl + ":[ret]");
}
for(const std::string& binding : scope->__bindings) {
Symbol bindingSymbol{scope->getSymbol(binding), scope};
SymbolPacked bindingPacked=clasp->pack(bindingSymbol, binding);
getSymbolCache().setCachedValue(bindingSymbol, SymbolNode(bindingPacked));
}
return AbstractPass<SymbolNode>::process(scope, context, hintBlockDecl);
}
SymbolNode
DFAPass::process(ManagedFnPtr function) {
clasp->pack(Symbol{ScopedSymbol::RetSymbol, function->getEntryScope()}, function->getName()+to_string(function.id())+":[ret]");
SymbolNode result=AbstractPass<SymbolNode>::process(function);
graph->printFunctionRet(function, result);
return result;
}
void
DFAPass::finish() {
clasp->registerReport(graph);
//Declare symbols:
graph->printSymbols(clasp);
AbstractPass::finish();
}
} //end of namespace dfa
template<>
dfa::SymbolNode
defaultValue() {
assert(false);
}
-} //xreate namespace
+} //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/interpretationpass.cpp b/cpp/src/pass/interpretationpass.cpp
index 89bf2fc..5e75aea 100644
--- a/cpp/src/pass/interpretationpass.cpp
+++ b/cpp/src/pass/interpretationpass.cpp
@@ -1,522 +1,525 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: interpretationpass.cpp
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on July 5, 2016, 5:21 PM
*/
/**
* \file interpretationpass.h
* \brief Interpretation analysis: determines what parts of code could be interpreted
*/
#include "pass/interpretationpass.h"
#include <compilation/targetinterpretation.h>
#include <bits/stl_vector.h>
#include "ast.h"
//DEBT implement InterpretationPass purely in clasp
//DEBT represent InterpretationPass as general type inference
using namespace std;
namespace xreate {
template<>
interpretation::InterpretationResolution
defaultValue<interpretation::InterpretationResolution>() {
return interpretation::CMPL_ONLY;
}
namespace interpretation {
enum InterpretationQuery {
QUERY_INTR_ONLY, QUERY_CMPL_ONLY
};
namespace details {
template<InterpretationQuery FLAG_REQUIRED>
bool
checkConstraints(InterpretationResolution flag) {
return( (flag==INTR_ONLY&&FLAG_REQUIRED==QUERY_INTR_ONLY)
||(flag==CMPL_ONLY&&FLAG_REQUIRED==QUERY_CMPL_ONLY));
}
InterpretationResolution
recognizeTags(const map<std::string, Expression>& tags) {
auto i=tags.find("interpretation");
if(i==tags.end()){
return ANY;
}
assert(i->second.op==Operator::CALL);
const string& cmd=i->second.operands.at(0).getValueString();
//TODO make consistent names of annotation and resolution
if(cmd=="force"){
return INTR_ONLY;
} else if(cmd=="suppress"){
return CMPL_ONLY;
}
return ANY;
}
}
InterpretationResolution
unify(InterpretationResolution flag) {
return flag;
}
template<typename FLAG_A, typename FLAG_B, typename... FLAGS>
InterpretationResolution
unify(FLAG_A flagA, FLAG_B flagB, FLAGS... flags) {
if(flagA==ANY){
return unify(flagB, flags...);
}
if(flagB==ANY){
return unify(flagA, flags...);
}
assert(flagA==flagB);
return flagA;
}
template<InterpretationQuery FLAG_REQUIRED>
bool
checkConstraints(std::vector<InterpretationResolution>&& flags) {
assert(flags.size());
InterpretationResolution flag=flags.front();
return details::checkConstraints<FLAG_REQUIRED>(flag);
}
template<InterpretationQuery FLAG_REQUIRED_A, InterpretationQuery FLAG_REQUIRED_B, InterpretationQuery... FLAGS>
bool
checkConstraints(std::vector<InterpretationResolution>&& flags) {
assert(flags.size());
InterpretationResolution flag=flags.front();
flags.pop_back();
if(details::checkConstraints<FLAG_REQUIRED_A>(flag)){
return checkConstraints<FLAG_REQUIRED_B, FLAGS...>(move(flags));
}
return false;
}
bool
InterpretationData::isDefault() const {
return(resolution==ANY&&op==NONE);
}
void
recognizeTags(const Expression& e) {
InterpretationData tag{details::recognizeTags(e.tags), NONE};
if(!tag.isDefault())
Attachments::put<InterpretationData>(e, tag);
}
InterpretationResolution
recognizeTags(const ManagedFnPtr& f) {
return details::recognizeTags(f->getTags());
}
InterpretationPass::InterpretationPass(PassManager* manager)
: AbstractPass(manager) {
Attachments::init<FunctionInterpretationData>();
Attachments::init<InterpretationData>();
}
void
InterpretationPass::run() {
ManagedFnPtr f=man->root->begin<Function>();
auto& visitedSymbols=getSymbolCache();
while(f.isValid()) {
const Symbol&symbolFunction{ScopedSymbol::RetSymbol, f->getEntryScope()};
if(!visitedSymbols.isCached(symbolFunction)){
visitedSymbols.setCachedValue(symbolFunction, process(f));
}
++f;
}
}
InterpretationResolution
InterpretationPass::process(const Expression& expression, PassContext context, const std::string& decl) {
recognizeTags(expression);
InterpretationResolution resolution=ANY;
InterpretationOperator op=NONE;
switch(expression.__state) {
case Expression::NUMBER:
case Expression::STRING:
{
break;
}
case Expression::IDENT:
{
resolution=Parent::processSymbol(Attachments::get<IdentifierSymbol>(expression), context);
break;
}
case Expression::COMPOUND:
break;
default:
{
resolution=CMPL_ONLY;
break;
}
}
if(expression.__state==Expression::COMPOUND)
switch(expression.op) {
case Operator::EQU:
case Operator::NE:
{
InterpretationResolution left=process(expression.operands[0], context);
InterpretationResolution right=process(expression.operands[1], context);
resolution=unify(left, right);
break;
}
case Operator::LOGIC_AND:
{
assert(expression.operands.size()==1);
resolution=process(expression.operands[0], context);
break;
}
case Operator::CALL:
{
//TODO cope with static/dynamic context
- //TODO BUG here: if several variants they all are processed as CMPL careless of signature
+ //TODO BUG here: if several variants they all are processed as CMPL regardless of signature
list<ManagedFnPtr> callees=man->root->getFunctionSpecializations(expression.getValueString());
if(callees.size()!=1){
resolution=CMPL_ONLY;
break;
}
ManagedFnPtr callee=callees.front();
- const Symbol&symbCalleeFunc{ScopedSymbol::RetSymbol, callee->getEntryScope()};
+ const Symbol& symbCalleeFunc{ScopedSymbol::RetSymbol, callee->getEntryScope()};
//recursion-aware processing:
// - skip self recursion
const Symbol&symbSelfFunc{ScopedSymbol::RetSymbol, context.function->getEntryScope()};
if(!(symbSelfFunc==symbCalleeFunc)){
InterpretationResolution resCallee=processFnCall(callee, context);
assert(resCallee!=FUNC_POSTPONED&&"Indirect recursion detected: can't decide on interpretation resolution");
resolution=unify(resolution, resCallee);
}
//check arguments compatibility
const FunctionInterpretationData& calleeSignature=FunctionInterpretationHelper::getSignature(callee);
for(size_t op=0, size=expression.operands.size(); op<size; ++op) {
const Expression &operand=expression.operands[op];
InterpretationResolution argActual=process(operand, context);
InterpretationResolution argExpected=calleeSignature.signature[op];
//TODO use args unification result to properly process function call
unify(argActual, argExpected);
}
if(FunctionInterpretationHelper::needPartialInterpretation(callee)){
op=CALL_INTERPRET_PARTIAL;
}
break;
}
case Operator::CALL_INTRINSIC:
{
std::string nameFunction=expression.getValueString();
if(nameFunction=="query"){
resolution=INTR_ONLY;
+ } else if(nameFunction=="query_scope") {
+ resolution=INTR_ONLY;
+
} else {
resolution=CMPL_ONLY;
}
break;
}
case Operator::IF:
{
InterpretationResolution flagCondition=process(expression.getOperands()[0], context);
InterpretationResolution flagScope1=Parent::process(expression.blocks.front(), context);
InterpretationResolution flagScope2=Parent::process(expression.blocks.back(), context);
//special case: IF_INTERPRET_CONDITION
if(checkConstraints<QUERY_INTR_ONLY>({flagCondition})){
op=IF_INTERPRET_CONDITION;
flagCondition=ANY;
}
resolution=unify(flagCondition, flagScope1, flagScope2);
break;
}
case Operator::FOLD:
{
InterpretationResolution flagInput=process(expression.getOperands()[0], context);
InterpretationResolution flagAccumInit=process(expression.getOperands()[1], context);
CodeScope* scopeBody=expression.blocks.front();
const std::string& nameEl=expression.bindings[0];
Symbol symbEl{ScopedSymbol
{scopeBody->__identifiers.at(nameEl), versions::VERSION_NONE}, scopeBody};
getSymbolCache().setCachedValue(symbEl, InterpretationResolution(flagInput));
const std::string& nameAccum=expression.bindings[1];
Symbol symbAccum{ScopedSymbol
{scopeBody->__identifiers.at(nameAccum), versions::VERSION_NONE}, scopeBody};
getSymbolCache().setCachedValue(symbAccum, InterpretationResolution(flagAccumInit));
InterpretationResolution flagBody=Parent::process(expression.blocks.front(), context);
//special case: FOLD_INTERPRET_INPUT
if(checkConstraints<QUERY_INTR_ONLY>({flagInput})){
op=FOLD_INTERPRET_INPUT;
flagInput=ANY;
}
resolution=unify(flagInput, flagAccumInit, flagBody);
break;
}
case Operator::INDEX:
{
for(const Expression &op : expression.getOperands()) {
resolution=unify(resolution, process(op, context));
}
break;
}
case Operator::SWITCH:
{
InterpretationResolution flagCondition=process(expression.operands[0], context);
bool hasDefaultCase=expression.operands[1].op==Operator::CASE_DEFAULT;
//determine conditions resolution
InterpretationResolution flagHeaders=flagCondition;
for(size_t size=expression.operands.size(), i=hasDefaultCase?2:1; i<size; ++i) {
const Expression& exprCase=expression.operands[i];
flagHeaders=unify(flagHeaders, Parent::process(exprCase.blocks.front(), context));
}
if(checkConstraints<QUERY_INTR_ONLY>({flagHeaders})){
op=SWITCH_INTERPRET_CONDITION;
flagHeaders=ANY;
}
//determine body resolutions
resolution=flagHeaders;
for(size_t size=expression.operands.size(), i=1; i<size; ++i) {
const Expression& exprCase=expression.operands[i];
resolution=unify(resolution, Parent::process(exprCase.blocks.back(), context));
}
break;
}
case Operator::SWITCH_VARIANT:
{
InterpretationResolution resolutionCondition=process(expression.operands.at(0), context);
resolution=resolutionCondition;
if(checkConstraints<QUERY_INTR_ONLY>({resolution})){
op=SWITCH_VARIANT;
resolution=ANY;
}
const string identCondition=expression.bindings.front();
for(auto scope : expression.blocks) {
//set binding resolution
ScopedSymbol symbolInternal=scope->getSymbol(identCondition);
getSymbolCache().setCachedValue(Symbol{symbolInternal, scope}, InterpretationResolution(resolutionCondition));
resolution=unify(resolution, Parent::process(scope, context));
}
for(auto scope : expression.blocks) {
resolution=unify(resolution, Parent::process(scope, context));
}
break;
}
case Operator::LIST:
case Operator::LIST_NAMED:
{
for(const Expression &op : expression.getOperands()) {
resolution=unify(resolution, process(op, context));
}
break;
}
case Operator::VARIANT:
{
if(expression.getOperands().size()){
resolution=process(expression.getOperands().front(), context);
} else {
resolution=ANY;
}
break;
}
default:
{
resolution=CMPL_ONLY;
for(const Expression &op : expression.getOperands()) {
process(op, context);
}
for(CodeScope* scope : expression.blocks) {
Parent::process(scope, context);
}
break;
}
}
- InterpretationResolution resolutionExpected=
- Attachments::get<InterpretationData>(expression,{ANY, NONE}).resolution;
+ InterpretationData dataExpected=
+ Attachments::get<InterpretationData>(expression,{ANY, NONE});
- resolution=unify(resolution, resolutionExpected);
- if(resolution!=resolutionExpected&&(op!=NONE||resolution==INTR_ONLY)){
+ resolution=unify(resolution, dataExpected.resolution);
+ if(resolution!=dataExpected.resolution || op != dataExpected.op ){
Attachments::put<InterpretationData>(expression,{resolution, op});
}
return resolution;
}
InterpretationResolution
InterpretationPass::processFnCall(ManagedFnPtr function, PassContext context) {
return process(function);
}
InterpretationResolution
InterpretationPass::process(ManagedFnPtr function) {
CodeScope* entry=function->getEntryScope();
std::vector<std::string> arguments=entry->__bindings;
const Symbol&symbSelfFunc{ScopedSymbol::RetSymbol, function->getEntryScope()};
auto& cache=getSymbolCache();
if(cache.isCached(symbSelfFunc))
return cache.getCachedValue(symbSelfFunc);
const FunctionInterpretationData& fnSignature=FunctionInterpretationHelper::getSignature(function);
InterpretationResolution fnResolutionExpected=details::recognizeTags(function->getTags());
//mark preliminary function resolution as expected
if(fnResolutionExpected!=ANY){
cache.setCachedValue(symbSelfFunc, move(fnResolutionExpected));
} else {
// - in order to recognize indirect recursion mark this function resolution as POSTPONED
cache.setCachedValue(symbSelfFunc, FUNC_POSTPONED);
}
//set resolution for function arguments as expected
for(int argNo=0, size=arguments.size(); argNo<size; ++argNo) {
Symbol symbArg{ScopedSymbol
{entry->__identifiers.at(arguments[argNo]), versions::VERSION_NONE}, entry};
cache.setCachedValue(symbArg, InterpretationResolution(fnSignature.signature[argNo]));
}
PassContext context;
context.function=function;
context.scope=entry;
InterpretationResolution resActual=process(CodeScope::getDefinition(symbSelfFunc), context);
resActual=unify(resActual, fnResolutionExpected);
return cache.setCachedValue(symbSelfFunc, move(resActual));
}
const FunctionInterpretationData
FunctionInterpretationHelper::getSignature(ManagedFnPtr function) {
if(Attachments::exists<FunctionInterpretationData>(function)){
return Attachments::get<FunctionInterpretationData>(function);
}
FunctionInterpretationData&& data=recognizeSignature(function);
Attachments::put<FunctionInterpretationData>(function, data);
return data;
}
FunctionInterpretationData
FunctionInterpretationHelper::recognizeSignature(ManagedFnPtr function) {
CodeScope* entry=function->__entry;
FunctionInterpretationData result;
result.signature.reserve(entry->__bindings.size());
bool flagPartialInterpretation=false;
for(size_t no=0, size=entry->__bindings.size(); no<size; ++no) {
const std::string& argName=entry->__bindings[no];
Symbol symbArg{ScopedSymbol
{entry->__identifiers.at(argName), versions::VERSION_NONE}, entry};
const Expression& arg=CodeScope::getDefinition(symbArg);
InterpretationResolution argResolution=details::recognizeTags(arg.tags);
flagPartialInterpretation|=(argResolution==INTR_ONLY);
result.signature.push_back(argResolution);
}
result.flagPartialInterpretation=flagPartialInterpretation;
return result;
}
bool
FunctionInterpretationHelper::needPartialInterpretation(ManagedFnPtr function) {
const FunctionInterpretationData& data=getSignature(function);
return data.flagPartialInterpretation;
}
}
} //end of namespace xreate::interpretation
/** \class xreate::interpretation::InterpretationPass
*
* Encapsulates *Interpretation Analysis* to support [Interpretation Concept](/w/concepts/dfa)
*
* Recognizes program functions, expressions, instructions eligible for interpretation
* and stores output in Attachments<FunctionInterpretationData> and Attachments<InterpretationData>
*
* There are number of instructions currently able to be interpreted:
* - Basic literals: numbers and strings
* - Compounds: lists, structs, variants
* - Non-versioned identifiers
* - Comparison and logic operators
* - %Function calls
* - `query` intrinsic function calls
* - Branching: `if`, `loop fold`, `switch`, `switch variant` statements
*
* Some of those instructions are eligibile for *hybrid interpretation* to allow coupling
* of compiled instructions with interpreted ones, those are:
* - Partial function calls
* - Branching: `if`, `loop fold`, `switch`, `switch variant` statements
*
* \sa xreate::interpretation::TargetInterpretation, [Interpretation Concept](/w/concepts/dfa)
*/
\ No newline at end of file
diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt
index b8605c3..fae4c99 100644
--- a/cpp/tests/CMakeLists.txt
+++ b/cpp/tests/CMakeLists.txt
@@ -1,55 +1,54 @@
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
+ virtualization.cpp
exploitation.cpp
communication.cpp
polymorph.cpp
association.cpp
main.cpp
modules.cpp
adhoc.cpp
attachments.cpp
ast.cpp
cfa.cpp
dfa.cpp
compilation.cpp
ExpressionSerializer.cpp
externc.cpp
- context.cpp
types.cpp
vendorAPI/clangAPI.cpp
vendorAPI/xml2.cpp
vendorAPI/json.cpp
containers.cpp
- context.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/adhoc.cpp b/cpp/tests/adhoc.cpp
index 72a565f..8e9578b 100644
--- a/cpp/tests/adhoc.cpp
+++ b/cpp/tests/adhoc.cpp
@@ -1,196 +1,196 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* adhoc-exceptions.cpp
*
* Created on: Nov 19, 2015
* Author: pgess <v.melnychenko@xreate.org>
*/
class Adhoc_pass_Adhoc1_Test;
#define FRIENDS_ADHOC \
friend class ::Adhoc_pass_Adhoc1_Test;
#include "ast.h"
#include "xreatemanager.h"
#include "gtest/gtest.h"
#include <stdio.h>
#include <memory>
#include <sstream>
#include <stdlib.h>
#include "pass/adhocpass.h"
#include "pass/compilepass.h"
#include "llvmlayer.h"
using namespace xreate;
using namespace xreate::adhoc;
using namespace std;
TEST(Adhoc, ast_operatorAdhoc1){
XreateManager* man = XreateManager::prepare (
"test = function:: int {\n"
" ad hoc exception(nonImplemented)\n"
"}");
const Expression& subject = man->root->findFunction("test")->getEntryScope()->getBody();
ASSERT_EQ(Operator::ADHOC, subject.op);
Expression exception = AdhocExpression(subject).getCommand();
ASSERT_EQ("exception", exception.getValueString());
}
TEST(Adhoc, ast_schemeAdhoc1){
XreateManager* man = XreateManager::prepare (
"interface(adhoc){\n"
" pre function expectNoErrors:: bool {\n"
" case (Error) {false}\n"
" case (Success) {true}\n"
" }\n"
" }");
assert(man->root->__interfacesData.count(ASTInterface::Adhoc));
Expression adhocData = man->root->__interfacesData.find(ASTInterface::Adhoc)->second;
ASSERT_EQ(Operator::SWITCH, adhocData.operands[0].op);
}
TEST(Adhoc, pass_Adhoc1){
details::tier1::XreateManager* man = details::tier1::XreateManager::prepare (
"interface(adhoc){\n"
" pre function expectNoErrors:: bool {\n"
" case (Error) {false}\n"
" case (Success) {true}\n"
" }\n"
"}\n"
"main = function::int; entry {0} \n"
);
man->analyse();
AdhocPass* pass = reinterpret_cast<AdhocPass* >(man->getPassById(PassId::AdhocPass));
EXPECT_TRUE(pass->__schemes.size() > 0);
AdhocScheme* scheme = pass->__schemes.begin()->second;
EXPECT_EQ("expectNoErrors", scheme->getName());
}
TEST(Adhoc, full_1){
XreateManager* man = XreateManager::prepare (
" import raw (\"core/control-context.lp\").\n"
" interface(adhoc){\n"
" pre function expectNoErrors:: bool {\n"
" case (error) {false}\n"
" case (success) {true}\n"
" }\n"
" }\n"
" test1 = pre function {\n"
" context:: expectNoErrors."
" ad hoc success\n"
" }"
"main = function::bool;entry {\n"
" test1()\n"
" }");
bool (*main)() = (bool (*)()) man->run();
bool result = main();
ASSERT_EQ(true, result);
}
TEST(Adhoc, full_2){
XreateManager* man = XreateManager::prepare (
" import raw (\"core/control-context.lp\").\n"
" interface(adhoc){\n"
" pre function expectNoErrors:: bool {\n"
" case (error) {false}\n"
" case (success) {true}\n"
" }\n"
" pre function expectErrors:: bool {\n"
" case (error) {true}\n"
" case (success) {false}\n"
" }\n"
" }\n"
" test1 = pre function {\n"
" context:: expectNoErrors."
" ad hoc success\n"
" }\n"
" test2 = pre function {\n"
" context:: expectErrors."
" ad hoc success\n"
" }"
"main = function::bool;entry {\n"
" test1() != test2()\n"
"}");
bool (*main)() = (bool (*)()) man->run();
bool result = main();
ASSERT_EQ(true, result);
}
//TODO adhoc type. FDecl sets wrong type in prefunc case(invalid type))
TEST(Adhoc, full_contextExpectNoErrrors){
XreateManager* man = XreateManager::prepare (
"import raw (\"core/control-context.lp\").\n"
"interface(extern-c){\n"
" xml2 = library:: pkgconfig(\"libxml-2.0\").\n"
" \n"
" include {\n"
" xml2 = [\"stdlib.h\"]\n"
" }.\n"
"}"
"interface(adhoc){\n"
" pre function expectNoErrors:: bool {\n"
" case (error) {false}\n"
" case (success) {true}\n"
" }\n"
"}\n"
"expectErrorCode = pre function(x::int){\n"
- " if (x==0)::undef {ad hoc success}\n"
+ " if (x==0)::unknType {ad hoc success}\n"
" else {ad hoc error}\n"
"}\n"
"main = function::bool; entry {\n"
" context:: expectNoErrors."
" expectErrorCode(system(\"ls -la\"))\n"
"}" );
int (*main)() = (int (*)()) man->run();
ASSERT_EQ(1, main());
}
//DEBT Implement compilation of switch adhoc
TEST(Adhoc, ast_switchAdhoc1){
XreateManager* man = XreateManager::prepare (
"test1 = function:: bool {\n"
" x = 0. \n"
" switch ad hoc (x:: errors)\n"
" case (error) {0}\n"
" case (success) {1}\n"
"\n"
"}"
);
const Expression& eSwitch = man->root->findFunction("test1")->getEntryScope()->getBody();
EXPECT_EQ(Operator::SWITCH_ADHOC, eSwitch.op);
EXPECT_EQ(3, eSwitch.operands.size());
EXPECT_EQ(1, eSwitch.tags.size());
EXPECT_EQ("errors", eSwitch.tags.begin()->first);
Expression eCondition = eSwitch.getOperands()[0];
EXPECT_EQ("x", eCondition.getValueString());
}
diff --git a/cpp/tests/association.cpp b/cpp/tests/association.cpp
index b243f67..4b9ed90 100644
--- a/cpp/tests/association.cpp
+++ b/cpp/tests/association.cpp
@@ -1,100 +1,129 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* association.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on August 12, 2017, 9:28 PM
*/
#include "xreatemanager.h"
#include "clasplayer.h"
#include <gtest/gtest.h>
using namespace xreate;
using namespace std;
TEST(Association, test1){
std::string controller=
R"Code(
program(add).
)Code";
std::string script=
R"Code(
Annotation = type variant {
Num:: int,
String:: string,
Func:: {name::string, arguments::[Annotation]}
}.
extractCmd = function(program::Annotation):: Annotation; interpretation(force){
switch variant(program)::Annotation
case (Num){String("wrong expression")}
case (String){String("wrong expression")}
case (Func){program["arguments"][0]}
}
main= function:: int; entry{
x= 5::int.
y = 6::int.
program = intrinsic query("program")[0]::Annotation.
cmd = extractCmd(program)::Annotation; interpretation(force).
answer = switch variant(cmd)::int
case (Num) {0}
case (String){0}
case (Func){
switch(cmd["name"])::int
case("add"){x + y}
case default {0}
}.
answer
}
)Code";
std::unique_ptr<XreateManager> man(XreateManager::prepare(std::move(script)));
man->clasp->addRawScript(move(controller));
int (*main)() = (int (*)())man->run();
int result = main();
ASSERT_EQ(11, result);
}
+TEST(Association, QueryScope1){
+std::string script = R"Code(
+ Annotation = type variant {
+ Num:: int,
+ String:: string,
+ Func:: {name::string, arguments::[Annotation]}
+ }.
+
+ func = function::int{10} //aux func in order to have few scopes
+
+ main = function:: int; entry {
+ scope = intrinsic query_scope()::Annotation.
+
+ answer = switch variant(scope):: int
+ case (Num) {scope}
+ case (String){-1}
+ case (Func){-1}.
+
+ answer
+ }
+
+)Code";
+
+ std::unique_ptr<XreateManager> man(XreateManager::prepare(std::move(script)));
+ int (*main)() = (int (*)())man->run();
+ int result = main();
+
+ ASSERT_EQ(1, result);
+}
//std::string script=
//R"Code(
//
//case context:: test1 {
//test= function::bool; registerTest {
// x = 8:: int.
//
// x == 8
//}}
//
//case context:: test2{
//test= function::bool{
// x = 3::int.
// y = 12::int.,
//
// (x+y) <> 25
//}}
//
//runTests= function::bool{
// tests = intrinsic query (registeredTests)::[Expression].
//
// loop fold(tests->test::Expression, true->result):: bool {
// shot = {
// context:: make context (test)
// test()
// }
//
// result and shot
// }
//}
//
//main= function:: int; entry{
// runTests()
//}
//)Code";
diff --git a/cpp/tests/context.cpp b/cpp/tests/context.cpp
deleted file mode 100644
index 3581303..0000000
--- a/cpp/tests/context.cpp
+++ /dev/null
@@ -1,497 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- *
- * frame-context.cpp
- *
- * Created on: Dec 3, 2015
- * Author: pgess <v.melnychenko@xreate.org>
- */
-
-#include "xreatemanager.h"
-#include "query/context.h"
-
-#include "gtest/gtest.h"
-#include <iostream>
-#include <boost/scoped_ptr.hpp>
-
-using namespace xreate;
-using namespace xreate::context;
-
-TEST(Context, frame_Context1){
- details::tier1::XreateManager* man = details::tier1::XreateManager::prepare(
- " import raw (\"core/control-context.lp\").\n"
- " compute = function::int {\n"
- " 0\n"
- " }\n"
-
- " computeFast = function:: int {\n"
- " context:: computation(fast).\n"
-
- " compute()\n"
- " }\n"
-
- " computePrecisely = function:: int {\n"
- " context:: computation(precise). \n"
-
- " compute()\n"
- " }\n"
-
- "test = function(cmnd:: int):: int; entry {\n"
- " context:: arithmetic(iee754). \n"
-
- " if (cmnd > 0)::int {computePrecisely()} else {computeFast()} \n"
- "}\n"
- );
-
- ContextQuery* query = (ContextQuery*) man->clasp->registerQuery(new ContextQuery(), QueryId::ContextQuery);
- man->analyse();
-
- CodeScope* scopeTestC = man->root->findFunction("compute")->getEntryScope();
- const Domain& context = query->getContext(man->clasp->pack(scopeTestC));
-
- int contextSize = context.size();
- EXPECT_EQ(1, contextSize);
-}
-
-TEST(Context, contextAsRequirementSuccessful1){
- XreateManager* man = XreateManager::prepare(
- " import raw (\"core/control-context.lp\").\n"
-
- " case context::safe {\n"
- " funcSensitive = function::int {\n"
- " 0\n"
- " }}\n"
-
- " test = function:: int; entry {\n"
- " context:: safe; test.\n"
-
- " funcSensitive()\n"
- " }\n"
- );
-
- int (*main)() = (int (*)()) man->run();
- ASSERT_EQ(0, main());
-}
-
-TEST(Context, contextAsRequirementFailed){
- XreateManager* man = XreateManager::prepare(
- " import raw (\"core/control-context.lp\").\n"
-
- " case context::safe {\n"
- " funcSensitive = function::int {\n"
- " 0\n"
- " }}\n"
-
- " test = function:: int; entry {\n"
- " context:: non_safe; test.\n"
-
- " funcSensitive()\n"
- " }\n"
- );
-
- ASSERT_DEATH(man->run(), "findFunction");
-}
-
-TEST(Context, ContextPropagationNested){
- XreateManager* man = XreateManager::prepare(
- " import raw (\"core/control-context.lp\").\n"
-
- " case context::safe {\n"
- " square = function(x:: int) ::int {\n"
- " x * x\n"
- " }}\n"
-
- " test = function:: int; entry {\n"
- " context:: safe; test.\n"
-
- " range = [1..10]:: [int]. \n"
- " loop fold(range->x::int, 0->acc):: int { \n"
- " acc + square(x) \n"
- " } \n"
- " }\n"
- );
-
- int (*main)() = (int (*)()) man->run();
- ASSERT_EQ(385, main());
-}
-
-TEST(Context, ContextPropagationNestedInterfunction){
-
- XreateManager* man = XreateManager::prepare(
- " import raw (\"core/control-context.lp\").\n"
- " case context::toMillimeters {\n"
- " convertConcrete = function(source:: num)::num {\n"
- " 10 * source \n"
- " }\n"
- " }\n"
-
- " case context::toInches {\n"
- " convertConcrete = function(source:: num)::num {\n"
- " 2 * source \n"
- " }\n"
- " }\n"
-
- "convert= function(source:: num):: num { \n"
- "convertConcrete(source) \n"
- "} \n"
-
- "test = function(source:: num):: num; entry {\n"
- " context:: toMillimeters.\n"
- " convert(1)\n"
- "}\n" );
-
- int (*main)(int) = (int (*)(int)) man->run();
- ASSERT_EQ(10, main(1));
-}
-
-TEST(Context, full_ContextBasedFunctionSpecialization){
-
- XreateManager* man = XreateManager::prepare(
- " import raw (\"core/control-context.lp\").\n"
- " case context::toMillimeters {\n"
- " convert = function(source:: num)::num {\n"
- " 10 * source \n"
- " }\n"
- " }\n"
-
- " case context::toInches {\n"
- " convert = function(source:: num)::num {\n"
- " 2 * source \n"
- " }\n"
- " }\n"
-
- "test = function(vrnt:: int)::int; entry {\n"
- " switch(vrnt):: int\n"
- " case (0) {\n"
- " context:: toMillimeters.\n"
- " convert(1)\n"
- " }\n"
- "\n"
- " case (1) {\n"
- " context:: toInches.\n"
- " convert(1)\n"
- " }\n"
- " case default {0}\n"
- " }" );
-
- int (*main)(int) = (int (*)(int)) man->run();
- ASSERT_EQ(10, main(0));
- ASSERT_EQ(2, main(1));
-}
-
-TEST(Context, full_RuleContext){
- /*
- "rule context:: childs(Child)\n"
- " case artefact(Item)\n"
- " {\n"
- " artefact_depends(Item, Child)\n"
- " }";
- */
-
- XreateManager* man = XreateManager::prepare(
- " import raw (\"core/control-context.lp\").\n"
- " case context:: toMilli {\n"
- " convert = function(length::int)::int{\n"
- " 10 * length\n"
- " }\n"
- " }\n"
- "\n"
- " case context:: toCenti {\n"
- " convert = function(length::int)::int{\n"
- " length\n"
- " }\n"
- " }\n"
- "\n"
- " main=function::int; entry {\n"
- " context:: output(milli).\n"
- "\n"
- " rule context::toMilli\n"
- " case (output(milli)) {truth}\n"
- "\n"
- " convert(1)\n"
- " }" );
-
- man->clasp->addRawScript("truth.");
- int (*entry)() = (int (*)()) man->run();
- ASSERT_EQ(10, entry());
-}
-
-TEST(Context, full_InheritedRuleContext){
- XreateManager* man = XreateManager::prepare(
-" import raw (\"core/control-context.lp\"). \n"
-
-" case context:: toMilli {\n"
-" convert = function(length::int)::int{\n"
-" 10 * length\n"
-" }\n"
-" }\n"
-
-" case context:: toCenti {\n"
-" convert = function(length::int)::int{\n"
-" length\n"
-" }\n"
-" }\n"
-"\n"
-
-"main = function(comm:: num)::num; entry{\n"
-" rule context::X case (output(X)) {truth}\n"
-"\n"
-" switch (comm)::num \n"
-" case (0) {\n"
-" context:: output(toMilli).\n"
-" convert(1)\n"
-" }\n"
-" case default {\n"
-" context:: output(toCenti).\n"
-" convert(1)\n"
-" }\n"
-" }");
-
- man->clasp->addRawScript("truth.");
- int (*entry)(int) = (int (*)(int)) man->run();
- ASSERT_EQ(10, entry(0));
- ASSERT_EQ(1, entry(1));
-}
-
-
-
-TEST(Context, full_LateContext){
- details::tier1::XreateManager* man = details::tier1::XreateManager::prepare(
- "import raw (\"core/control-context.lp\").\n"
-
- " convert = function(length:: num)::num{\n"
- " 0\n"
- " }\n"
-
- "case context:: milli {\n"
- " convert = function(length:: num)::num{\n"
- " 1000 * length\n"
- " }\n"
- "}\n"
- "\n"
- "case context:: centi {\n"
- " convert = function(length:: num)::num{\n"
- " 100 * length\n"
- " }\n"
- "}\n"
- "\n"
- "calculate = function(length:: num)::num {\n"
- " convert(length)\n"
- "}\n"
- "\n"
- "main = function(com:: num):: num; entry {\n"
- " switch (com):: num \n"
- " case (0) {\n"
- " context:: milli.\n"
- " calculate(1)\n"
- " }\n"
- "\n"
- " case default{\n"
- " context:: centi. \n"
- " calculate(1)\n"
- " }\n"
- "}");
-
- man->analyse();
- ContextQuery* queryContext = reinterpret_cast<ContextQuery*>(man->clasp->getQuery(QueryId::ContextQuery));
- const Expression& exprSwitch = man->root->findFunction("main")->__entry->getBody();
- const CodeScope* blockDefault = man->root->findFunction("main")->__entry->getBody().operands.at(1).blocks.front();
- ScopePacked blockDefaultId = man->clasp->pack(blockDefault);
- const Domain& domDefault = queryContext->getContext(blockDefaultId);
- ASSERT_EQ(1, domDefault.count(Expression(Atom<Identifier_t>("centi"))));
-
- std::list<ManagedFnPtr> variants = man->root->getFunctionSpecializations("convert");
- for (ManagedFnPtr f: variants){
- const Expression guard = f->guardContext;
- bool result = (guard.getValueString() == "centi" || guard.getValueString() == "milli" || !guard.isValid());
- ASSERT_TRUE(result);
- }
-
- const FunctionDemand& demMain = queryContext->getFunctionDemand("main");
- ASSERT_EQ(0, demMain.size());
-
- const FunctionDemand& demCalculate = queryContext->getFunctionDemand("calculate");
- ASSERT_EQ(1, demCalculate.size());
-
- int (*entry)(int) = (int (*)(int)) man->run();
- ASSERT_EQ(1000, entry(0));
- ASSERT_EQ(100, entry(1));
-}
-
-TEST(Context, loopContextExists){
- XreateManager* man = XreateManager::prepare (
- "import raw (\"core/control-context.lp\").\n"
-
- "interface(cfa){\n"
- " operator fold:: annotation1.\n"
- "}\n"
- "\n"
- "main = function:: int; entry {\n"
- " x = [1..10]:: [int].\n"
- " sum = loop fold (x->el:: int, 0->sum):: int {\n"
- " el + sum + f1()\n"
- " }. \n"
- " sum\n"
- "}"
- "case context:: annotation1 {"
- " f1 = function::int {\n"
- " x = 0:: int. "
- " x\n"
- " }"
- "}"
- );
-
- man->run();
-}
-
-TEST(Context, pathDependentContext){
- std::string program =
-R"CODE(
-import raw("core/control-context.lp").
-
-convert = function(length:: num) :: num {
- 0
-}
-
-case context:: convert(milli, meters) {
- convert = function(length:: num) :: num {
- 1000 * length
- }
-}
-
-case context:: convert(centi, meters) {
- convert = function(length:: num) :: num {
- 100 * length
- }
-}
-
-case context:: convert(centi, kilo) {
- convert = function(length:: num) :: num {
- 100000 * length
- }
-}
-
-case context:: convert(milli, kilo) {
- convert = function(length:: num) :: num {
- 1000000 * length
- }
-}
-
-main = function(value::num, unitsInput::num, unitsOutput::num)::num; entry{
- switch (unitsInput)::num
- case (0) {
- test_fromMilli(value, unitsOutput)
- }
- case (1) {
- test_fromCenti(value, unitsOutput)
- }
-
- case default {0}
-}
-
-test_fromCenti = function(value::num, output::num)::num{
- context:: input(centi).
-
- switch(output):: num
- case (0) {
- toMeters(value)
- }
-
- case (1) {
- toKilo(value)
- }
-
- case default {0}
-}
-
-test_fromMilli = function(value::num, output::num)::num{
- context:: input(milli).
-
- switch(output):: num
- case (0) {
- toMeters(value)
- }
-
- case (1) {
- toKilo(value)
- }
-
- case default {0}
-}
-
-toMeters = function(value::num)::num {
- rule context:: convert(X, meters) case (input(X)) {truth}
-
- doConvert(value)
-}
-
-toKilo = function(value::num)::num {
- rule context:: convert(X, kilo) case (input(X)) {truth}
-
- doConvert(value)
-}
-
-doConvert = function(value::num)::num{
- convert(value)
-})CODE";
-
- boost::scoped_ptr<details::tier1::XreateManager> man(details::tier1::XreateManager::prepare(move(program)));
- man->clasp->addRawScript("truth.");
- man->analyse();
-
- int (*test)(int, int, int) = (int (*)(int, int, int))man->run();
-
- enum {INPUT_MILLI, INPUT_CENTI};
- enum {OUTPUT_METERS, OUTPUT_KILO};
-
- ASSERT_EQ(1000000, test(1, INPUT_MILLI, OUTPUT_KILO));
- ASSERT_EQ(200, test(2, INPUT_CENTI, OUTPUT_METERS));
-}
-
-//TODO recover context loop and enable the test
-TEST(Context, DISABLED_full_LoopContext){
- XreateManager* man = XreateManager::prepare(
- " import raw (\"core/control-context.lp\")\n"
- " case context:: a {\n"
- " print = function:: string {\n"
- " \"a\"\n"
- " }}\n"
- "\n"
- " case context:: b {\n"
- " print = function:: string {\n"
- " \"b\"\n"
- " }}\n"
- "\n"
- " case context:: c {\n"
- " print = function:: string {\n"
- " \"c\"\n"
- " }}\n"
- "\n"
- " case context:: d {\n"
- " print = function:: string {\n"
- " \"d\"\n"
- " }}\n"
- "\n"
- " start = function(command::int)::string; entry {\n"
- " switch (command) :: string \n"
- " case (0) {\n"
- " context:: print(a); print(b); print(d).\n"
- "\n"
- " loop context (\"print\") {\n"
- " print()\n"
- " }\n"
- " }\n"
- "\n"
- " case default {\n"
- " context:: print(c).\n"
- " loop context (\"print\") {\n"
- " print()\n"
- " }\n"
- " }\n"
- " }");
-
-
- char* (*main)(int) =(char* (*)(int)) man->run();
- ASSERT_STREQ("c", main(1));
- ASSERT_STREQ("a", main(0));
-}
diff --git a/cpp/tests/interpretation.cpp b/cpp/tests/interpretation.cpp
index a017579..336f58d 100644
--- a/cpp/tests/interpretation.cpp
+++ b/cpp/tests/interpretation.cpp
@@ -1,468 +1,531 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* interpretation.cpp
*
* Created on: -
* Author: pgess <v.melnychenko@xreate.org>
*/
#include "attachments.h"
using namespace xreate;
#include "xreatemanager.h"
#include "compilation/targetinterpretation.h"
#include "gtest/gtest.h"
#include "boost/scoped_ptr.hpp"
//#define FRIENDS_INTERPRETATION_TESTS \
// friend class ::Modules_AST2_Test; \
// friend class ::Modules_Discovery1_Test; \
// friend class ::Modules_Solve1_Test;
#include "pass/interpretationpass.h"
using namespace xreate::grammar::main;
using namespace xreate::interpretation;
TEST(Interpretation, Analysis_StatementIF_1){
XreateManager* man = XreateManager::prepare(
R"Code(
main = function::bool {
x = "a":: string.
y = if (x=="b"):: bool; interpretation(force) {
true
} else {
false
}.
y
}
)Code" );
InterpretationPass* pass = new InterpretationPass(man);
pass->run();
CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope();
Symbol symbolY{scopeEntry->getSymbol("y"), scopeEntry};
InterpretationData& dataSymbolY = Attachments::get<InterpretationData>(symbolY);
ASSERT_EQ(INTR_ONLY, dataSymbolY.resolution);
}
TEST(Interpretation, Compilation_StatementIF_1){
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(
R"Code(
main = function::int; entry {
x = "a":: string.
y = if (x=="b"):: string; interpretation(force) {
1
} else {
0
}.
y
}
)Code" );
man->analyse();
InterpretationPass* pass;
if (man->isPassRegistered(PassId::InterpretationPass)){
pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass);
} else {
pass = new InterpretationPass(man);
pass->run();
}
int (*main)() = (int (*)())man->run();
int result = main();
ASSERT_EQ(0, result);
}
TEST(Interpretation, Analysis_StatementIF_InterpretCondition_1){
XreateManager* man = XreateManager::prepare(
R"Code(
main = function(x:: int):: int {
comm= "inc":: string; interpretation(force).
y = if (comm == "inc")::int {x+1} else {x}.
y
}
)Code" );
InterpretationPass* pass = new InterpretationPass(man);
pass->run();
CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope();
Symbol symbolY{scopeEntry->getSymbol("y"), scopeEntry};
InterpretationData& dataSymbolY = Attachments::get<InterpretationData>(symbolY);
ASSERT_EQ(CMPL_ONLY, dataSymbolY.resolution);
ASSERT_EQ(IF_INTERPRET_CONDITION, dataSymbolY.op);
}
TEST(Interpretation, Compilation_StatementIF_InterpretCondition_1){
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(
R"Code(
main = function(x:: int):: int; entry {
comm= "inc":: string; interpretation(force).
y = if (comm == "inc")::int {x+1} else {x}.
y
}
)Code" );
man->analyse();
InterpretationPass* pass;
if (man->isPassRegistered(PassId::InterpretationPass)){
pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass);
} else {
pass = new InterpretationPass(man);
pass->run();
}
int (*main)(int) = (int (*)(int))man->run();
int result = main(1);
ASSERT_EQ(2, result);
}
TEST(Interpretation, Compilation_StatementFOLD_INTERPRET_INPUT_1){
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(
R"Code(
main = function(x:: int):: int; entry {
commands = ["inc", "double", "dec"]:: [string]; interpretation(force).
loop fold(commands->comm::string, x->operand):: int{
switch(comm)::int
case ("inc"){
operand + 1
}
case ("dec"){
operand - 1
}
case ("double"){
operand * 2
}
}
}
)Code" );
man->analyse();
InterpretationPass* pass;
if (man->isPassRegistered(PassId::InterpretationPass)){
pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass);
} else {
pass = new InterpretationPass(man);
pass->run();
}
const ManagedFnPtr& funcMain = man->root->findFunction("main");
InterpretationData& dataBody = Attachments::get<InterpretationData>(funcMain);
ASSERT_EQ(FOLD_INTERPRET_INPUT, dataBody.op);
int (*main)(int) = (int (*)(int))man->run();
int result = main(10);
ASSERT_EQ(21, result);
}
TEST(Interpretation, StatementCall_RecursionNo_1){
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(
R"Code(
unwrap = function(data::unknType, keys::unknType):: unknType; interpretation(force){
loop fold(keys->key::string, data->a):: unknType {
a[key]
}
}
start = function::num; entry{
result = unwrap(
{
a = {
b =
{
c = "core"
}
}
}, ["a", "b", "c"])::unknType.
result == "core"
}
)Code" );
man->analyse();
InterpretationPass* pass;
if (man->isPassRegistered(PassId::InterpretationPass)){
pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass);
} else {
pass = new InterpretationPass(man);
pass->run();
}
int (*main)() = (int (*)())man->run();
int result = main();
ASSERT_EQ(1, result);
}
TEST(Interpretation, StatementCall_RecursionDirect_1){
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(
R"Code(
unwrap = function(data:: X):: Y {
if (data[0] == "a")::Y {0} else {unwrap(data[0])}
}
entry = function:: i8; entry {
unwrap([[[["a"]]]]):: i8; interpretation(force)
}
)Code" );
man->analyse();
InterpretationPass* pass;
if (man->isPassRegistered(PassId::InterpretationPass)){
pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass);
} else {
pass = new InterpretationPass(man);
pass->run();
}
InterpretationResolution resolutionActual = pass->process(man->root->findFunction("unwrap"));
ASSERT_EQ(ANY, resolutionActual);
int (*main)() = (int (*)())man->run();
int result = main();
ASSERT_EQ(0, result);
}
TEST(Interpretation, StatementCall_RecursionIndirect_1){
XreateManager* man = XreateManager::prepare(
R"Code(
funcA = function(data:: X):: Y {
if (data == "a")::Y {0} else {funcB(data)}
}
funcB = function(data:: X):: Y {
if (data == "b")::Y {1} else {funcA(data)}
}
entry = function:: i8; entry {
funcA(""):: i8; interpretation(force)
}
)Code" );
InterpretationPass* pass = new InterpretationPass(man);
ASSERT_DEATH(pass->run(), "Indirect recursion detected");
}
TEST(Interpretation, PartialIntr_1){
XreateManager* man = XreateManager::prepare(
R"Code(
evaluate= function(argument:: num, code:: string; interpretation(force)):: num {
switch(code)::int
case ("inc") {argument + 1}
case ("dec") {argument - 1}
case ("double") {argument * 2}
}
main = function::int; entry {
commands= ["inc", "double", "dec"]:: [string]; interpretation(force).
loop fold(commands->comm::string, 10->operand):: int{
evaluate(operand, comm)
}
}
)Code" );
InterpretationPass* pass = new InterpretationPass(man);
pass->run();
ManagedFnPtr fnEvaluate = man->root->findFunction("evaluate");
InterpretationResolution resFnEvaluate= pass->process(fnEvaluate);
ASSERT_EQ(CMPL_ONLY, resFnEvaluate);
ASSERT_TRUE(FunctionInterpretationHelper::needPartialInterpretation(fnEvaluate));
const Expression& exprLoop = man->root->findFunction("main")->__entry->getBody();
Symbol symbCallEv{{0, versions::VERSION_NONE}, exprLoop.blocks.front()};
InterpretationData dataCallEv = Attachments::get<InterpretationData>(symbCallEv);
ASSERT_EQ(CMPL_ONLY, dataCallEv.resolution);
ASSERT_EQ(CALL_INTERPRET_PARTIAL, dataCallEv.op);
}
TEST(Interpretation, Compilation_PartialIntr_2){
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(
R"Code(
evaluate= function(argument:: num, code:: string; interpretation(force)):: num {
switch(code)::int
case ("inc") {argument + 1}
case ("dec") {argument - 1}
case ("double") {argument * 2}
case default {argument}
}
main = function::int; entry {
commands= ["inc", "double", "dec"]:: [string]; interpretation(force).
loop fold(commands->comm::string, 10->operand):: int{
evaluate(operand, comm)
}
}
)Code" );
man->analyse();
if (!man->isPassRegistered(PassId::InterpretationPass)){
InterpretationPass* pass = new InterpretationPass(man);
pass->run();
}
int (*main)() = (int (*)())man->run();
int result = main();
ASSERT_EQ(21, result);
}
TEST(Interpretation, PartialIntr_3){
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(
R"Code(
Command= type variant {INC, DEC, DOUBLE}.
evaluate= function(argument:: num, code:: Command; interpretation(force)):: num {
switch variant(code)::int
case (INC) {argument + 1}
case (DEC) {argument - 1}
case (DOUBLE) {argument * 2}
}
main = function::int; entry {
commands= [INC(), DOUBLE(), DEC()]:: [Command]; interpretation(force).
loop fold(commands->comm::Command, 10->operand):: int{
evaluate(operand, comm)
}
}
)Code" );
man->analyse();
if (!man->isPassRegistered(PassId::InterpretationPass)){
InterpretationPass* pass = new InterpretationPass(man);
pass->run();
}
int (*main)() = (int (*)())man->run();
int result = main();
ASSERT_EQ(21, result);
}
+TEST(Interpretation, PartialIntr_4){
+ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(
+R"Code(
+ Command= type variant {INC, DEC, DOUBLE}.
+
+ evaluate= function(argument:: num, code:: Command; interpretation(force)):: num {
+ switch variant(code)::num
+ case (INC) {argument + 1}
+ case (DEC) {argument - 1}
+ case (DOUBLE) {argument * 2}
+ }
+
+ main = function::int; entry {
+ evaluate(4, DEC())
+ }
+)Code" );
+
+ man->analyse();
+ if (!man->isPassRegistered(PassId::InterpretationPass)){
+ InterpretationPass* pass = new InterpretationPass(man);
+ pass->run();
+ }
+
+ int (*main)() = (int (*)())man->run();
+ int result = main();
+
+ ASSERT_EQ(3, result);
+}
+
TEST(Interpretation, SwitchVariant){
xreate::XreateManager* man = xreate::XreateManager::prepare(
R"Code(
OneArgument = type{x::int}.
TWoArgument = type {x::int, y::int}.
Command= type variant {
ADD::TwoArguments,
DEC:: OneArgument,
DOUBLE::OneArgument
}.
main = function::int; entry{
program = ADD({x=2, y=3})::Command; interpretation(force).
switch variant(program)::int
case (ADD) {program["x"]+program["y"]}
case (DEC) {1}
case (DOUBLE) {2}
}
)Code" );
int (*main)() = (int (*)())man->run();
int result = main();
ASSERT_EQ(5, result);
}
TEST(Interpretation, SwitchVariantAlias){
xreate::XreateManager* man = xreate::XreateManager::prepare(
R"Code(
OneArgument = type{x::int}.
TWoArgument = type {x::int, y::int}.
Command= type variant {
ADD::TwoArguments,
DEC:: OneArgument,
DOUBLE::OneArgument
}.
main = function::int; entry{
program = [ADD({x=2, y=3}), DEC({x=8})]::[Command]; interpretation(force).
switch variant(program[0]->program::Command)::int
case (ADD) {program["x"]+program["y"]}
case (DEC) {1}
case (DOUBLE) {2}
}
)Code" );
int (*main)() = (int (*)())man->run();
int result = main();
ASSERT_EQ(5, result);
}
TEST(Interpretation, Multiindex1){
std::string script2=
R"Code(
extract = function(program::unknType)::int; interpretation(force){
program["arguments"][1]
}
main = function::int; entry {
x = {arguments = [10, 9, 8, 7]}:: unknType; interpretation(force).
extract(x)
}
)Code";
std::unique_ptr<XreateManager> man(XreateManager::prepare(std::move(script2)));
int (*main)() = (int (*)())man->run();
int result = main();
ASSERT_EQ(9, result);
}
TEST(InterpretationExamples, Regexp1){
FILE* input = fopen("scripts/dsl/regexp.xreate","r");
assert(input != nullptr);
std::unique_ptr<XreateManager> man(XreateManager::prepare(input));
int (*main)() = (int (*)())man->run();
int result = main();
ASSERT_EQ(4, result);
}
+TEST(Interpretation, Variant1){
+ std::string script=
+R"Code(
+Data = type {Num:: [int], String::string}.
+
+DataPacked = type variant {
+ Var1:: Data,
+ Var2:: Data
+}.
+
+extractInt = function(data::DataPacked):: int {
+ resultWrong = 0 :: int.
+
+ switch variant(data)::int
+ case (Var1) {data["Num", 0]}
+ case (Var2) {resultWrong}
+}
+
+main = function :: int; entry {
+ dataActual = 10.
+ dataPacked = Var1({Num = [dataActual], String = "whatever"}):: DataPacked.
+
+ extractInt(dataPacked):: int; interpretation(force)
+}
+)Code";
+
+ std::unique_ptr<XreateManager> man(XreateManager::prepare(std::move(script)));
+
+ int (*main)() = (int (*)())man->run();
+ int result = main();
+
+ ASSERT_EQ(10, result);
+}
+
//TOTEST call indirect recursion(w/o tags)
//TASk implement and test Loop Inf (fix acc types in coco grammar)
diff --git a/cpp/tests/virtualization.cpp b/cpp/tests/virtualization.cpp
index 2191504..eccbd29 100644
--- a/cpp/tests/virtualization.cpp
+++ b/cpp/tests/virtualization.cpp
@@ -1,27 +1,38 @@
/*
* 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/.
=
* virtualization.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on February 24, 2018, 4:30 PM
*/
#include "xreatemanager.h"
#include "gtest/gtest.h"
-
using namespace xreate;
TEST(Virtualization, test1){
FILE* input = fopen("scripts/virtualization/test1.xreate","r");
assert(input != nullptr);
std::unique_ptr<XreateManager> man(XreateManager::prepare(input));
int (*main)() = (int (*)())man->run();
int result = main();
ASSERT_EQ(1, result);
+}
+
+TEST(Virtualization, test2){
+ FILE* input = fopen("scripts/virtualization/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);
}
\ No newline at end of file
diff --git a/grammar/xreate.ATG b/grammar/xreate.ATG
index 86b8dc1..408c907 100644
--- a/grammar/xreate.ATG
+++ b/grammar/xreate.ATG
@@ -1,665 +1,663 @@
//TODO add ListLiteral
//TODO ExprTyped: assign default(none) type
#include "ast.h"
#include "ExternLayer.h"
#include "pass/adhocpass.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".
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 | ContextSection | GuardSection
+ | 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));.)
} ')']
[ tagcolon
( IF(flagIsPrefunct) FnTag<f>
| Type<typOut>
)
{';' FnTag<f> }]
BDecl<entry> (. const_cast<Expression&>(entry->getBody()).bindType(move(typOut));.)
.
-ContextSection<>= (. Expression context; Function* f; .)
- "case" "context" tagcolon MetaSimpExpr<context>
- lcurbrack { FDecl<f> (. f->guardContext = context; root->add(f); .)
- } rcurbrack.
-
GuardSection<>= (. Expression guard; Function* f; .)
"guard" tagcolon MetaSimpExpr<guard>
- lcurbrack { FDecl<f> (. f->guard = guard; root->add(f); .)
+ 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>
| 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()); .)
} 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); .)
} ')']
) .
TList<TypeAnnotation& typ> = (. TypeAnnotation ty; .)
'[' Type<ty> ']' (. 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()); .)
{',' (
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; .)
[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)); .)
.
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> '.'
| RuleContextDecl<scope>
| ContextDecl<scope>'.'
| 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}); .)
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>
(.
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> ')'
(.
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>')'
(.
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); .)
)
| "context" '(' string (. contextClass = t->val; .)
')' BDecl<&*block>
(. e = Expression(Operator::LOOP_CONTEXT, {Expression(Atom<String_t>(std::move(contextClass)))});
e.addBlock(block);
.)
).
// Switches
SwitchDecl<Expression& eSwitch, SwitchKind flagSwitchKind> = (. TypeAnnotation typ; eSwitch = Expression(Operator::SWITCH, {}); Expression eCondition; Expression tag;.)
"switch"
(
SwitchVariantDecl<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)); .)
} (. scope->setBody(guard); popContextScope(); .)
.
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 '.'.
InterfaceData<> = "interface" '('
( "dfa" ')' InterfaceDFA
| "extern-c" ')' InterfaceExternC
| "cfa" ')' InterfaceCFA
| "adhoc" ')' InterfaceAdhoc
).
InterfaceAdhoc<> =
'{' { PrefunctionSchemeDecl } '}'.
PrefunctionSchemeDecl<> = (. TypeAnnotation typReturn; std::wstring prefName; Expression exprCases; .)
pre function Ident<prefName> tagcolon Type<typReturn>
lcurbrack SwitchDecl<exprCases, SWITCH_META> rcurbrack
(. Expression prefData(Operator::CALL, {Atom<Identifier_t>(prefName), exprCases});
prefData.bindType(typReturn);
root->addInterfaceData(Adhoc, move(prefData));
.).
InterfaceExternC<> = (. ExternData data; .)
'{' {IncludeExternDecl<data> | LibExternDecl<data> } '}'
(. 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)); .)
.
IncludeExternDecl<ExternData& data> = (. Expression inc; .)
"include" StructLiteral<inc> '.' (. data.addIncludeDecl(move(inc)); .)
.
InterfaceDFA<> = '{' { InstructDecl } '}' .
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); .)
[
MetaSimpExpr<tag> (. tags.push_back(tag); .)
{
',' MetaSimpExpr<tag> (. tags.push_back(tag); .)
}
] ')' [ implic MetaSimpExpr<tag> (. tags[0] = tag; .)
] (. root->addDFAData(move(scheme)); .)
'.'.
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 } '}' .
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); .)
}
] '.' (. 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> '}' .
/* - 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})); .).
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> ')'
| 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> ] ')'
| 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)); .)
}.
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>] ')'
| VarIdent<e> (. recognizeIdentifier(e); .)
| ListLiteral<e> (. /* tuple */.)
| StructLiteral<e> (. /* struct */.)
| LoopDecl<e>
| IfDecl<e>
| SwitchDecl<e, SWITCH_NORMAL>
| AdhocDecl<e>
| 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> ')'
).
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>
| 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>
| 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; .)
-'['
-[ Expr<eFrom> (. e.addArg(Expression(eFrom)); .)
-(".." Expr<eTo> (. e.addArg(Expression(eTo)); e.setOp(Operator::LIST_RANGE); .)
- |{',' Expr<eFrom> (. e.addArg(Expression(eFrom)); .)
-} (. e.setOp(Operator::LIST); .)
-) ] ']'.
+'[' (. 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)); .)
+ }
+ )
+ ]
+']'.
AdhocDecl<Expression& e> = (. Expression command; .)
"ad" "hoc" MetaSimpExpr<command> (. adhoc::AdhocExpression exprAdhoc; exprAdhoc.setCommand(command); e = exprAdhoc; .).
CalleeParams<Expression& e> = (. Expression e2; .)
ExprTyped<e2> (. e.addArg(Expression(e2)); .)
{',' 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} '}'.
END Xreate.
diff --git a/core/control-context-v1.lp b/scripts/cfa/control-context-v1.lp
similarity index 100%
rename from core/control-context-v1.lp
rename to scripts/cfa/control-context-v1.lp
diff --git a/core/control-context-v3.lp b/scripts/cfa/control-context-v3.lp
similarity index 86%
rename from core/control-context-v3.lp
rename to scripts/cfa/control-context-v3.lp
index ab4cfe3..03fe0d5 100644
--- a/core/control-context-v3.lp
+++ b/scripts/cfa/control-context-v3.lp
@@ -1,64 +1,70 @@
% This Source Code Form is subject to the terms of the Mozilla Public
% License, v. 2.0. If a copy of the MPL was not distributed with this
% file, You can obtain one at http://mozilla.org/MPL/2.0/.
%% SCHEMA:
%% specialization(Fn, Scope) - indicates query of exact Fn specialization to use in Scope.
%% resolution_dependency(Resolution, Dependency) - Dependency is necessary prerequisite for choosing Resolution.
%%
true.
%nested scope propagation:
bind_scope(Scope, Context, Info) :- bind_scope(ScopeParent, Context, Info), cfa_parent(Scope, scope(ScopeParent)).
%strong/uniform inter-function propagation:
bind_scope(Scope, Context,Info) :- bind_scope(ScopeParent, Context, Info): cfa_call(ScopeParent, FnCurrent);
cfa_parent(Scope, function(FnCurrent)); cfa_call(_, FnCurrent);
bind_scope(_, Context, Info); scope(Scope).
%weak inter-function propagation
bind_scope(Scope, Context, weak(ScopeParent)):- not bind_scope(Scope, Context, strong), bind_scope(ScopeParent, Context, strong), cfa_call(ScopeParent, FnCurrent), cfa_parent(Scope, function(FnCurrent)).
bind_scope(Scope, Context, weak(ScopeParent, Info)):- Info<>strong, not bind_scope(Scope, Context, Info), bind_scope(ScopeParent, Context, Info), cfa_call(ScopeParent, FnCurrent), cfa_parent(Scope, function(FnCurrent)).
%make decisions
%%%bind_scope_decision(Scope, loop(Subject), Scope):- cfa_contextloop(Scope, Subject), demand_dependency(loop(Subject), X), bind_scope(Scope, X, strong).*
%%%bind_scope_decision(Scope, loop(Subject), Scope):- cfa_call(Scope, FnChild), bind_function_demand(FnChild, loop(Subject)), demand_dependency(loop(Subject), X), bind_scope(Scope, X, strong).
%on-site decision
% ASSERT: ON-SITE DECISION SHOULD BE FIRST CLASS (checks at least one specialization exists)
-bind_scope_decision(Scope, Subject, Resolution):- bind_scope(Scope, Resolution, strong), Subject = specialization(Fn, Scope),
- cfa_call(Scope, Fn),
- cfa_function_specializations(Fn, Resolution).
-
-bind_scope_decision(ScopeSource, Subject, Resolution):- bind_scope(Scope, Resolution, weak(ScopeSource)), Subject = specialization(Fn, Scope), cfa_call(Scope, Fn), cfa_function_specializations(Fn, Resolution).
-bind_scope_decision(ScopeSource, Subject, resolution_dependency(Resolution, Dependency)):- bind_scope(Scope, Resolution, weak(ScopeSource, Dependency)), Subject = specialization(Fn, Scope), cfa_call(Scope, Fn), cfa_function_specializations(Fn, Resolution).
+bind_scope_decision(Scope, Subject, Resolution):-
+ bind_scope(Scope, Resolution, strong), Subject = specialization(Fn, Scope);
+ cfa_call(Scope, Fn);
+ cfa_function_specializations(Fn, Resolution).
+
+bind_scope_decision(ScopeSource, Subject, Resolution):-
+ bind_scope(Scope, Resolution, weak(ScopeSource)); Subject = specialization(Fn, Scope);
+ cfa_call(Scope, Fn); cfa_function_specializations(Fn, Resolution).
+
+bind_scope_decision(ScopeSource, Subject, resolution_dependency(Resolution, Dependency)):-
+ bind_scope(Scope, Resolution, weak(ScopeSource, Dependency)); Subject = specialization(Fn, Scope);
+ cfa_call(Scope, Fn), cfa_function_specializations(Fn, Resolution).
%dependent decisions
bind_scope_demand(Scope, dependency(Subject, Scope)) :- bind_scope_decision(Scope, Subject, resolution_dependency(_, Dependency)).
bind_scope_demand(ScopeSource, dependency(Subject, ScopeSource)) :- Dependency = weak(ScopeSource, DependencyTail), bind_scope_demand(Scope, dependency(Subject, Scope)), scope_dependencies(dependency(Subject, Scope), Dependency).
bind_scope_decision(ScopeSource, dependency(Subject, Scope), Dependency) :- Dependency = weak(ScopeSource), bind_scope_demand(Scope, dependency(Subject, Scope)), scope_dependencies(dependency(Subject, Scope), Dependency).
bind_scope_decision(ScopeSource, dependency(Subject, Scope), resolution_dependency(Dependency, DependencyTail)) :- Dependency = weak(ScopeSource, DependencyTail), bind_scope_demand(Scope, dependency(Subject, Scope)), scope_dependencies(dependency(Subject, Scope), Dependency).
%dependent decision helpers:
scope_dependencies(dependency(Subject, Scope), Dependency) :- bind_scope_decision(Scope, Subject, resolution_dependency(_, Dependency)).
scope_dependencies(dependency(Subject, ScopeSource), DependencyTail) :- Dependency = weak(ScopeSource, DependencyTail), bind_scope_demand(Scope, dependency(Subject, Scope)), scope_dependencies(dependency(Subject, Scope), Dependency).
%on-site demand
% ASSERT: ON-SITE DEMAND SHOULD BE dependent OF on-site decision (check there are no specializations AT ALL)
%%%bind_scope_demand(Scope, Subject):- cfa_contextloop(Scope, Subject), not bind_scope_decision(Scope, loop(Subject), _).
bind_scope_demand(Scope, Subject):- Subject = specialization(FnCallee, Scope),
cfa_call(Scope, FnCallee),
cfa_function_specializations(FnCallee, _),
not bind_scope_decision(Scope, Subject, _).
%nested scope demand propagation
%ASSERT: NO DECISION CHECKS. because decisions linked to a leaf(function execution sites) scopes
bind_scope_demand(Scope, Subject):- bind_scope_demand(ScopeChild, Subject), cfa_parent(ScopeChild, scope(Scope)).
bind_function_demand(Fn, Subject):- bind_scope_demand(Scope, Subject), cfa_parent(Scope, function(Fn)).
%inter-function propagation demand
bind_scope_demand(Scope, Subject):- cfa_call(Scope, FnChild), bind_function_demand(FnChild, Subject), not bind_scope_decision(Scope, Subject, _).
diff --git a/scripts/cfa/control-context.lp b/scripts/cfa/control-context.lp
new file mode 120000
index 0000000..e2a1c99
--- /dev/null
+++ b/scripts/cfa/control-context.lp
@@ -0,0 +1 @@
+/private/prg/code/xreate/scripts/cfa/control-context-v3.lp
\ No newline at end of file
diff --git a/core/containers.lp b/scripts/containers/containers.lp
similarity index 100%
rename from core/containers.lp
rename to scripts/containers/containers.lp
diff --git a/scripts/virtualization/context-v1.lp b/scripts/virtualization/context-v1.lp
new file mode 100644
index 0000000..f0a7feb
--- /dev/null
+++ b/scripts/virtualization/context-v1.lp
@@ -0,0 +1,47 @@
+%INPUT:
+% kleo_registered_subjects(Scope, Option, Subject)
+
+%bind_scope_decision - scope has decision for demand of one of its subscopes.
+
+% CLIENTS
+%===========================================================
+% clients defined downstream
+
+%Register fn argument demand
+kleo_registered_subjects(ScopeCaller, kleo_arg(Subject), Guard):-
+ kleo_fn_demand(Fn, Subject);
+ cfa_parent(ScopeCallee, function(Fn));
+ kleo_registered_subjects(ScopeCallee, Subject, Guard);
+ cfa_call(ScopeCaller, Fn).
+
+% DEMAND
+%===========================================================
+
+%local demand
+kleo_scope_demand(Scope, Subject):-
+ not kleo_scope_decision(Scope, Subject, _);
+ kleo_registered_subjects(Scope, Subject, Decision).
+
+%demand propagation: scope
+kleo_scope_demand(Scope, Subject):-
+ kleo_scope_demand(ScopeChild, Subject);
+ cfa_parent(ScopeChild, scope(Scope)).
+
+%propagation: interfn
+kleo_fn_demand(Fn, Subject):-
+ kleo_scope_demand(ScopeFnBody, Subject);
+ cfa_parent(ScopeFnBody, function(Fn)).
+
+
+% DECISIONS
+%===========================================================
+
+%local decision
+kleo_scope_decision(Scope, Subject, Decision):-
+ bind_scope(Scope, Decision, strong);
+ kleo_registered_subjects(Scope, Subject, Decision).
+
+%interfn decision
+%kleo_scope_decision(ScopeSource, parameter(Subject), Decision):-
+% weak(bind_scope(Scope, Decision), ScopeSource);
+% kleo_registered_subjects(Scope, Subject, Decision).
diff --git a/scripts/virtualization/test1.assembly.lp b/scripts/virtualization/test1.assembly.lp
new file mode 100644
index 0000000..3762dae
--- /dev/null
+++ b/scripts/virtualization/test1.assembly.lp
@@ -0,0 +1,2 @@
+virtDomain(domainA).
+virtDomain(domainB).
diff --git a/scripts/virtualization/test1.xreate b/scripts/virtualization/test1.xreate
new file mode 100644
index 0000000..35c05b1
--- /dev/null
+++ b/scripts/virtualization/test1.xreate
@@ -0,0 +1,72 @@
+interface(extern-c){
+ externalLibs = library:: pkgconfig("libxml-2.0").
+
+ include {
+ externalLibs = ["stdio.h"]
+ }.
+}
+
+import raw ("scripts/virtualization/test1.assembly.lp").
+import raw ("scripts/virtualization/virtualization.lp").
+
+Annotation = type variant {
+ Num:: int,
+ String:: string,
+ Func:: {name::string, arguments::[Annotation]}
+}.
+
+DictEntry = type {Annotation, Id}.
+
+extractDictEntry = function(entry:: Annotation):: DictEntry; interpretation(force){
+ resultWrong = { String("wrong"), 0 }:: DictEntry.
+
+ switch variant (entry):: DictEntry
+ case (Num) { resultWrong }
+ case (String) { resultWrong }
+ case (Func){
+ domAnn = entry["arguments"][0]:: Annotation.
+
+ switch variant ( entry["arguments"][1]->id ):: Annotation
+ case (Num) { {domAnn, id} }
+ case (String) { resultWrong }
+ case (Func) { resultWrong }
+ }
+}
+
+encodeDomain = function(key::Annotation):: int; interpretation(force){
+ dict = intrinsic query("virtDictDomains")::[Annotation].
+
+ id = loop fold(dict->entryAnn::Annotation, 0->id):: int {
+ entry = extractDictEntry(entryAnn):: DictEntry.
+
+ if(entry[0] == key):: int { entry[1] } else { id }
+ }.
+
+ id
+
+ /*
+ buf = "000000000"::string.
+ seq
+ { sprintf(buf, "%d", id).}
+ { buf}
+ */
+}
+
+
+main = function:: int; entry {
+ encodeDomain(Func({"domainB", []}))
+}
+
+/*
+openfile = function(fileName::string, prefixPackedAnn:: Annotation) {
+ prefixStr = encodeDomain(prefixPackedAnn):: string.
+
+ fopen(prefixStr + fileName)
+}
+
+main = function:: entry (
+ seq
+ { context::virtualization(domainA). openFile("test1", intrinsic query("openFileAdditionalArgsDomA")[0]) }
+ { context::virtualization(domainB). openFile("test1", intrinsic query("openFileAdditionalArgsDomB")[0]) }
+)
+*/
diff --git a/scripts/virtualization/test2.assembly.lp b/scripts/virtualization/test2.assembly.lp
new file mode 100644
index 0000000..a3845ac
--- /dev/null
+++ b/scripts/virtualization/test2.assembly.lp
@@ -0,0 +1,12 @@
+
+dfa_callguard(Instance, Guard):- %static local decision
+ bind_scope(Scope, callguard(Guard), strong);
+ bind(InstSymbRet, dfa_polym(cntxt));
+ dfa_callinstance(Instance, FnCallee);
+ dfa_callret(Instance, InstSymbRet);
+ InstSymbRet = s(_, _, Scope).
+
+%Register manual demand
+kleo_registered_subjects(Scope, spec(FnCallee), Guard):-
+ bind_scope(Scope, kleo_manual_demand(FnCallee), strong);
+ cfa_function_specializations(FnCallee, Guard).
diff --git a/scripts/virtualization/test2.xreate b/scripts/virtualization/test2.xreate
new file mode 100644
index 0000000..12942f9
--- /dev/null
+++ b/scripts/virtualization/test2.xreate
@@ -0,0 +1,101 @@
+import raw ("scripts/virtualization/context-v1.lp").
+import raw ("scripts/virtualization/test2.assembly.lp").
+
+Annotation = type variant {
+ Num:: int,
+ String:: string,
+ Func:: {name::string, arguments::[Annotation]}
+}.
+
+FnControl = type variant {
+ Variant1, Variant2
+}.
+
+main = function:: int; entry {
+ funcA() + funcB() :: int
+}
+
+funcA = function::int{
+ context:: variant1.
+
+ testedFunc(prepareCtrlArg("testedFunc", intrinsic query_scope()))
+}
+
+funcB = function::int {
+ context:: variant2.
+
+ testedFunc(prepareCtrlArg("testedFunc", intrinsic query_scope()))
+}
+
+testedFunc = function(ctrl::FnControl):: int {
+ context:: kleo_manual_demand(funcC).
+
+ switch variant(ctrl)::int
+ case(Variant1){context:: callguard(variant1). funcC():: int; dfa_polym(cntxt)}
+ case(Variant2){context:: callguard(variant2). funcC():: int; dfa_polym(cntxt)}
+}
+
+guard:: variant1 {
+ funcC = function:: int {1}
+}
+
+guard:: variant2 {
+ funcC = function:: int {2}
+}
+
+selectSecond = function (db:: [Annotation], argFirst::Annotation):: Annotation; interpretation(force) {
+ resultWrong = String("wrong")::Annotation.
+
+ loop fold(db->entry:: Annotation, resultWrong->result):: Annotation{
+ switch variant(entry):: Annotation
+ case (Num) {resultWrong}
+ case (String) {resultWrong}
+
+ case (Func) {
+ if(entry["arguments"][0] == argFirst)::Annotation
+ {entry["arguments"][1]::Annotation; break}
+ else {result}
+ }
+ }
+}
+
+selectThird = function (db:: [Annotation], argFirst::Annotation, argSecond:: Annotation):: Annotation; interpretation(force){
+ resultWrong = String("wrong")::Annotation.
+
+ loop fold(db->entry:: Annotation, resultWrong->result):: Annotation{
+ switch variant(entry):: Annotation
+ case (Num) {resultWrong}
+ case (String) {resultWrong}
+
+ case (Func) {
+ if(entry["arguments"][0] == argFirst)::Annotation{
+ if (entry["arguments"][1] == argSecond):: Annotation{
+ entry["arguments"][2]:: Annotation; break
+ } else {result}
+ } else {result}
+ }
+ }
+}
+
+prepareCtrlArg = function(fnName:: string; interpretation(force),
+ scope:: Annotation; interpretation(force))
+ :: FnControl {
+
+ demandsDb = intrinsic query("kleo_fn_demand")::[Annotation].
+ decisionsDb = intrinsic query("kleo_scope_decision")::[Annotation].
+
+ demandKey = selectSecond(demandsDb, Func({name = fnName, arguments = []})):: Annotation.
+ decisionKey = Func({name="kleo_arg", arguments=[demandKey]}):: Annotation.
+
+ decision = selectThird(decisionsDb, scope, decisionKey)::Annotation.
+
+ switch variant(decision):: FnControl
+ case (Num) {Variant1()}
+ case (String) {Variant1()}
+ case (Func) {
+ switch(decision["name"]):: FnControl
+ case("variant1") {Variant1()}
+ case("variant2") {Variant2()}
+ case default {Variant1()}
+ }
+}
diff --git a/scripts/virtualization/virtualization.lp b/scripts/virtualization/virtualization.lp
new file mode 100644
index 0000000..9aa3f5a
--- /dev/null
+++ b/scripts/virtualization/virtualization.lp
@@ -0,0 +1,6 @@
+% INPUT:
+% virtDomain() - different virtualization domains
+
+virtDictDomains(Dom, Id):- Id = #sum{1, DomLess : virtDomain(DomLess), DomLess < Dom};
+ virtDomain(Dom).
+

Event Timeline