Page Menu
Home
Xreate
Search
Configure Global Search
Log In
Docs
Questions
Repository
Issues
Patches
Internal API
Files
F2729743
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Fri, Mar 13, 10:23 AM
Size
125 KB
Mime Type
text/x-diff
Expires
Sun, Mar 15, 10:23 AM (1 d, 17 h)
Engine
blob
Format
Raw Data
Handle
243150
Attached To
rXR Xreate
View Options
diff --git a/config/default.json b/config/default.json
index 807e420..157f4a6 100644
--- a/config/default.json
+++ b/config/default.json
@@ -1,69 +1,69 @@
{
"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",
"templates": {
"default": "*-",
"adhocs": "Adhoc.*",
"effects": "Effects.*",
"basic": "Attachments.*",
"ast": "AST.*",
"cfa": "CFA.*",
"dfa": "DFA.*",
- "compilation": "Compilation.functionEntry1*",
+ "compilation": "Compilation.*",
"diagnostic": "Diagnostic.*",
"ExpressionSerializer": "ExpressionSerializer.*",
"externc": "InterfaceExternC.*",
"types": "Types.*-",
"vendorsAPI/clang": "ClangAPI.*",
"vendorsAPI/xml2": "libxml2*",
"dsl": "Interpretation.*:InterpretationExamples.*",
"context": "Context.*",
"containers": "Containers.*",
"loops": "Loop.*"
}
}
}
diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt
index 78a19cc..e59b682 100644
--- a/cpp/src/CMakeLists.txt
+++ b/cpp/src/CMakeLists.txt
@@ -1,219 +1,219 @@
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}/../coco/)
set(COCO_SOURCE_FILES
${COCO_GRAMMAR_PATH}/Parser.cpp
${COCO_GRAMMAR_PATH}/Scanner.cpp)
INCLUDE_DIRECTORIES(${COCO_GRAMMAR_PATH})
add_custom_command(OUTPUT ${COCO_SOURCE_FILES}
COMMAND ${COCO_GRAMMAR_PATH}/gen-grammar ${COCO_EXECUTABLE} ${COCO_FRAMES_PATH}
WORKING_DIRECTORY ${COCO_GRAMMAR_PATH}
MAIN_DEPENDENCY ${COCO_GRAMMAR_PATH}/xreate.ATG
)
message(STATUS "COCO GRAMMAR BUILD STATUS:" ${COCO_OUTPUT})
# XREATE
#======================
set(SOURCE_FILES
- compilation/pointerarithmetic.cpp
+ compilation/operators.cpp
compilation/transformations.cpp
compilation/transformersaturation.cpp
pass/compilepass.cpp
pass/dfapass.cpp
analysis/dfagraph.cpp
pass/versionspass.cpp
compilation/targetinterpretation.cpp
attachments.cpp
ast.cpp
ExternLayer.cpp
analysis/cfagraph.cpp
analysis/aux.cpp
compilation/containers.cpp
compilation/advanced.cpp
clasplayer.cpp
compilation/latecontextcompiler2.cpp
query/context.cpp
llvmlayer.cpp
utils.cpp
passmanager-bare.cpp
passmanager-full.cpp
pass/abstractpass.cpp
pass/cfapass.cpp
pass/adhocpass.cpp
contextrule.cpp
query/containers.cpp
pass/interpretationpass.cpp
analysis/DominatorsTreeAnalysisProvider.cpp
serialization/expressionserializer.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 ${SOURCE_FILES} ${COCO_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
)
#${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/ast.cpp b/cpp/src/ast.cpp
index 6a6cccf..09498dc 100644
--- a/cpp/src/ast.cpp
+++ b/cpp/src/ast.cpp
@@ -1,915 +1,929 @@
#include "ast.h"
#include "ExternLayer.h"
#include <stdexcept>
#include <iostream>
namespace std{
std::size_t
hash<xreate::ScopedSymbol>::operator()(xreate::ScopedSymbol const& s) const
{return s.id ^ (s.version << 2);}
bool
equal_to<xreate::ScopedSymbol>::operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const
{ return __x.id == __y.id && __x.version == __y.version; }
}
using namespace std;
namespace xreate {
Atom<Identifier_t>::Atom(const std::wstring& value) {
__value = wstring_to_utf8(value);
}
Atom<Identifier_t>::Atom(std::string && name) : __value(name)
{}
const std::string&
Atom<Identifier_t>::get() const {
return __value;
}
Atom<Number_t>::Atom(wchar_t* value) {
//DEBT reconsider number literal recognition
__value = wcstol(value, 0, 10);
}
Atom<Number_t>::Atom(int value)
: __value(value) {
}
double
Atom<Number_t>::get()const {
return __value;
}
Atom<String_t>::Atom(const std::wstring& value) {
assert(value.size() >=2);
__value = wstring_to_utf8(value.substr(1, value.size() -2));
}
const std::string&
Atom<String_t>::get() const {
return __value;
}
class ExpressionHints {
public:
static bool
isStringValueValid(const Expression& e) {
switch (e.__state) {
case Expression::INVALID:
assert(false);
case Expression::IDENT:
case Expression::STRING:
return true;
case Expression::NUMBER:
case Expression::BINDING:
case Expression::VARIANT:
return false;
case Expression::COMPOUND:
{
switch (e.op) {
case Operator::CALL:
return true;
default: return false;
}
}
}
return false;
}
static bool
isDoubleValueValid(const Expression& e) {
switch (e.__state) {
case Expression::NUMBER:
case Expression::VARIANT:
return true;
case Expression::INVALID:
assert(false);
case Expression::IDENT:
case Expression::STRING:
case Expression::COMPOUND:
case Expression::BINDING:
return false;
}
return false;
}
};
class TypesResolver {
private:
const AST* ast;
std::map<std::string, TypeAnnotation> scope;
std::map<TypeAnnotation, int> signatures;
ExpandedType expandType(const TypeAnnotation &t, const std::vector<TypeAnnotation> &args = std::vector<TypeAnnotation>()) {
return TypesResolver(ast, scope, signatures)(t, args);
}
std::vector<TypeAnnotation>
expandOperands(const std::vector<TypeAnnotation>& operands) {
std::vector<TypeAnnotation> pack;
pack.reserve(operands.size());
std::transform(operands.begin(), operands.end(), std::inserter(pack, pack.end()),
[this](const TypeAnnotation & t) {
return expandType(t);
});
return pack;
}
public:
TypesResolver(const AST* root, const std::map<std::string, TypeAnnotation>& scopeOuter = std::map<std::string, TypeAnnotation>(),
std::map<TypeAnnotation, int> signaturesOuter = std::map<TypeAnnotation, int>())
: ast(root), scope(scopeOuter), signatures(signaturesOuter) {
}
ExpandedType
operator()(const TypeAnnotation &t, const std::vector<TypeAnnotation> &args = std::vector<TypeAnnotation>()) {
//assert(args.size() == t.bindings.size()); // invalid number of arguments
for (size_t i = 0; i < args.size(); ++i) {
scope[t.bindings.at(i)] = args.at(i);
}
switch (t.__operator) {
case TypeOperator::ARRAY:
{
assert(t.__operands.size() == 1);
Expanded<TypeAnnotation> elTy = expandType(t.__operands.at(0));
return ExpandedType(TypeAnnotation(tag_array, elTy, 0));
}
case TypeOperator::STRUCT:
{
assert(t.__operands.size());
std::vector<TypeAnnotation>&& pack = expandOperands(t.__operands);
auto tnew = TypeAnnotation(TypeOperator::STRUCT, move(pack));
tnew.fields = t.fields;
return ExpandedType(move(tnew));
};
case TypeOperator::CALL:
{
std::string alias = t.__valueCustom;
//find in local scope:
TypeAnnotation ty;
if (scope.count(alias)) {
ty = scope.at(alias);
} else if (ast->__indexTypeAliases.count(alias)) {
ty = ast->__indexTypeAliases.at(alias);
} else {
assert(false && "Undefined or external type");
}
std::vector<TypeAnnotation>&& operands = expandOperands(t.__operands);
TypeAnnotation signature(TypeOperator::CALL, move(operands));
signature.__valueCustom = alias;
if (signatures.count(signature)) {
auto link = TypeAnnotation(TypeOperator::LINK,{});
link.conjuctionId = signatures.at(signature);
return ExpandedType(move(link));
}
int cid = signatures.size();
signatures[signature] = cid;
TypeAnnotation tyResult = expandType(ty, operands);
tyResult.conjuctionId = cid;
return ExpandedType(move(tyResult));
};
case TypeOperator::CUSTOM:
{
std::string alias = t.__valueCustom;
/*
if (signatures.count(alias)) {
return ExpandedType(TypeAnnotation(TypeOperator::LINK, {t}));
}
signatures[alias].emplace(t);
*/
//find in local scope:
if (scope.count(alias)) {
return expandType(scope.at(alias));
}
// find in general scope:
if (ast->__indexTypeAliases.count(alias)) {
return expandType(ast->__indexTypeAliases.at(t.__valueCustom));
}
//if type is unknown keep it as is.
return ExpandedType(TypeAnnotation(t));
};
case TypeOperator::ACCESS:
{
std::string alias = t.__valueCustom;
ExpandedType tyAlias = ExpandedType(TypeAnnotation());
//find in local scope:
if (scope.count(alias)) {
tyAlias = expandType(scope.at(alias));
//find in global scope:
} else if ((ast->__indexTypeAliases.count(alias))) {
tyAlias = expandType(ast->__indexTypeAliases.at(alias));
} else {
assert(false && "Undefined or external type");
}
assert(tyAlias->__operator == TypeOperator::STRUCT);
for (const string& field : t.fields) {
auto fieldIt = std::find(tyAlias->fields.begin(), tyAlias->fields.end(), field);
assert(fieldIt != tyAlias->fields.end() && "unknown field");
int fieldId = fieldIt - tyAlias->fields.begin();
tyAlias = expandType(tyAlias->__operands.at(fieldId));
}
return tyAlias;
}
case TypeOperator::TUPLE:
{
assert(t.__operands.size());
std::vector<TypeAnnotation> pack;
pack.reserve(t.__operands.size());
std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(pack, pack.end()),
[this](const TypeAnnotation & t) {
return expandType(t);
});
return ExpandedType(TypeAnnotation(TypeOperator::TUPLE, move(pack)));
}
case TypeOperator::VARIANT:
{
return ExpandedType(TypeAnnotation(t));
}
case TypeOperator::NONE:
{
return ExpandedType(TypeAnnotation(t));
}
default:
assert(false);
}
assert(false);
return ExpandedType(TypeAnnotation());
}
};
TypeAnnotation::TypeAnnotation()
: __operator(TypeOperator::NONE), __value(TypePrimitive::Invalid)
{}
TypeAnnotation::TypeAnnotation(TypePrimitive typ)
: __value(typ) {
}
TypeAnnotation::TypeAnnotation(TypeOperator op, std::initializer_list<TypeAnnotation> operands)
: __operator(op), __operands(operands) {
}
TypeAnnotation::TypeAnnotation(TypeOperator op, std::vector<TypeAnnotation>&& operands)
: __operator(op), __operands(operands) {
}
TypeAnnotation::TypeAnnotation(llvm_array_tag, TypeAnnotation typ, int size)
: TypeAnnotation(TypeOperator::ARRAY,{typ}) {
__size = size;
}
bool
TypeAnnotation::isValid() const{
return !(__value == TypePrimitive::Invalid && __operator == TypeOperator::NONE);
}
bool
TypeAnnotation::operator<(const TypeAnnotation& t) const {
if (__operator != t.__operator) return __operator < t.__operator;
if (__operator == TypeOperator::NONE)
return __value < t.__value;
if (__operator == TypeOperator::CALL || __operator == TypeOperator::CUSTOM || __operator == TypeOperator::ACCESS) {
if (__valueCustom != t.__valueCustom)
return __valueCustom < t.__valueCustom;
}
return __operands < t.__operands;
}
/*
TypeAnnotation (struct_tag, std::initializer_list<TypeAnnotation>)
{}
*/
void
TypeAnnotation::addBindings(std::vector<Atom<Identifier_t>>&& params) {
bindings.reserve(bindings.size() + params.size());
std::transform(params.begin(), params.end(), std::inserter(bindings, bindings.end()),
[](const Atom<Identifier_t>& ident) {
return ident.get(); });
}
void
TypeAnnotation::addFields(std::vector<Atom<Identifier_t>>&& listFields) {
fields.reserve(fields.size() + listFields.size());
std::transform(listFields.begin(), listFields.end(), std::inserter(fields, fields.end()),
[](const Atom<Identifier_t>& ident) {
return ident.get(); });
}
unsigned int Expression::nextVacantId = 0;
Expression::Expression(const Atom<Number_t>& number)
: Expression() {
__state=NUMBER; op=Operator::NONE; __valueD=number.get();
}
Expression::Expression(const Atom<String_t>& a)
: Expression(){
__state=STRING; op=Operator::NONE; __valueS=a.get();
}
Expression::Expression(const Atom<Identifier_t> &ident)
: Expression() {
__state=IDENT; op=Operator::NONE; __valueS=ident.get();
}
Expression::Expression(const Operator &oprt, std::initializer_list<Expression> params)
: Expression() {
__state=COMPOUND; op=oprt;
if (op == Operator::CALL) {
assert(params.size() > 0);
Expression arg = *params.begin();
assert(arg.__state == Expression::IDENT);
__valueS = std::move(arg.__valueS);
operands.insert(operands.end(), params.begin() + 1, params.end());
return;
}
operands.insert(operands.end(), params.begin(), params.end());
}
void
Expression::setOp(Operator oprt) {
op = oprt;
switch (op) {
case Operator::NONE:
__state = INVALID;
break;
default:
__state = COMPOUND;
break;
}
}
void
Expression::addArg(Expression &&arg) {
operands.push_back(arg);
}
void
Expression::addTags(const std::list<Expression> tags) const{
std::transform(tags.begin(), tags.end(), std::inserter(this->tags, this->tags.end()),
[](const Expression& tag){
return make_pair(tag.getValueString(), tag);
});
}
void
Expression::addBindings(std::initializer_list<Atom<Identifier_t>> params) {
addBindings(params.begin(), params.end());
}
void
Expression::bindType(TypeAnnotation t) {
type = move(t);
}
void
Expression::addBlock(ManagedScpPtr scope) {
blocks.push_back(scope.operator->());
}
const std::vector<Expression>&
Expression::getOperands() const {
return operands;
}
double
Expression::getValueDouble() const {
return __valueD;
}
const std::string&
Expression::getValueString() const {
return __valueS;
}
void
Expression::setValue(const Atom<Identifier_t>&& v) {
__valueS = v.get();
}
void Expression::setValueDouble(double value) {
__valueD = value;
}
bool
Expression::isValid() const {
return (__state != INVALID);
}
bool
Expression::isDefined() const {
return (__state != BINDING);
}
Expression::Expression()
: __state(INVALID), op(Operator::NONE), id(nextVacantId++)
{ }
AST::AST() {
Attachments::init<VariableVersion>();
Attachments::init<Symbol>();
}
void
AST::addInterfaceData(const ASTInterface& interface, Expression&& data) {
__interfacesData.emplace(interface, move(data));
}
void
AST::addDFAData(Expression &&data) {
__dfadata.push_back(data);
}
void
AST::addExternData(ExternData &&data) {
__externdata.insert(__externdata.end(), data.entries.begin(), data.entries.end());
}
void
AST::add(Function* f) {
__functions.push_back(f);
__indexFunctions.emplace(f->getName(), __functions.size() - 1);
}
void
AST::add(MetaRuleAbstract *r) {
__rules.push_back(r);
}
void
AST::add(TypeAnnotation t, Atom<Identifier_t> alias) {
if (t.__operator == TypeOperator::VARIANT) {
for (int i = 0, size = t.fields.size(); i < size; ++i) {
__dictVariants.emplace(t.fields[i], make_pair(t, i));
}
}
__indexTypeAliases.emplace(alias.get(), move(t));
}
ManagedScpPtr
AST::add(CodeScope* scope) {
this->__scopes.push_back(scope);
return ManagedScpPtr(this->__scopes.size() - 1, &this->__scopes);
}
std::string
AST::getModuleName() {
const std::string name = "moduleTest";
return name;
}
ManagedPtr<Function>
AST::findFunction(const std::string& name) {
int count = __indexFunctions.count(name);
if (!count) {
return ManagedFnPtr::Invalid();
}
assert(count == 1);
auto range = __indexFunctions.equal_range(name);
return ManagedPtr<Function>(range.first->second, &this->__functions);
}
std::list<ManagedFnPtr>
AST::getAllFunctions() const {
const size_t size = __functions.size();
std::list<ManagedFnPtr> result;
for (size_t i = 0; i < size; ++i) {
result.push_back(ManagedFnPtr(i, &this->__functions));
}
return result;
}
//TASK select default specializations
std::list<ManagedFnPtr>
AST::getFunctionVariants(const std::string& name) const {
auto functions = __indexFunctions.equal_range(name);
std::list<ManagedFnPtr> result;
std::transform(functions.first, functions.second, inserter(result, result.end()),
[this](auto f) {
return ManagedFnPtr(f.second, &this->__functions);
});
return result;
}
template<>
ManagedPtr<Function>
AST::begin<Function>() {
return ManagedPtr<Function>(0, &this->__functions);
}
template<>
ManagedPtr<CodeScope>
AST::begin<CodeScope>() {
return ManagedPtr<CodeScope>(0, &this->__scopes);
}
template<>
ManagedPtr<MetaRuleAbstract>
AST::begin<MetaRuleAbstract>() {
return ManagedPtr<MetaRuleAbstract>(0, &this->__rules);
}
Expanded<TypeAnnotation>
AST::expandType(const TypeAnnotation &t) const {
return TypesResolver(this)(t);
}
Expanded<TypeAnnotation>
AST::findType(const std::string& name) {
// find in general scope:
if (__indexTypeAliases.count(name))
return expandType(__indexTypeAliases.at(name));
//if type is unknown keep it as is.
TypeAnnotation t(TypeOperator::CUSTOM,{});
t.__valueCustom = name;
return ExpandedType(move(t));
}
+ ExpandedType
+ AST::getType(const Expression& expression){
+ if (expression.type.isValid()){
+ return expandType(expression.type);
+ }
+
+ if (expression.__state == Expression::IDENT){
+ Symbol s = Attachments::get<Symbol>(expression);
+ return getType(CodeScope::getDeclaration(s));
+ }
+
+ assert(false && "Type can't be determined for an expression");
+ }
+
bool
AST::recognizeVariantIdentifier(Expression& identifier) {
assert(identifier.__state == Expression::IDENT);
std::string variant = identifier.getValueString();
if (!__dictVariants.count(variant)) {
return false;
}
auto record = __dictVariants.at(variant);
const TypeAnnotation& typ = record.first;
identifier.__state = Expression::VARIANT;
identifier.setValueDouble(record.second);
identifier.type = typ;
return true;
}
Function::Function(const Atom<Identifier_t>& name)
: __entry(new CodeScope(0)) {
__name = name.get();
}
void
Function::addTag(Expression&& tag, const TagModifier mod) {
string name = tag.getValueString();
__tags.emplace(move(name), move(tag));
}
const std::map<std::string, Expression>&
Function::getTags() const {
return __tags;
}
CodeScope*
Function::getEntryScope() const {
return __entry;
}
void
Function::addBinding(Atom <Identifier_t>&& name, Expression&& argument) {
__entry->addBinding(move(name), move(argument));
}
const std::string&
Function::getName() const {
return __name;
}
ScopedSymbol
CodeScope::registerIdentifier(const Expression& identifier) {
VariableVersion version = Attachments::get<VariableVersion>(identifier, VERSION_NONE);
auto result = __identifiers.emplace(identifier.getValueString(), __vCounter);
if (result.second){
++__vCounter;
return {__vCounter-1, version};
}
return {result.first->second, version};
}
bool
CodeScope::recognizeIdentifier(const Expression& identifier) const{
VariableVersion version = Attachments::get<VariableVersion>(identifier, VERSION_NONE);
const std::string& name = identifier.getValueString();
//search identifier in the current block
if (__identifiers.count(name)){
VNameId id = __identifiers.at(name);
Symbol s;
s.identifier = ScopedSymbol{id, version};
s.scope = const_cast<CodeScope*>(this);
Attachments::put<Symbol>(identifier, s);
return true;
}
//search in the parent scope
if (__parent)
{
return __parent->recognizeIdentifier(identifier);
}
return false;
}
ScopedSymbol
CodeScope::getSymbol(const std::string& alias){
assert(__identifiers.count(alias));
VNameId id = __identifiers.at(alias);
return {id, VERSION_NONE};
}
void
AST::postponeIdentifier(CodeScope* scope, const Expression& id) {
binUnrecognizedIdentifiers.emplace(scope, id);
}
void
AST::recognizePostponedIdentifiers() {
for(const auto& identifier: binUnrecognizedIdentifiers){
if (!identifier.first->recognizeIdentifier(identifier.second)){
//exception: Ident not found
std::cout << "Unknown symbol: "<< identifier.second.getValueString() << std::endl;
assert(false && "Symbol not found");
}
}
}
void
CodeScope::addBinding(Expression&& var, Expression&& argument) {
argument.__state = Expression::BINDING;
__bindings.push_back(var.getValueString());
ScopedSymbol binding = registerIdentifier(var);
__declarations[binding] = move(argument);
}
void
CodeScope::addDeclaration(Expression&& var, Expression&& body) {
ScopedSymbol s = registerIdentifier(var);
__declarations[s] = move(body);
}
CodeScope::CodeScope(CodeScope* parent)
: __parent(parent) {
}
CodeScope::~CodeScope() {
}
void
CodeScope::setBody(const Expression &body) {
__declarations[ScopedSymbol::RetSymbol] = body;
}
Expression&
CodeScope::getBody() {
return __declarations[ScopedSymbol::RetSymbol];
}
const Expression&
CodeScope::getDeclaration(const Symbol& symbol) {
CodeScope* self = symbol.scope;
return self->getDeclaration(symbol.identifier);
}
const Expression&
CodeScope::getDeclaration(const ScopedSymbol& symbol){
assert(__declarations.count(symbol) && "Symbol's declaration not found");
return __declarations.at(symbol);
}
void
RuleArguments::add(const Atom<Identifier_t> &arg, DomainAnnotation typ) {
emplace_back(arg.get(), typ);
}
void
RuleGuards::add(Expression&& e) {
push_back(e);
}
MetaRuleAbstract::
MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards)
: __args(std::move(args)), __guards(std::move(guards)) {
}
MetaRuleAbstract::~MetaRuleAbstract() {
}
RuleWarning::
RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom<String_t>&& message)
: MetaRuleAbstract(std::move(args), std::move(guards)), __message(message.get()), __condition(condition) {
}
RuleWarning::~RuleWarning() {
}
void
RuleWarning::compile(ClaspLayer& layer) {
//TODO restore addRuleWarning
//layer.addRuleWarning(*this);
}
bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2) {
return (s1.id < s2.id) || (s1.id==s2.id && s1.version < s2.version);
}
bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2) {
return (s1.id == s2.id) && (s1.version == s2.version);
}
bool operator<(const Symbol& s1, const Symbol& s2) {
return (s1.scope < s2.scope) || (s1.scope == s2.scope && s1.identifier < s2.identifier);
}
bool operator==(const Symbol& s1, const Symbol& s2) {
return (s1.scope == s2.scope) && (s1.identifier == s2.identifier);
}
bool operator<(const Expression&a, const Expression&b) {
if (a.__state != b.__state) return a.__state < b.__state;
assert(a.__state != Expression::INVALID);
switch (a.__state) {
case Expression::IDENT:
case Expression::STRING:
case Expression::VARIANT:
return a.getValueString() < b.getValueString();
case Expression::NUMBER:
return a.getValueDouble() < b.getValueDouble();
case Expression::COMPOUND:
{
assert(a.blocks.size() == 0);
assert(b.blocks.size() == 0);
if (a.op != b.op){
return a.op < b.op;
}
bool flagAValid = ExpressionHints::isStringValueValid(a);
bool flagBValid = ExpressionHints::isStringValueValid(b);
if (flagAValid != flagBValid) {
return flagAValid < flagBValid;
}
if (flagAValid){
if (a.getValueString() != b.getValueString()) {
return a.getValueString() < b.getValueString();
}
}
flagAValid = ExpressionHints::isDoubleValueValid(a);
flagBValid = ExpressionHints::isDoubleValueValid(b);
if (flagAValid != flagBValid) {
return flagAValid < flagBValid;
}
if (flagAValid){
if (a.getValueDouble() != b.getValueDouble()) {
return a.getValueDouble() < b.getValueDouble();
}
}
if (a.operands.size() != b.operands.size()) {
return (a.operands.size() < b.operands.size());
}
for (size_t i = 0; i < a.operands.size(); ++i) {
bool result = a.operands[i] < b.operands[i];
if (result) return true;
}
return false;
}
case Expression::BINDING:
case Expression::INVALID:
assert(false);
}
return false;
}
bool
Expression::operator==(const Expression& other) const {
if (this->__state != other.__state) return false;
if (ExpressionHints::isStringValueValid(*this)) {
if (this->__valueS != other.__valueS) return false;
}
if (ExpressionHints::isDoubleValueValid(*this)) {
if (this->__valueD != other.__valueD) return false;
}
if (this->__state != Expression::COMPOUND) {
return true;
}
if (this->op != other.op) {
return false;
}
if (this->operands.size() != other.operands.size()) {
return false;
}
for (size_t i = 0; i<this->operands.size(); ++i) {
if (!(this->operands[i] == other.operands[i])) return false;
}
assert(!this->blocks.size());
assert(!other.blocks.size());
return true;
}
const ScopedSymbol
ScopedSymbol::RetSymbol = ScopedSymbol{0, VERSION_NONE};
}
diff --git a/cpp/src/ast.h b/cpp/src/ast.h
index 8c24e48..5c8623d 100644
--- a/cpp/src/ast.h
+++ b/cpp/src/ast.h
@@ -1,556 +1,557 @@
#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 String_t {
};
struct Identifier_t {
};
struct Number_t {
};
struct Type_t {
};
template<typename A>
class Atom {
};
//DEBT hold for all atoms/identifiers Parser::Token data, like line:col position
template<> class
Atom<Identifier_t> {
public:
Atom(const std::wstring& value);
Atom(std::string && name);
const std::string& get() const;
private:
std::string __value;
};
template<>
class Atom<Number_t> {
public:
Atom(wchar_t* value);
Atom(int value);
double get()const;
private:
double __value;
};
template<>
class Atom<String_t> {
public:
Atom(const std::wstring& value);
const std::string& get() const;
private:
std::string __value;
};
enum class TypePrimitive {
Invalid, Bool, I8, I32, I64, Num, Int, Float, String
};
enum class TypeOperator {
NONE, CALL, CUSTOM, VARIANT, ARRAY, TUPLE, STRUCT, ACCESS, LINK
};
struct llvm_array_tag {
};
struct struct_tag {
};
const llvm_array_tag tag_array = llvm_array_tag();
const struct_tag tag_struct = struct_tag();
class TypeAnnotation {
public:
TypeAnnotation();
TypeAnnotation(const Atom<Type_t>& typ);
TypeAnnotation(TypePrimitive typ);
TypeAnnotation(llvm_array_tag, TypeAnnotation typ, int size);
TypeAnnotation(TypeOperator op, std::initializer_list<TypeAnnotation> operands);
TypeAnnotation(TypeOperator op, std::vector<TypeAnnotation>&& operands);
void addBindings(std::vector<Atom<Identifier_t>>&& params);
void addFields(std::vector<Atom<Identifier_t>>&& listFields);
bool operator<(const TypeAnnotation& t) const;
// TypeAnnotation (struct_tag, std::initializer_list<TypePrimitive>);
bool isValid() const;
TypeOperator __operator = TypeOperator::NONE;
std::vector<TypeAnnotation> __operands;
TypePrimitive __value;
std::string __valueCustom;
int conjuctionId = -1; //conjunction point id (relevant for recursive types)
uint64_t __size = 0;
std::vector<std::string> fields;
std::vector<std::string> bindings;
private:
};
enum class Operator {
ADD, SUB, MUL, DIV,
EQU, NE, NEG, LSS,
LSE, GTR, GTE, LIST,
LIST_RANGE, LIST_NAMED,
CALL, CALL_INTRINSIC, NONE,
IMPL/* implication */, MAP,
FOLD, FOLD_INF, LOOP_CONTEXT,
INDEX, IF, SWITCH, SWITCH_ADHOC,
CASE, CASE_DEFAULT, LOGIC_AND,
ADHOC, CONTEXT_RULE
};
class Function;
class AST;
class CodeScope;
class MetaRuleAbstract;
template<class Target>
struct ManagedPtr {
static ManagedPtr<Target> Invalid() {
return ManagedPtr<Target>();
}
ManagedPtr() : __storage(0) {
}
ManagedPtr(unsigned int id, const std::vector<Target*>* storage)
: __id(id), __storage(storage) {
}
Target&
operator*() const {
assert(isValid() && "Invalid Ptr");
return *__storage->at(__id);
}
void operator=(const ManagedPtr<Target>& other) {
__id = other.__id;
__storage = other.__storage;
}
bool
operator==(const ManagedPtr<Target>& other) {
return isValid() && (__id == other.__id);
}
Target*
operator->() const noexcept {
assert(isValid() && "Invalid Ptr");
return __storage->at(__id);
}
inline bool isValid() const {
return (__storage) && (0 <= __id) && (__id < __storage->size());
}
inline operator bool() const {
return isValid();
}
ManagedPtr<Target>& operator++() {
++__id;
return *this;
}
inline unsigned int id() const {
return __id;
}
private:
unsigned int __id = 0;
const std::vector<Target*> * __storage = 0;
};
typedef ManagedPtr<Function> ManagedFnPtr;
typedef ManagedPtr<CodeScope> ManagedScpPtr;
typedef ManagedPtr<MetaRuleAbstract> ManagedRulePtr;
const ManagedScpPtr NO_SCOPE = ManagedScpPtr(UINT_MAX, 0);
//To update ExpressionHints in case of any changes
struct Expression {
friend class CodeScope;
friend class ClaspLayer;
friend class CFAPass;
friend class ExpressionHints;
Expression(const Operator &oprt, std::initializer_list<Expression> params);
Expression(const Atom<Identifier_t>& ident);
Expression(const Atom<Number_t>& number);
Expression(const Atom<String_t>& a);
Expression();
void setOp(Operator oprt);
void addArg(Expression&& arg);
void addBindings(std::initializer_list<Atom<Identifier_t>> params);
void bindType(TypeAnnotation t);
template<class InputIt>
void addBindings(InputIt paramsBegin, InputIt paramsEnd);
void addTags(const std::list<Expression> tags) const;
void addBlock(ManagedScpPtr scope);
const std::vector<Expression>& getOperands() const;
double getValueDouble() const;
void setValueDouble(double value);
const std::string& getValueString() const;
void setValue(const Atom<Identifier_t>&& v);
bool isValid() const;
bool isDefined() const;
bool operator==(const Expression& other) const;
enum {
INVALID, COMPOUND, IDENT, NUMBER, STRING, VARIANT, BINDING
} __state = INVALID;
Operator op;
unsigned int id;
std::vector<std::string> bindings;
std::map<std::string, size_t> __indexBindings;
std::vector<Expression> operands;
TypeAnnotation type;
mutable std::map<std::string, Expression> tags;
std::list<CodeScope*> blocks;
private:
std::string __valueS;
double __valueD;
static unsigned int nextVacantId;
};
bool operator< (const Expression&, const Expression&);
template<class InputIt>
void Expression::addBindings(InputIt paramsBegin, InputIt paramsEnd) {
size_t index = bindings.size();
std::transform(paramsBegin, paramsEnd, std::inserter(bindings, bindings.end()),
[&index, this] (const Atom<Identifier_t> atom) {
std::string key = atom.get();
this->__indexBindings[key] = index++;
return key;
});
}
typedef std::list<Expression> ExpressionList;
enum class TagModifier {
NONE, ASSERT, REQUIRE
};
enum class DomainAnnotation {
FUNCTION, VARIABLE
};
class RuleArguments : public std::vector<std::pair<std::string, DomainAnnotation>>
{
public:
void add(const Atom<Identifier_t>& name, DomainAnnotation typ);
};
class RuleGuards : public std::vector<Expression> {
public:
void add(Expression&& e);
};
class ClaspLayer;
class LLVMLayer;
class MetaRuleAbstract {
public:
MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards);
virtual ~MetaRuleAbstract();
virtual void compile(ClaspLayer& layer) = 0;
protected:
RuleArguments __args;
RuleGuards __guards;
};
class RuleWarning : public MetaRuleAbstract {
friend class ClaspLayer;
public:
RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom<String_t>&& message);
virtual void compile(ClaspLayer& layer);
~RuleWarning();
private:
std::string __message;
Expression __condition;
};
typedef unsigned int VNameId;
typedef int VariableVersion;
const VariableVersion VERSION_NONE = -2;
const VariableVersion VERSION_INIT = 0;
template<>
struct AttachmentsDict<VariableVersion>
{
typedef VariableVersion Data;
static const unsigned int key = 6;
};
struct ScopedSymbol{
VNameId id;
VariableVersion version;
static const ScopedSymbol RetSymbol;
};
struct Symbol {
ScopedSymbol identifier;
CodeScope * scope;
};
template<>
struct AttachmentsDict<Symbol>
{
typedef Symbol Data;
static const unsigned int key = 7;
};
}
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;
};
}
namespace xreate {
typedef std::pair<Expression, TagModifier> Tag;
bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2);
bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2);
bool operator<(const Symbol& s1, const Symbol& s2);
bool operator==(const Symbol& s1, const Symbol& s2);
class CodeScope {
friend class Function;
friend class PassManager;
public:
CodeScope(CodeScope* parent = 0);
void setBody(const Expression& body);
Expression& getBody();
void addDeclaration(Expression&& var, Expression&& body);
void addBinding(Expression&& var, Expression&& argument);
static const Expression& getDeclaration(const Symbol& symbol);
const Expression& getDeclaration(const ScopedSymbol& symbol);
~CodeScope();
std::vector<std::string> __bindings;
std::map<std::string, VNameId> __identifiers;
CodeScope* __parent;
//TODO move __definitions to SymbolsAttachments data
//NOTE: definition of return type has zero(0) variable index
std::unordered_map<ScopedSymbol, Expression> __declarations;
std::vector<Expression> tags;
std::vector<Expression> contextRules;
private:
VNameId __vCounter = 1;
ScopedSymbol registerIdentifier(const Expression& identifier);
public:
bool recognizeIdentifier(const Expression& identifier) const;
ScopedSymbol getSymbol(const std::string& alias);
};
class Function {
friend class Expression;
friend class CodeScope;
friend class AST;
public:
Function(const Atom<Identifier_t>& name);
void addBinding(Atom <Identifier_t>&& name, Expression&& argument);
void addTag(Expression&& tag, const TagModifier mod);
const std::string& getName() const;
const std::map<std::string, Expression>& getTags() const;
CodeScope* getEntryScope() const;
CodeScope* __entry;
std::string __name;
bool isPrefunction = false; //SECTIONTAG adhoc Function::isPrefunction flag
Expression guardContext;
private:
std::map<std::string, Expression> __tags;
};
class ExternData;
struct ExternEntry {
std::string package;
std::vector<std::string> headers;
};
typedef Expanded<TypeAnnotation> ExpandedType;
enum ASTInterface {
CFA, DFA, Extern, Adhoc
};
struct FunctionSpecialization {
std::string guard;
size_t id;
};
struct FunctionSpecializationQuery {
std::unordered_set<std::string> context;
};
template<>
struct AttachmentsId<Expression>{
static unsigned int getId(const Expression& expression){
return expression.id;
}
};
template<>
struct AttachmentsId<Symbol>{
static unsigned int getId(const Symbol& s){
return s.scope->__declarations.at(s.identifier).id;
}
};
template<>
struct AttachmentsId<ManagedFnPtr>{
static unsigned int getId(const ManagedFnPtr& f){
const Symbol symbolFunction{ScopedSymbol::RetSymbol, f->getEntryScope()};
return AttachmentsId<Symbol>::getId(symbolFunction);
}
};
class AST {
public:
AST();
//TASK extern and DFA interfaces move into addInterfaceData
/**
* DFA Interface
*/
void addDFAData(Expression&& data);
/**
* Extern Interface
*/
void addExternData(ExternData&& data);
void addInterfaceData(const ASTInterface& interface, Expression&& data);
void add(Function* f);
void add(MetaRuleAbstract* r);
ManagedScpPtr add(CodeScope* scope);
std::string getModuleName();
ManagedPtr<Function> findFunction(const std::string& name);
typedef std::multimap<std::string, unsigned int> FUNCTIONS_REGISTRY;
std::list<ManagedFnPtr> getAllFunctions() const;
std::list<ManagedFnPtr> getFunctionVariants(const std::string& name) const;
template<class Target>
ManagedPtr<Target> begin();
std::vector<ExternEntry> __externdata;
std::list<Expression> __dfadata; //TODO move to more appropriate place
std::list<std::string> __rawImports; //TODO move to more appropriate place
std::multimap<ASTInterface, Expression> __interfacesData; //TODO CFA data here.
private:
std::vector<MetaRuleAbstract*> __rules;
std::vector<Function*> __functions;
std::vector<CodeScope*> __scopes;
FUNCTIONS_REGISTRY __indexFunctions;
// ***** TYPES SECTION *****
public:
std::map<std::string, TypeAnnotation> __indexTypeAliases;
ExpandedType expandType(const TypeAnnotation &t) const;
ExpandedType findType(const std::string& name);
+ ExpandedType getType(const Expression& expression);
void add(TypeAnnotation t, Atom<Identifier_t> alias);
//TODO revisit enums/variants, move to codescope
bool recognizeVariantIdentifier(Expression& identifier);
private:
std::map<std::string, std::pair<TypeAnnotation, int>> __dictVariants;
ExpandedType expandType(const TypeAnnotation &t, std::map<std::string, TypeAnnotation> scope,
const std::vector<TypeAnnotation> &args = std::vector<TypeAnnotation>()) const;
// ***** SYMBOL RECOGNITION *****
public:
std::set<std::pair<CodeScope*, Expression>> binUnrecognizedIdentifiers;
public:
void postponeIdentifier(CodeScope* scope, const Expression& id);
void recognizePostponedIdentifiers();
};
template<>
ManagedPtr<Function>
AST::begin<Function>();
template<>
ManagedPtr<CodeScope>
AST::begin<CodeScope>();
template<>
ManagedPtr<MetaRuleAbstract>
AST::begin<MetaRuleAbstract>();
}
#endif // AST_H
diff --git a/cpp/src/compilation/advanced.cpp b/cpp/src/compilation/advanced.cpp
index c83705f..f5c489b 100644
--- a/cpp/src/compilation/advanced.cpp
+++ b/cpp/src/compilation/advanced.cpp
@@ -1,404 +1,399 @@
/*
* File: InstructionsAdvanced.cpp
* Author: pgess
*
* Created on June 26, 2016, 6:00 PM
*/
//#include <compilation/transformations.h>
#include "compilation/advanced.h"
#include "compilation/containers.h"
#include "compilation/transformersaturation.h"
#include "query/context.h"
#include "query/containers.h"
#include "llvmlayer.h"
#include "ast.h"
using namespace std;
using namespace llvm;
using namespace xreate;
using namespace xreate::containers;
using namespace xreate::compilation;
#define NAME(x) (hintRetVar.empty()? x : hintRetVar)
#define UNUSED(x) (void)(x)
#define EXPAND_CONTEXT \
LLVMLayer* llvm = context.pass->man->llvm; \
compilation::AbstractCodeScopeUnit* scope = context.scope; \
compilation::FunctionUnit* function = context.function;
Advanced::Advanced(compilation::Context ctx)
: context(ctx), tyNum(static_cast<llvm::IntegerType*> (ctx.pass->man->llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::Num))))) {
}
llvm::Value*
Advanced::compileMapSolidOutput(const Expression &expr, const std::string hintRetVar) {
EXPAND_CONTEXT
//initialization
Symbol symbolIn = Attachments::get<Symbol>(expr.getOperands()[0]);
ImplementationRec<SOLID> implIn = containers::Query::queryImplementation(symbolIn).extract<SOLID>(); // impl of input list
size_t size = implIn.size;
CodeScope* scopeLoop = expr.blocks.front();
std::string varEl = scopeLoop->__bindings[0];
Iterator* it = Iterator::create(context, symbolIn);
llvm::Value *rangeFrom = it->begin();
llvm::Value *rangeTo = it->end();
//definitions
ArrayType* tyNumArray = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::Num, size))));
llvm::IRBuilder<> &builder = llvm->builder;
llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "loop", function->raw);
llvm::BasicBlock *blockBeforeLoop = builder.GetInsertBlock();
llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "postloop", function->raw);
Value* dataOut = llvm->builder.CreateAlloca(tyNumArray, ConstantInt::get(tyNum, size), NAME("map"));
// * initial check
Value* condBefore = builder.CreateICmpSLE(rangeFrom, rangeTo);
builder.CreateCondBr(condBefore, blockLoop, blockAfterLoop);
// create PHI:
builder.SetInsertPoint(blockLoop);
llvm::PHINode *stateLoop = builder.CreatePHI(tyNum, 2, "mapIt");
stateLoop->addIncoming(rangeFrom, blockBeforeLoop);
// loop body:
Value* elIn = it->get(stateLoop, varEl);
compilation::AbstractCodeScopeUnit* scopeLoopUnit = function->getScopeUnit(scopeLoop);
scopeLoopUnit->bindArg(elIn, move(varEl));
Value* elOut = scopeLoopUnit->compile();
Value *pElOut = builder.CreateGEP(dataOut, ArrayRef<Value *>(std::vector<Value*>{ConstantInt::get(tyNum, 0), stateLoop}));
builder.CreateStore(elOut, pElOut);
//next iteration preparing
Value *stateLoopNext = builder.CreateAdd(stateLoop, llvm::ConstantInt::get(tyNum, 1));
stateLoop->addIncoming(stateLoopNext, builder.GetInsertBlock());
//next iteration checks:
Value* condAfter = builder.CreateICmpSLE(stateLoopNext, rangeTo);
builder.CreateCondBr(condAfter, blockLoop, blockAfterLoop);
//finalization:
builder.SetInsertPoint(blockAfterLoop);
return dataOut;
}
Value*
Advanced::compileArrayIndex(llvm::Value* aggregate, std::vector<llvm::Value *> indexes, std::string hintRetVar) {
EXPAND_CONTEXT
UNUSED(function);
indexes.insert(indexes.begin(), llvm::ConstantInt::get(tyNum, 0));
llvm::Value *pEl = llvm->builder.CreateGEP(aggregate, llvm::ArrayRef<llvm::Value *>(indexes));
return llvm->builder.CreateLoad(pEl, NAME("el"));
}
Value*
Advanced::compileStructIndex(llvm::Value* aggregate, const ExpandedType& t, const std::string& idx) {
EXPAND_CONTEXT
UNUSED(scope);
-
TypeUtils types(llvm);
-
std::vector<std::string>&& fields = types.getStructFields(t);
+
for (unsigned i = 0, size = fields.size(); i < size; ++i) {
if (fields.at(i) == idx) {
- std::vector<llvm::Value*> refs;
-
- llvm::IntegerType* tyInt = llvm::Type::getInt32Ty(llvm::getGlobalContext());
- llvm::ConstantInt* zero = llvm::ConstantInt::get(tyInt, 0, false);
-
- llvm::BasicBlock *blockSafe = llvm::BasicBlock::Create(llvm::getGlobalContext(), "safe", function->raw);
-
+ //TODO DISABLEDFEATURE validptr
// TODO review safety check: validPtr for `aggregate`
// SECTIONTAG validptr exception
- PointerType* tyAggr = dyn_cast<PointerType>(aggregate->getType());
- llvm::Value* null = llvm::ConstantPointerNull::get(tyAggr);
- Value* condNull = llvm->builder.CreateICmpNE(aggregate, null);
-
- llvm::BasicBlock *blockException = llvm::BasicBlock::Create(llvm::getGlobalContext(), "exception", function->raw);
- llvm->builder.CreateCondBr(condNull, blockSafe, blockException);
- llvm->initExceptionBlock(blockException);
-
- llvm->builder.SetInsertPoint(blockSafe);
- std::vector<Value*> indexes;
+// std::vector<llvm::Value*> refs;
+// llvm::BasicBlock *blockSafe = llvm::BasicBlock::Create(llvm::getGlobalContext(), "safe", function->raw);
+// PointerType* tyAggr = dyn_cast<PointerType>(aggregate->getType());
+// llvm::Value* null = llvm::ConstantPointerNull::get(tyAggr);
+// Value* condNull = llvm->builder.CreateICmpNE(aggregate, null);
+//
+// llvm::BasicBlock *blockException = llvm::BasicBlock::Create(llvm::getGlobalContext(), "exception", function->raw);
+// llvm->builder.CreateCondBr(condNull, blockSafe, blockException);
+// llvm->initExceptionBlock(blockException);
+//
+// llvm->builder.SetInsertPoint(blockSafe);
//dereference pointer
if (types.isPointer(t)) {
- indexes.push_back(zero);
+ llvm::Value* addr = llvm->builder.CreateConstGEP2_32(nullptr, aggregate, 0, i);
+ return llvm->builder.CreateLoad(addr);
}
- indexes.push_back(ConstantInt::get(tyInt, i));
-
- Value* addr = llvm->builder.CreateGEP(aggregate, indexes);
- return llvm->builder.CreateLoad(addr);
+ aggregate->getType()->dump();
+ return llvm->builder.CreateExtractValue(aggregate, llvm::ArrayRef<unsigned>{i});
}
}
assert(false && "not found required struct field");
return nullptr;
}
llvm::Value*
Advanced::compileFold(const Expression& fold, const std::string& hintRetVar) {
EXPAND_CONTEXT
assert(fold.op == Operator::FOLD);
//initialization:
Symbol varInSymbol = Attachments::get<Symbol>(fold.getOperands()[0]);
Implementation info = Query::queryImplementation(varInSymbol);
Iterator* it = Iterator::create(context, varInSymbol);
llvm::Value* rangeBegin = it->begin();
llvm::Value* rangeEnd = it->end();
llvm::Value* accumInit = scope->process(fold.getOperands()[1]);
std::string varIn = fold.getOperands()[0].getValueString();
std::string varAccum = fold.bindings[1];
std::string varEl = fold.bindings[0];
llvm::BasicBlock *blockBeforeLoop = llvm->builder.GetInsertBlock();
std::unique_ptr<TransformerSaturation> transformerSaturation(new TransformerSaturation(blockBeforeLoop, context.pass->managerTransformations));
llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold", function->raw);
llvm::BasicBlock *blockLoopBody = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold_body", function->raw);
llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold_after", function->raw);
llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold_next", function->raw);
llvm->builder.CreateBr(blockLoop);
// * create phi
llvm->builder.SetInsertPoint(blockLoop);
llvm::PHINode *accum = llvm->builder.CreatePHI(accumInit->getType(), 2, varAccum);
accum->addIncoming(accumInit, blockBeforeLoop);
llvm::PHINode *itLoop = llvm->builder.CreatePHI(rangeBegin->getType(), 2, "foldIt");
itLoop->addIncoming(rangeBegin, blockBeforeLoop);
// * loop checks
Value* condRange = llvm->builder.CreateICmpNE(itLoop, rangeEnd);
llvm->builder.CreateCondBr(condRange, blockLoopBody, blockAfterLoop);
// * loop body
llvm->builder.SetInsertPoint(blockLoopBody);
CodeScope* scopeLoop = fold.blocks.front();
compilation::AbstractCodeScopeUnit* loopUnit = function->getScopeUnit(scopeLoop);
Value* elIn = it->get(itLoop);
loopUnit->bindArg(accum, move(varAccum));
loopUnit->bindArg(elIn, move(varEl));
Value* accumNext = loopUnit->compile();
// * Loop saturation checks
bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockNext, blockAfterLoop, context);
llvm::BasicBlock* blockSaturation = llvm->builder.GetInsertBlock();
if (!flagSaturationTriggered){
llvm->builder.CreateBr(blockNext);
}
// * computing next iteration state
llvm->builder.SetInsertPoint(blockNext);
Value *itLoopNext = it->advance(itLoop);
accum->addIncoming(accumNext, llvm->builder.GetInsertBlock());
itLoop->addIncoming(itLoopNext, llvm->builder.GetInsertBlock());
llvm->builder.CreateBr(blockLoop);
// * finalization:
llvm->builder.SetInsertPoint(blockAfterLoop);
if (!flagSaturationTriggered){
return accum;
}
llvm::PHINode* result = llvm->builder.CreatePHI(accumInit->getType(), 2);
result->addIncoming(accum, blockLoop);
result->addIncoming(accumNext, blockSaturation);
return result;
}
llvm::Value*
Advanced::compileFoldInf(const Expression& fold, const std::string& hintRetVar) {
EXPAND_CONTEXT
assert(fold.op == Operator::FOLD_INF);
std::string accumName = fold.bindings[0];
llvm::Value* accumInit = scope->process(fold.getOperands()[0]);
llvm::BasicBlock *blockBeforeLoop = llvm->builder.GetInsertBlock();
llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "foldinf", function->raw);
llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm::getGlobalContext(), "foldinf_next", function->raw);
llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "foldinf_post", function->raw);
std::unique_ptr<TransformerSaturation> transformerSaturation(new TransformerSaturation(blockBeforeLoop, context.pass->managerTransformations));
llvm->builder.CreateBr(blockLoop);
// * create phi
llvm->builder.SetInsertPoint(blockLoop);
llvm::PHINode *accum = llvm->builder.CreatePHI(accumInit->getType(), 2, accumName);
accum->addIncoming(accumInit, blockBeforeLoop);
// * loop body
CodeScope* scopeLoop = fold.blocks.front();
compilation::AbstractCodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop);
unitLoop->bindArg(accum, move(accumName));
Value* accumNext = unitLoop->compile();
// * Loop saturation checks
bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockNext, blockAfterLoop, context);
assert(flagSaturationTriggered);
// * computing next iteration state
llvm->builder.SetInsertPoint(blockNext);
accum->addIncoming(accumNext, llvm->builder.GetInsertBlock());
llvm->builder.CreateBr(blockLoop);
// finalization:
llvm->builder.SetInsertPoint(blockAfterLoop);
return accumNext;
}
llvm::Value*
Advanced::compileIf(const Expression& exprIf, const std::string& hintRetVar) {
EXPAND_CONTEXT
//initialization:
const Expression& condExpr = exprIf.getOperands()[0];
llvm::IRBuilder<>& builder = llvm->builder;
//llvm::Type* tyResultType = llvm->toLLVMType(llvm->ast->expandType(exprIf.type));
llvm::BasicBlock *blockAfter = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifAfter", function->raw);
llvm::BasicBlock *blockTrue = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifTrue", function->raw);
llvm::BasicBlock *blockFalse = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifFalse", function->raw);
llvm::Value* cond = scope->process(condExpr);
llvm->builder.CreateCondBr(cond, blockTrue, blockFalse);
builder.SetInsertPoint(blockTrue);
CodeScope* scopeTrue = exprIf.blocks.front();
llvm::Value* resultTrue = function->getScopeUnit(scopeTrue)->compile();
blockTrue = builder.GetInsertBlock();
builder.CreateBr(blockAfter);
builder.SetInsertPoint(blockFalse);
CodeScope* scopeFalse = exprIf.blocks.back();
llvm::Value* resultFalse = function->getScopeUnit(scopeFalse)->compile();
blockFalse = builder.GetInsertBlock();
builder.CreateBr(blockAfter);
builder.SetInsertPoint(blockAfter);
llvm::PHINode *ret = builder.CreatePHI(resultTrue->getType(), 2, NAME("if"));
ret->addIncoming(resultTrue, blockTrue);
ret->addIncoming(resultFalse, blockFalse);
return ret;
}
//TODO Switch: default variant no needed when all possible conditions are considered
llvm::Value*
Advanced::compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar) {
EXPAND_CONTEXT
+ AST* root = context.pass->man->root;
UNUSED(function);
+
assert(exprSwitch.operands.size() >= 2);
assert(exprSwitch.operands[1].op == Operator::CASE_DEFAULT && "No default case in Switch Statement");
int countCases = exprSwitch.operands.size() - 1;
llvm::IRBuilder<>& builder = llvm->builder;
llvm::BasicBlock* blockProlog = builder.GetInsertBlock();
llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "switchAfter", function->raw);
builder.SetInsertPoint(blockEpilog);
- llvm::Type* exprSwitchType = llvm->toLLVMType(ExpandedType(exprSwitch.type));
+ llvm::Type* exprSwitchType = llvm->toLLVMType(root->getType(exprSwitch));
llvm::PHINode *ret = builder.CreatePHI(exprSwitchType, countCases, NAME("switch"));
builder.SetInsertPoint(blockProlog);
llvm::Value * conditionSwitch = scope->process(exprSwitch.operands[0]);
llvm::BasicBlock *blockDefault = llvm::BasicBlock::Create(llvm::getGlobalContext(), "caseDefault", function->raw);
llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(conditionSwitch, blockDefault, countCases);
for (int size = exprSwitch.operands.size(), i = 2; i < size; ++i) {
llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm::getGlobalContext(), "case" + std::to_string(i), function->raw);
llvm::Value* condCase = function->getScopeUnit(exprSwitch.operands[i].blocks.front())->compile();
builder.SetInsertPoint(blockCase);
llvm::Value* resultCase = function->getScopeUnit(exprSwitch.operands[i].blocks.back())->compile();
builder.CreateBr(blockEpilog);
ret->addIncoming(resultCase, builder.GetInsertBlock());
builder.SetInsertPoint(blockProlog);
instructionSwitch->addCase(dyn_cast<llvm::ConstantInt>(condCase), blockCase);
}
//compile default block:
builder.SetInsertPoint(blockDefault);
CodeScope* scopeDefault = exprSwitch.operands[1].blocks.front();
llvm::Value* resultDefault = function->getScopeUnit(scopeDefault)->compile();
builder.CreateBr(blockEpilog);
ret->addIncoming(resultDefault, builder.GetInsertBlock());
builder.SetInsertPoint(blockEpilog);
return ret;
}
//TODO recognize cases to make const arrays/stored in global mem/stack alloced.
llvm::Value*
Advanced::compileListAsSolidArray(const Expression &expr, const std::string& hintRetVar) {
EXPAND_CONTEXT
UNUSED(scope);
UNUSED(function);
AST* root = context.pass->man->root;
const size_t& length = expr.getOperands().size();
const Expression& expression = expr;
llvm::Value* zero = ConstantInt::get(tyNum, 0);
llvm::Value* one = ConstantInt::get(tyNum, 1);
- ExpandedType typAggrExpanded = root->expandType(expression.type);
+ ExpandedType typAggrExpanded = root->getType(expression);
assert(typAggrExpanded->__operator == TypeOperator::ARRAY);
llvm::Type* typEl = llvm->toLLVMType(ExpandedType(typAggrExpanded->__operands[0]));
ArrayType* typAggr = (ArrayType*) llvm::ArrayType::get(typEl, length);
llvm::Value* list = llvm->builder.CreateAlloca(typAggr, ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), length, false), hintRetVar);
const std::vector<Expression>& operands = expression.getOperands();
llvm::Value* addrOperand = llvm->builder.CreateGEP(typAggr, list, ArrayRef<Value *>(std::vector<Value*>{zero, zero}));
llvm->builder.CreateStore(scope->process(operands.front()), addrOperand) ;
for (auto i=++operands.begin(); i!=operands.end(); ++i){
addrOperand = llvm->builder.CreateGEP(typEl, addrOperand, ArrayRef<Value *>(std::vector<Value*>{one}));
llvm->builder.CreateStore(scope->process(*i), addrOperand) ;
}
return list;
// Value* listDest = l.builder.CreateAlloca(typList, ConstantInt::get(typI32, __size), *hintRetVar);
// l.buil1der.CreateMemCpy(listDest, listSource, __size, 16);
}
llvm::Value*
Advanced::compileConstantStringAsPChar(const string& data, const std::string& hintRetVar) {
EXPAND_CONTEXT
UNUSED(function);
UNUSED(scope);
Type* typPchar = PointerType::getUnqual(Type::getInt8Ty(llvm::getGlobalContext()));
//ArrayType* typStr = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::I8, size+1))));
/*
std::vector<Constant *> chars;
chars.reserve(size+1);
for (size_t i=0; i< size; ++i){
chars[i] = ConstantInt::get(typI8, (unsigned char) data[i]);
}
chars[size] = ConstantInt::get(typI8, 0);
*/
Value* rawData = ConstantDataArray::getString(llvm::getGlobalContext(), data);
Value* rawPtrData = llvm->builder.CreateAlloca(rawData->getType(), ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), 1, false));
llvm->builder.CreateStore(rawData, rawPtrData);
return llvm->builder.CreateCast(llvm::Instruction::BitCast, rawPtrData, typPchar, hintRetVar);
}
diff --git a/cpp/src/compilation/containers.cpp b/cpp/src/compilation/containers.cpp
index f60f5ed..c86d08d 100644
--- a/cpp/src/compilation/containers.cpp
+++ b/cpp/src/compilation/containers.cpp
@@ -1,195 +1,195 @@
#include "compilation/containers.h"
using namespace std;
using namespace llvm;
using namespace xreate;
using namespace xreate::containers;
Iterator*
Iterator::create(xreate::compilation::Context context, const xreate::Symbol& var){
const Implementation& data = Query::queryImplementation(var);
switch(data.impl){
case ON_THE_FLY:
return new IteratorForward<ON_THE_FLY>(context, var, data.extract<ON_THE_FLY>());
case SOLID:
return new IteratorForward<SOLID>(context, var, data.extract<SOLID>());
default: assert(true);
}
assert(false && "Unknown declaration");
return nullptr;
}
llvm::Value*
IteratorForward<ON_THE_FLY>::begin() {
switch(sourceDecl.op) {
case xreate::Operator::LIST:
{
sourceRawType = llvm::Type::getInt32Ty(llvm::getGlobalContext());
return llvm::ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), 0);
};
case xreate::Operator::LIST_RANGE:{
assert(sourceDecl.operands.size()==2);
llvm::Value* result = sourceUnit->process(sourceDecl.operands.at(0));
sourceRawType = result->getType();
return result;
};
default: break;
}
if (linkedlist){
llvm::Value* result = sourceUnit->process(sourceDecl);
sourceRawType = result->getType();
return result;
}
assert(false);
}
llvm::Value*
IteratorForward<ON_THE_FLY>::end(){
switch(sourceDecl.op) {
case xreate::Operator::LIST: {
size_t idLast = sourceDecl.operands.size() - 1;
return ConstantInt::get(sourceRawType, idLast);
}
case xreate::Operator::LIST_RANGE: {
assert(sourceDecl.operands.size() == 2);
llvm::Value* valueEndOfRange = sourceUnit->process(sourceDecl.operands.at(1));
llvm::Value* valueConstOne = llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 1);
return llvm->builder.CreateAdd(valueEndOfRange, valueConstOne);
};
default: break;
}
//return null pointer
if (linkedlist){
return ConstantPointerNull::getNullValue(sourceRawType);
}
assert(false && "Unknown declaration");
return nullptr;
}
llvm::Value*
IteratorForward<ON_THE_FLY>::get(Value* index,const std::string& hintRetVar){
const Expression& currentDecl = CodeScope::getDeclaration(current);
switch (currentDecl.op) {
case xreate::Operator::LIST: {
//TODO re check is it right scope(source) to compile currentDecl. Provide unittests.
llvm::Value* currentValue = sourceUnit->processSymbol(current);
return xreate::compilation::Advanced(context).compileArrayIndex(currentValue, std::vector<Value *>{index});
};
case xreate::Operator::LIST_RANGE: {
return index;
};
case xreate::Operator::MAP: {
assert(currentDecl.getOperands().size()==1);
assert(currentDecl.bindings.size());
assert(currentDecl.blocks.size());
CodeScope* scopeLoop = currentDecl.blocks.front();
std::string varEl = currentDecl.bindings[0];
const Symbol& symbIn = Attachments::get<Symbol>(currentDecl.getOperands()[0]);
auto it = std::unique_ptr<Iterator>(Iterator::create(context, symbIn));
Value* elIn = it->get(index, varEl);
compilation::AbstractCodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop);
unitLoop->bindArg(elIn, std::move(varEl));
return unitLoop->compile();
}
case xreate::Operator::NONE: {
//TODO review iterator determination strategy for case of Expression::BINDING
assert(currentDecl.__state==Expression::IDENT);
const Symbol& symbIn = Attachments::get<Symbol>(currentDecl);
auto it = std::unique_ptr<Iterator>(Iterator::create(context, symbIn));
return it->get(index);
};
default: break;
}
if (linkedlist){
return index;
}
assert(false && "Unknown declaration");
return nullptr;
}
llvm::Value*
IteratorForward<ON_THE_FLY>::advance(Value* index, const std::string& hintRetVar){
switch(sourceDecl.op)
{
case xreate::Operator::LIST:
case xreate::Operator::LIST_RANGE:
return llvm->builder.CreateAdd(index, llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 1), hintRetVar);
default: break;
}
if (linkedlist){
- ExpandedType tySource = llvm->ast->expandType(CodeScope::getDeclaration(source).type);
+ ExpandedType tySource = llvm->ast->getType(CodeScope::getDeclaration(source));
assert(tySource->__operator == TypeOperator::ARRAY && "Linked list implementation has to have ARRAY type");
assert(tySource->__operands.size());
return xreate::compilation::Advanced(context).compileStructIndex(index, ExpandedType(TypeAnnotation(tySource->__operands.at(0))), linkedlist.fieldPointer);
}
assert(false && "Unknown declaration");
return nullptr;
}
//const ImplementationRec<ON_THE_FLY>& implementation
IteratorForward<SOLID>::IteratorForward(const compilation::Context& ctx, const xreate::Symbol& symbolContainer, const ImplementationRec<SOLID>& implementation)
: Iterator(), __length(implementation.size), llvm(ctx.pass->man->llvm)
{
__container = ctx.function->getScopeUnit(symbolContainer.scope)->processSymbol(symbolContainer);
}
llvm::Value*
IteratorForward<SOLID>::begin(){
//0
return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 0);
}
llvm::Value*
IteratorForward<SOLID>::end(){
//length
return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), __length);
}
llvm::Value*
IteratorForward<SOLID>::get(llvm::Value* index,const std::string& hintRetVar){
//GEP[index]]
llvm::Type* tyNum = llvm::Type::getInt32Ty(llvm::getGlobalContext());
llvm::Value* pResult = llvm->builder.CreateGEP(__container, ArrayRef<Value *>(std::vector<Value*>{ConstantInt::get(tyNum, 0), index}));
return llvm->builder.CreateLoad(pResult, hintRetVar);
}
llvm::Value*
IteratorForward<SOLID>::advance(llvm::Value* index, const std::string& hintRetVar){
//index + 1
llvm::Type* tyNum = llvm::Type::getInt32Ty(llvm::getGlobalContext());
return llvm->builder.CreateAdd(index, llvm::ConstantInt::get(tyNum, 1), hintRetVar);
}
diff --git a/cpp/src/compilation/operators.cpp b/cpp/src/compilation/operators.cpp
new file mode 100644
index 0000000..26330b2
--- /dev/null
+++ b/cpp/src/compilation/operators.cpp
@@ -0,0 +1,66 @@
+/*
+ * operators.cpp
+ *
+ * Author: pgess <v.melnychenko@xreate.org>
+ * Created on April 8, 2017, 1:35 PM
+ */
+
+#include "operators.h"
+#include "llvmlayer.h"
+#include "ExternLayer.h"
+#include <vector>
+
+using namespace llvm;
+using namespace std;
+
+namespace xreate { namespace compilation {
+
+llvm::Value*
+PointerArithmetic::add(llvm::Value *left, llvm::Value *right, Context context, const std::string& hintVarDecl){
+ LLVMLayer* llvm = context.pass->man->llvm;
+
+ if (left->getType()->isPointerTy() && right->getType()->isIntegerTy()){
+
+ std::vector<llvm::Value*> indexes{right};
+ //{llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 0)};
+ //indexes.push_back(right);
+
+ return llvm->builder.CreateGEP(left, llvm::ArrayRef<llvm::Value*>(indexes), hintVarDecl);
+ }
+
+ return nullptr;
+}
+
+
+llvm::Value*
+StructUpdate::add(const Expression& left, llvm::Value *leftRaw, const Expression& right, Context context, const std::string& hintVarDecl){\
+ if (!(right.__state == Expression::COMPOUND && right.op == Operator::LIST_NAMED)){
+ return nullptr;
+ }
+
+ PassManager* man = context.pass->man;
+
+ ExpandedType tyOperandLeft = man->root->getType(left);
+
+ const std::vector<string> fieldsFormal = (tyOperandLeft.get().__operator == TypeOperator::CUSTOM)?
+ man->llvm->layerExtern->getStructFields(man->llvm->layerExtern->lookupType(tyOperandLeft.get().__valueCustom))
+ : tyOperandLeft.get().fields;
+
+ std::map<std::string, size_t> indexFields;
+ for(size_t i=0, size = fieldsFormal.size(); i<size; ++i){
+ indexFields.emplace(fieldsFormal[i], i);
+ }
+
+ llvm::Value* result = leftRaw;
+ for (size_t i=0; i<right.operands.size(); ++i){
+ const Expression& value = right.operands.at(i);
+ llvm::Value* valueRaw = context.scope->process(value, right.bindings.at(i));
+ unsigned int fieldId = indexFields.at(right.bindings.at(i));
+
+ result = man->llvm->builder.CreateInsertValue(result, valueRaw, llvm::ArrayRef<unsigned>({fieldId}));
+ }
+
+ return result;
+}
+
+} }
\ No newline at end of file
diff --git a/cpp/src/compilation/pointerarithmetic.h b/cpp/src/compilation/operators.h
similarity index 50%
rename from cpp/src/compilation/pointerarithmetic.h
rename to cpp/src/compilation/operators.h
index 5302d7b..7e6a296 100644
--- a/cpp/src/compilation/pointerarithmetic.h
+++ b/cpp/src/compilation/operators.h
@@ -1,29 +1,33 @@
/*
- * File: pointerarithmetic.h
+ * File: operators.h
* Author: pgess <v.melnychenko@xreate.org>
*
- * Created on March 29, 2017, 11:52 AM
+ * Created on April 8, 2017, 1:33 PM
*/
-#ifndef POINTERARITHMETIC_H
-#define POINTERARITHMETIC_H
+#ifndef OPERATORS_H
+#define OPERATORS_H
#include "pass/compilepass.h"
namespace llvm {
class Value;
}
namespace xreate { namespace compilation {
class PointerArithmetic {
public:
static llvm::Value* add(llvm::Value *left, llvm::Value *right, Context context, const std::string& hintVarDecl);
};
+
+class StructUpdate {
+public:
+ static llvm::Value* add(const Expression& left, llvm::Value *leftRaw, const Expression& right, Context context, const std::string& hintVarDecl);
+};
-} }
-
+} } //namespace xreate
-#endif /* POINTERARITHMETIC_H */
+#endif /* OPERATORS_H */
diff --git a/cpp/src/compilation/pointerarithmetic.cpp b/cpp/src/compilation/pointerarithmetic.cpp
deleted file mode 100644
index 307c174..0000000
--- a/cpp/src/compilation/pointerarithmetic.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * pointerarithmetic.cpp
- *
- * Author: pgess <v.melnychenko@xreate.org>
- * Created on March 29, 2017, 11:52 AM
- */
-#include "pointerarithmetic.h"
-#include "llvmlayer.h"
-#include <vector>
-
-using namespace llvm;
-
-namespace xreate { namespace compilation {
-
-llvm::Value*
-PointerArithmetic::add(llvm::Value *left, llvm::Value *right, Context context, const std::string& hintVarDecl){
- LLVMLayer* llvm = context.pass->man->llvm;
-
- if (left->getType()->isPointerTy() && right->getType()->isIntegerTy()){
-
- std::vector<llvm::Value*> indexes{right};
- //{llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 0)};
- //indexes.push_back(right);
-
- return llvm->builder.CreateGEP(left, llvm::ArrayRef<llvm::Value*>(indexes), hintVarDecl);
- }
-
- return nullptr;
-}
-
-} }
\ No newline at end of file
diff --git a/cpp/src/compilation/targets.h b/cpp/src/compilation/targets.h
index 2ec48eb..6b891c7 100644
--- a/cpp/src/compilation/targets.h
+++ b/cpp/src/compilation/targets.h
@@ -1,191 +1,191 @@
/*
* File: targetabstract.h
* Author: pgess
*
* Created on July 2, 2016, 1:25 PM
*/
#ifndef TARGETABSTRACT_H
#define TARGETABSTRACT_H
#include "ast.h"
#include <boost/optional.hpp>
#include <map>
namespace xreate{ namespace compilation {
template <typename ConcreteTarget>
struct TargetInfo{
//typedef Result
//typedef Function
//typedef Scope
};
template<typename ConcreteTarget>
class Function;
template<typename ConcreteTarget>
class Target;
template<typename ConcreteTarget>
class Scope{
typedef typename TargetInfo<ConcreteTarget>::Scope Self;
public:
CodeScope* scope;
typename TargetInfo<ConcreteTarget>::Result
processSymbol(const Symbol& s){
CodeScope* scope = s.scope;
Self* self = function->getScope(scope);
if (self->__bindings.count(s.identifier)) {
return self->__bindings[s.identifier];
}
const Expression& declaration = CodeScope::getDeclaration(s);
if (!declaration.isDefined()){
assert(false); //for bindings there should be result already
}
return self->__bindings[s.identifier] = self->process(declaration);
}
typename TargetInfo<ConcreteTarget>::Result
processScope() {
if (raw) return *raw;
raw = process(scope->getBody());
return *raw;
}
// typename TargetInfo<ConcreteTarget>::Result
// processFunction(typename TargetInfo<ConcreteTarget>::Function* fnRemote, const std::vector<typename TargetInfo<ConcreteTarget>::Result>& args){
// Scope<ConcreteTarget> scopeRemote = fnRemote->getScope(fnRemote->__function->__entry);
//
// if (scopeRemote->raw){
// return scopeRemote->raw;
// }
//
// return fnRemote->process(args);
// }
virtual typename TargetInfo<ConcreteTarget>::Result
process(const Expression& expression)=0;
Scope(CodeScope* codeScope, Function<ConcreteTarget>* f)
: scope(codeScope), function(f) {}
virtual ~Scope(){}
void
overrideBinding(typename TargetInfo<ConcreteTarget>::Result arg, const std::string& name){
assert(scope->__identifiers.count(name));
ScopedSymbol id{scope->__identifiers.at(name), VERSION_NONE};
__bindings[id] = arg;
//reset the result if any:
raw.reset();
}
void registerChildScope(std::shared_ptr<Self> scope){
__childScopes.push_back(scope);
}
void reset(){
__bindings.clear();
__childScopes.clear();
- raw == nullptr;
+ raw.reset();
}
protected:
Function<ConcreteTarget>* function=0;
std::map<ScopedSymbol, typename TargetInfo<ConcreteTarget>::Result> __bindings;
std::list<std::shared_ptr<Self>> __childScopes;
typename boost::optional<typename TargetInfo<ConcreteTarget>::Result> raw;
};
template<typename ConcreteTarget>
class Function{
typedef typename TargetInfo<ConcreteTarget>::Result Result;
typedef typename TargetInfo<ConcreteTarget>::Scope ConcreteScope;
public:
Function(const ManagedFnPtr& function, Target<ConcreteTarget>* target)
: man(target), __function(function) {}
virtual ~Function(){};
ConcreteScope*
getScope(CodeScope* scope){
if (__scopes.count(scope)) {
auto result = __scopes.at(scope).lock();
if (result){
return result.get();
}
}
std::shared_ptr<ConcreteScope> unit(new ConcreteScope(scope, this));
if (scope->__parent != nullptr){
getScope(scope->__parent)->registerChildScope(unit);
} else {
assert(!__entryScope);
__entryScope = unit;
}
if (!__scopes.emplace(scope, unit).second){
__scopes[scope] = unit;
}
return unit.get();
}
virtual Result
process(const std::vector<Result>& args)=0;
Target<ConcreteTarget>* man=0;
ManagedFnPtr __function;
protected:
std::map<CodeScope*, std::weak_ptr<ConcreteScope>> __scopes;
std::shared_ptr<ConcreteScope> __entryScope;
};
template<typename ConcreteTarget>
class Target {
typedef typename TargetInfo<ConcreteTarget>::Function ConcreteFunction;
public:
Target(AST* root): ast(root){}
ConcreteFunction*
getFunction(const ManagedFnPtr& function){
unsigned int id = function.id();
if (!__functions.count(id)){
ConcreteFunction* unit = new ConcreteFunction(function, this);
__functions.emplace(id, unit);
return unit;
}
return __functions.at(id);
}
AST* ast;
virtual ~Target(){
for (const auto& entry: __functions){
delete entry.second;
}
}
protected:
std::map<unsigned int, ConcreteFunction*> __functions;
};
}}
#endif /* TARGETABSTRACT_H */
diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp
index e9e7d12..0859093 100644
--- a/cpp/src/pass/compilepass.cpp
+++ b/cpp/src/pass/compilepass.cpp
@@ -1,799 +1,807 @@
#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/pointerarithmetic.h"
+#include "compilation/operators.h"
#include <boost/optional.hpp>
#include <memory>
#include <iostream>
using namespace std;
using namespace xreate;
using namespace xreate::compilation;
using namespace llvm;
//TODO use Scope<TargetLlvm>
//SECTIONTAG types/convert implementation
//TODO type conversion:
//a) automatically expand types int -> bigger int; int -> floating
//b) detect exact type of `num` based on max used numeral / function type
//c) warning if need to truncate (allow/dissalow based on annotations)
namespace xreate {
llvm::Value*
doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, llvm::IRBuilder<>& builder){
if (tyTarget->isIntegerTy() && source->getType()->isIntegerTy())
{
llvm::IntegerType* tyTargetInt = llvm::dyn_cast<IntegerType>(tyTarget);
llvm::IntegerType* tySourceInt = llvm::dyn_cast<IntegerType>(source->getType());
if (tyTargetInt->getBitWidth() < tySourceInt->getBitWidth()){
return builder.CreateCast(llvm::Instruction::Trunc, source, tyTarget);
}
if (tyTargetInt->getBitWidth() > tySourceInt->getBitWidth()){
return builder.CreateCast(llvm::Instruction::SExt, source, tyTarget);
}
}
if (source->getType()->isIntegerTy() && tyTarget->isFloatingPointTy()){
return builder.CreateCast(llvm::Instruction::SIToFP, source, tyTarget);
}
return source;
}
std::string
BasicFunctionDecorator::prepareName(){
AST* ast = FunctionUnit::pass->man->root;
string name = ast->getFunctionVariants(FunctionUnit::function->__name).size() > 1?
FunctionUnit::function->__name + std::to_string(FunctionUnit::function.id()) :
FunctionUnit::function->__name;
return name;
}
std::vector<llvm::Type*>
BasicFunctionDecorator::prepareArguments(){
LLVMLayer* llvm = FunctionUnit::pass->man->llvm;
AST* ast = FunctionUnit::pass->man->root;
CodeScope* entry = FunctionUnit::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), VERSION_NONE};
return llvm->toLLVMType(ast->expandType(entry->__declarations.at(argid).type));
});
return signature;
}
llvm::Type*
BasicFunctionDecorator::prepareResult(){
LLVMLayer* llvm = FunctionUnit::pass->man->llvm;
AST* ast = FunctionUnit::pass->man->root;
CodeScope* entry = FunctionUnit::function->__entry;
return llvm->toLLVMType(ast->expandType(entry->__declarations.at(ScopedSymbol::RetSymbol).type));
}
llvm::Function::arg_iterator
BasicFunctionDecorator::prepareBindings(){
CodeScope* entry = FunctionUnit::function->__entry;
AbstractCodeScopeUnit* entryCompilation = FunctionUnit::getScopeUnit(entry);
llvm::Function::arg_iterator fargsI = FunctionUnit::raw->arg_begin();
for (std::string &arg : entry->__bindings) {
ScopedSymbol argid{entry->__identifiers[arg], VERSION_NONE};
entryCompilation->bindArg(&*fargsI, argid);
fargsI->setName(arg);
++fargsI;
}
return fargsI;
}
//SECTIONTAG late-context FunctionDecorator
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:
LateContextCompiler2 contextCompiler;
};
//SECTIONTAG adhoc FunctionDecorator
template<class Parent>
class AdhocFunctionDecorator: public Parent{
public:
AdhocFunctionDecorator(ManagedFnPtr f, CompilePass* p)
: Parent(f, p) {}
protected:
llvm::Type* prepareResult(){
PassManager* man = Parent::pass->man;
CodeScope* entry = Parent::function->__entry;
LLVMLayer* llvm = Parent::pass->man->llvm;
AST* ast = Parent::pass->man->root;
AdhocPass* adhocpass = reinterpret_cast<AdhocPass*>(man->getPassById(PassId::AdhocPass));
if (! Parent::function->isPrefunction){
return Parent::prepareResult();
}
adhocImplementation = adhocpass->findAssotiatedScheme(entry);
return llvm->toLLVMType(ast->expandType(adhocImplementation->getResultType()));
}
public:
AdhocScheme* adhocImplementation=nullptr;
};
//DEBT compiler rigidly depends on exact definition of DefaultFunctionUnit
typedef LateContextFunctionDecorator<
AdhocFunctionDecorator<
BasicFunctionDecorator>> DefaultFunctionUnit;
AbstractCodeScopeUnit::AbstractCodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass)
: pass(compilePass), function(f), scope(codeScope)
{}
llvm::Value*
CallStatementRaw::operator() (std::vector<llvm::Value *>&& args, const std::string& hintDecl) {
llvm::Function* calleeInfo = dyn_cast<llvm::Function>(__callee);
if (calleeInfo){
auto argsFormal = calleeInfo->args();
int pos=0;
//SECTIONTAG types/convert function ret value
for (auto argFormal = argsFormal.begin(); argFormal!=argsFormal.end(); ++argFormal, ++pos){
args[pos] = doAutomaticTypeConversion(args[pos], argFormal->getType(), llvm->builder);
}
}
return llvm->builder.CreateCall(__calleeTy, __callee, args, hintDecl);
}
//DESABLEDFEATURE implement inlining
class CallStatementInline: public CallStatement{
public:
CallStatementInline(FunctionUnit* caller, FunctionUnit* 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:
FunctionUnit* __caller;
FunctionUnit* __callee;
LLVMLayer* llvm;
bool isInline(){
// Symbol ret = Symbol{0, function->__entry};
// bool flagOnTheFly = SymbolAttachments::get<IsImplementationOnTheFly>(ret, false);
//TODO consider inlining
return false;
}
};
}
BasicCodeScopeUnit::BasicCodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass)
: AbstractCodeScopeUnit(codeScope, f, compilePass)
{}
llvm::Value*
BasicCodeScopeUnit::processSymbol(const Symbol& s, std::string hintRetVar){
Expression declaration = CodeScope::getDeclaration(s);
CodeScope* scope = s.scope;
AbstractCodeScopeUnit* self = AbstractCodeScopeUnit::function->getScopeUnit(scope);
return self->process(declaration, hintRetVar);
}
//SECTIONTAG late-context find callee function
//TOTEST static late context decisions
//TOTEST dynamic late context decisions
CallStatement*
BasicCodeScopeUnit::findFunction(const std::string& calleeName){
LLVMLayer* llvm = pass->man->llvm;
ClaspLayer* clasp = pass->man->clasp;
DefaultFunctionUnit* function = dynamic_cast<DefaultFunctionUnit*>(this->function);
ContextQuery* queryContext = pass->queryContext;
const std::list<ManagedFnPtr>& specializations = pass->man->root->getFunctionVariants(calleeName);
//if no specializations registered - check external function
if (specializations.size()==0){
llvm::Function* external = llvm->layerExtern->lookupFunction(calleeName);
llvm::outs() << "Debug/External function: " << calleeName;
external->getType()->print(llvm::outs(), true);
llvm::outs() << "\n";
return new CallStatementRaw(external, llvm);
}
//no decisions required
if (specializations.size()==1){
if (!specializations.front()->guardContext.isValid()) {
return new CallStatementRaw( pass->getFunctionUnit(specializations.front())->compile(), llvm);
}
}
//TODO move dictSpecialization over to a separate function in order to perform cache, etc.
//prepare specializations dictionary
std::map<Expression, ManagedFnPtr> dictSpecializations;
boost::optional<ManagedFnPtr> variantDefault;
boost::optional<ManagedFnPtr> variant;
for(const ManagedFnPtr& f: specializations){
const Expression& guard = f->guardContext;
//default case:
if (!guard.isValid()){
variantDefault = f;
continue;
}
assert(dictSpecializations.emplace(guard, f).second && "Found several identical specializations");
}
//check static context
ScopePacked scopeCaller = clasp->pack(this->scope);
const string atomSpecialization = "specialization";
const Expression topicSpecialization(Operator::CALL, {(Atom<Identifier_t>(string(atomSpecialization))), (Atom<Identifier_t>(string(calleeName))), (Atom<Number_t>(scopeCaller))});
const 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) {
FunctionUnit* calleeUnit = pass->getFunctionUnit(variant? *variant: *variantDefault);
//inlining possible based on static decision only
// if (calleeUnit->isInline()) {
// return new CallStatementInline(function, calleeUnit);
// }
return new CallStatementRaw(calleeUnit->compile(), llvm);
}
//require default variant if no static decision made
assert(variantDefault);
llvm::Function* functionVariantDefault = this->pass->getFunctionUnit(*variantDefault)->compile();
llvm::Value* resultFn = function->contextCompiler.findFunction(calleeName, functionVariantDefault, scopeCaller);
llvm::PointerType *resultPTy = cast<llvm::PointerType>(resultFn->getType());
llvm::FunctionType *resultFTy = cast<llvm::FunctionType>(resultPTy->getElementType());
return new CallStatementRaw(resultFn, resultFTy, llvm);
}
//DISABLEDFEATURE transformations
// if (pass->transformations->isAcceptable(expr)){
// return pass->transformations->transform(expr, result, ctx);
// }
llvm::Value*
BasicCodeScopeUnit::process(const Expression& expr, const std::string& hintVarDecl){
#define DEFAULT(x) (hintVarDecl.empty()? x: hintVarDecl)
llvm::Value *left; llvm::Value *right;
LLVMLayer& l = *pass->man->llvm;
xreate::compilation::Advanced instructions = xreate::compilation::Advanced({this, function, pass});
switch (expr.op) {
- case Operator::ADD: case Operator::SUB: case Operator::MUL:
+ case Operator::SUB: case Operator::MUL:
case Operator::DIV: case Operator::EQU: case Operator::LSS:
case Operator::GTR: case Operator::NE: case Operator::LSE:
case Operator::GTE:
assert(expr.__state == Expression::COMPOUND);
assert(expr.operands.size() == 2);
left = process(expr.operands[0]);
right = process(expr.operands[1]);
//SECTIONTAG types/convert binary operation
right = doAutomaticTypeConversion(right, left->getType(), l.builder);
break;
default:;
}
switch (expr.op) {
case Operator::ADD:{
- llvm::Value* resultAdd = PointerArithmetic::add(left, right, {this, function, pass}, DEFAULT("tmp_add"));
- if (resultAdd) {return resultAdd;}
+ 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::add(left, right, context,DEFAULT("tmp_add"));
+ if (resultAddPA) {return resultAddPA;}
return l.builder.CreateAdd(left, right, DEFAULT("tmp_add"));
break;
}
case Operator::SUB:
return l.builder.CreateSub(left, right, DEFAULT("tmp_sub"));
break;
case Operator::MUL:
return l.builder.CreateMul(left, right, DEFAULT("tmp_mul"));
break;
case Operator::DIV:
return l.builder.CreateSDiv(left, right, DEFAULT("tmp_div"));
break;
case Operator::EQU:
if (left->getType()->isIntegerTy()) return l.builder.CreateICmpEQ(left, right, DEFAULT("tmp_equ"));
if (left->getType()->isFloatingPointTy()) return l.builder.CreateFCmpOEQ(left, right, DEFAULT("tmp_equ"));
break;
case Operator::NE:
return l.builder.CreateICmpNE(left, right, DEFAULT("tmp_ne"));
break;
case Operator::LSS:
return l.builder.CreateICmpSLT(left, right, DEFAULT("tmp_lss"));
break;
case Operator::LSE:
return l.builder.CreateICmpSLE(left, right, DEFAULT("tmp_lse"));
break;
case Operator::GTR:
return l.builder.CreateICmpSGT(left, right, DEFAULT("tmp_gtr"));
break;
case Operator::GTE:
return l.builder.CreateICmpSGE(left, right, DEFAULT("tmp_gte"));
break;
case Operator::NEG:
left = process(expr.operands[0]);
return l.builder.CreateNeg(left, DEFAULT("tmp_neg"));
break;
case Operator::CALL: {
assert(expr.__state == Expression::COMPOUND);
std::string nameCallee = expr.getValueString();
shared_ptr<CallStatement> callee(findFunction(nameCallee));
//prepare arguments
std::vector<llvm::Value *> args;
args.reserve(expr.operands.size());
std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()),
[this](const Expression &operand) {
return process(operand);
}
);
ScopePacked outerScopeId = pass->man->clasp->pack(this->scope);
//TASK a) refactor CALL/ADHOC/find function
//SECTIONTAG late-context propagation arg
size_t calleeDemandSize = pass->queryContext->getFunctionDemand(nameCallee).size();
if (calleeDemandSize){
DefaultFunctionUnit* function = dynamic_cast<DefaultFunctionUnit*>(this->function);
llvm::Value* argLateContext = function->contextCompiler.compileContextArgument(nameCallee, outerScopeId);
args.push_back(argLateContext);
}
return (*callee)(move(args), DEFAULT("res_"+nameCallee));
}
case Operator::IF:
{
return instructions.compileIf(expr, DEFAULT("tmp_if"));
}
case Operator::SWITCH:
{
return instructions.compileSwitch(expr, DEFAULT("tmp_switch"));
}
case Operator::LOOP_CONTEXT:
{
assert(false);
return nullptr;
//return instructions.compileLoopContext(expr, DEFAULT("tmp_loop"));
}
case Operator::LOGIC_AND: {
assert(expr.operands.size() == 1);
return process (expr.operands[0]);
}
case Operator::LIST:
{
return instructions.compileListAsSolidArray(expr, DEFAULT("tmp_list"));
};
case Operator::LIST_RANGE:
{
assert(false); //no compilation phase for a range list
// return InstructionList(this).compileConstantArray(expr, l, hintRetVar);
};
case Operator::LIST_NAMED:
{
typedef Expanded<TypeAnnotation> ExpandedType;
- ExpandedType tyRaw = l.ast->expandType(expr.type);
+ ExpandedType tyStructLiteral = l.ast->getType(expr);
- const std::vector<string> fields = (tyRaw.get().__operator == TypeOperator::CUSTOM)?
- l.layerExtern->getStructFields(l.layerExtern->lookupType(tyRaw.get().__valueCustom))
- : tyRaw.get().fields;
+ 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 = fields.size(); i<size; ++i){
- indexFields.emplace(fields[i], i);
+ for(size_t i=0, size = fieldsFormal.size(); i<size; ++i){
+ indexFields.emplace(fieldsFormal[i], i);
}
- llvm::StructType* tyRecord = llvm::cast<llvm::StructType>(l.toLLVMType(tyRaw));
- llvm::Value* record = llvm::UndefValue::get(tyRecord);
+ llvm::StructType* tyLiteralRaw = llvm::cast<llvm::StructType>(l.toLLVMType(tyStructLiteral));
+ llvm::Value* record = llvm::UndefValue::get(tyLiteralRaw);
for (size_t i=0; i<expr.operands.size(); ++i){
const Expression& operand = expr.operands.at(i);
unsigned int fieldId = indexFields.at(expr.bindings.at(i));
llvm::Value* result = 0;
-//TODO Null ad hoc Llvm implementation
+//TODO Null ad hoc llvm implementation (related code: operators/StructUpdate/add)
// if (operand.isNone()){
// llvm::Type* tyNullField = tyRecord->getElementType(fieldId);
// result = llvm::UndefValue::get(tyNullField);
//
// } else {
result = process(operand);
// }
assert (result);
record = l.builder.CreateInsertValue(record, result, llvm::ArrayRef<unsigned>({fieldId}));
}
return record;
};
case Operator::MAP:
{
assert(expr.blocks.size());
return instructions.compileMapSolidOutput(expr, DEFAULT("map"));
};
case Operator::FOLD:
{
return instructions.compileFold(expr, DEFAULT("fold"));
};
case Operator::FOLD_INF:
{
return instructions.compileFoldInf(expr, DEFAULT("fold"));
};
case Operator::INDEX:
{
//TODO allow multiindex
assert(expr.operands.size()==2);
assert(expr.operands[0].__state == Expression::IDENT);
const std::string& hintIdent= expr.operands[0].getValueString();
Symbol s = Attachments::get<Symbol>(expr.operands[0]);
- const ExpandedType& t2 = pass->man->root->expandType(CodeScope::getDeclaration(s).type);
+ const ExpandedType& t2 = pass->man->root->getType(expr.operands[0]);
llvm::Value* aggr = processSymbol(s, hintIdent);
switch (t2.get().__operator)
{
case TypeOperator::STRUCT: case TypeOperator::CUSTOM:
{
const Expression& idx = expr.operands.at(1);
assert(idx.__state == Expression::STRING);
std::string idxField = idx.getValueString();
return instructions.compileStructIndex(aggr, t2, idxField);
};
case TypeOperator::ARRAY: {
std::vector<llvm::Value*> indexes;
std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()),
[this] (const Expression& op){
return process(op);
}
);
return instructions.compileArrayIndex(aggr, indexes, DEFAULT(string("el_") + hintIdent));
};
default:
assert(false);
}
};
//SECTIONTAG adhoc actual compilation
//TODO a) make sure that it's correct: function->adhocImplementation built for Entry scope and used in another scope
case Operator::ADHOC: {
DefaultFunctionUnit* function = dynamic_cast<DefaultFunctionUnit*>(this->function);
assert(function->adhocImplementation && "Adhoc implementation not found");
const Expression& comm = AdhocExpression(expr).getCommand();
CodeScope* scope = function->adhocImplementation->getCommandImplementation(comm);
AbstractCodeScopeUnit* unitScope = function->getScopeUnit(scope);
//SECTIONTAG types/convert ADHOC ret convertation
llvm::Type* resultTy = l.toLLVMType( pass->man->root->expandType(function->adhocImplementation->getResultType()));
return 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::NONE:
assert(expr.__state != Expression::COMPOUND);
switch (expr.__state) {
case Expression::IDENT: {
Symbol s = Attachments::get<Symbol>(expr);
return processSymbol(s, expr.getValueString());
}
case Expression::NUMBER: {
llvm::Type* typConst;
if (expr.type.isValid()){
- typConst = l.toLLVMType(pass->man->root->expandType(expr.type));
+ typConst = l.toLLVMType(pass->man->root->getType(expr));
} else {
typConst = llvm::Type::getInt32Ty(llvm::getGlobalContext());
}
int literal = expr.getValueDouble();
return llvm::ConstantInt::get(typConst, literal);
}
case Expression::STRING: {
return instructions.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str"));
};
case Expression::VARIANT: {
- const ExpandedType& typVariant = pass->man->root->expandType(expr.type);
+ const ExpandedType& typVariant = pass->man->root->getType(expr);
llvm::Type* typRaw = l.toLLVMType(typVariant);
int value = expr.getValueDouble();
return llvm::ConstantInt::get(typRaw, value);
}
default: {
break;
}
};
break;
default: break;
}
assert(false);
return 0;
}
llvm::Value*
BasicCodeScopeUnit::compile(const std::string& hintBlockDecl){
if (!hintBlockDecl.empty()) {
llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm::getGlobalContext(), hintBlockDecl, function->raw);
pass->man->llvm->builder.SetInsertPoint(block);
}
Symbol symbScope = Symbol{ScopedSymbol::RetSymbol, scope};
return processSymbol(symbScope);
}
AbstractCodeScopeUnit::~AbstractCodeScopeUnit()
{}
FunctionUnit::~FunctionUnit()
{}
llvm::Function*
FunctionUnit::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(doAutomaticTypeConversion(result, expectedResultType, llvm->builder));
if (blockCurrent){
builder.SetInsertPoint(blockCurrent);
}
llvm->moveToGarbage(ft);
return raw;
}
AbstractCodeScopeUnit*
FunctionUnit::getScopeUnit(CodeScope* scope){
if (__scopes.count(scope)) {
auto result = __scopes.at(scope).lock();
if (result){
return result.get();
}
}
std::shared_ptr<AbstractCodeScopeUnit> unit(new DefaultScopeUnit(scope, this, pass));
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();
}
AbstractCodeScopeUnit*
FunctionUnit::getScopeUnit(ManagedScpPtr scope){
return getScopeUnit(&*scope);
}
AbstractCodeScopeUnit*
FunctionUnit::getEntry(){
return getScopeUnit(function->getEntryScope());
}
FunctionUnit*
CompilePass::getFunctionUnit(const ManagedFnPtr& function){
unsigned int id = function.id();
if (!functions.count(id)){
FunctionUnit* unit = new DefaultFunctionUnit(function, this);
functions.emplace(id, unit);
return unit;
}
return functions.at(id);
}
void
CompilePass::run(){
managerTransformations = new TransformationsManager();
targetInterpretation = new TargetInterpretation(this->man->root, this);
queryContext = reinterpret_cast<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));
FunctionUnit* unitMain = getFunctionUnit(man->root->findFunction(nameMain));
entry = unitMain->compile();
}
llvm::Function*
CompilePass::getEntryFunction(){
assert(entry);
return entry;
}
void
CompilePass::prepareQueries(ClaspLayer* clasp){
clasp->registerQuery(new containers::Query(), QueryId::ContainersQuery);
clasp->registerQuery(new ContextQuery(), QueryId::ContextQuery);
}
diff --git a/cpp/tests/compilation.cpp b/cpp/tests/compilation.cpp
index 95b96b6..5188fe6 100644
--- a/cpp/tests/compilation.cpp
+++ b/cpp/tests/compilation.cpp
@@ -1,37 +1,60 @@
#include "passmanager.h"
#include "gtest/gtest.h"
using namespace xreate;
//DEBT implement no pkgconfig ways to link libs
//TOTEST FunctionUnit::compileInline
TEST(Compilation, DISABLED_functionInline1){
}
TEST(Compilation, functionEntry1){
std::unique_ptr<PassManager> program(PassManager::prepareForCode(
"func1 = function(a:: int):: int {a+8} \
func2 = function::int; entry {12 + func1(4)} \
"));
void* entryPtr = program->run();
int (*entry)() = (int (*)())(intptr_t)entryPtr;
int answer = entry();
ASSERT_EQ(24, answer);
}
TEST(Compilation, full_IFStatementWithVariantType){
PassManager* man = PassManager::prepareForCode(
"Color = type variant (RED, BLUE, GREEN).\n"
"\n"
" main = function(x::int):: bool; entry {\n"
" color = if (x == 0 )::Color {RED} else {BLUE}.\n"
" if (color == BLUE)::bool {true} else {false}\n"
" }"
);
bool (*main)(int) = (bool (*)(int)) man->run();
ASSERT_FALSE(main(0));
ASSERT_TRUE(main(1));
}
+TEST(Compilation, full_StructUpdate){
+PassManager* man = PassManager::prepareForCode(
+ R"Code(
+
+ Rec = type alias {
+ a :: int,
+ b:: int
+ }.
+
+ test= function:: int; entry {
+ a = {a = 18, b = 20}:: Rec.
+
+ b = a + {a = 11}:: Rec.
+ b["a"]
+ }
+ )Code");
+
+ int (*main)() = (int (*)()) man->run();
+ int result = main();
+
+ ASSERT_EQ(11, result);
+}
+
diff --git a/cpp/tests/externc.cpp b/cpp/tests/externc.cpp
index 4aa5d7e..68463e6 100644
--- a/cpp/tests/externc.cpp
+++ b/cpp/tests/externc.cpp
@@ -1,106 +1,105 @@
#include "gtest/gtest.h"
#include "passmanager.h"
#include "Scanner.h"
#include "Parser.h"
#include <iostream>
#include <llvm/Support/DynamicLibrary.h>
using namespace std;
TEST(InterfaceExternC, testAST) {
std::string code = " \
interface(extern-c){ \
xml2 = library:: pkgconfig(\"libxml-2.0\"). \
\
include { \
xml2 = [\"libxml/tree.h\"] \
}. \
} \
";
Scanner scanner(reinterpret_cast<const unsigned char*> (code.c_str()), code.size());
Parser parser(&scanner);
parser.Parse();
ASSERT_EQ(1, parser.root.__externdata.size());
for (const ExternEntry& lib : parser.root.__externdata) {
ASSERT_EQ("libxml-2.0", lib.package);
ASSERT_EQ(1, lib.headers.size());
ASSERT_EQ("libxml/tree.h", lib.headers.at(0));
}
}
TEST(InterfaceExternC, testfetchPackageHeaders) {
ExternEntry entry{"libxml-2.0",
{}};
vector<string> args = ExternLayer::fetchPackageFlags(entry);
ASSERT_EQ(1, args.size());
ASSERT_EQ("-I/usr/include/libxml2", args.at(0));
}
TEST(InterfaceExternC, testfetchPackageLibs) {
ExternEntry entry{"libxml-2.0",
{}};
vector<string> args = ExternLayer::fetchPackageLibs(entry);
ASSERT_EQ(1, args.size());
ASSERT_EQ("xml2", args.at(0));
}
TEST(InterfaceExternC, testLoadLib) {
std::string msgErr;
if (!llvm::sys::DynamicLibrary::LoadLibraryPermanently("-lpcre -lxml2", &msgErr)) {
cout << msgErr;
ASSERT_EQ("", msgErr);
}
ASSERT_TRUE(true);
}
TEST(InterfaceExternC, testBSD1) {
std::string code = " \n\
interface(extern-c){ \n\
libbsd = library:: pkgconfig(\"libbsd\"). \n\
\n\
include { \n\
libbsd = [\"bsd/stdlib.h\"] \n\
}. \n\
} \n"
"main= function:: int; entry{arc4random_uniform(24) }";
std::unique_ptr<PassManager> program(PassManager::prepareForCode(move(code)));
void* entryPtr = program->run();
int (*entry)() = (int (*)())(intptr_t) entryPtr;
int answer = 24;
answer = entry();
cout << answer;
ASSERT_LT(answer, 24);
}
TEST(InterfaceExternC, testStructFields1) {
FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate", "r");
assert(input != nullptr);
Scanner scanner(input);
Parser parser(&scanner);
parser.Parse();
AST& ast = parser.root;
CodeScope* body = ast.findFunction("test")->getEntryScope();
- const TypeAnnotation& tTree = body->getDeclaration(body->getSymbol("tree")).type;
- const ExpandedType& t2Tree = ast.expandType(tTree);
+ const ExpandedType& t2Tree = ast.getType(body->getDeclaration(body->getSymbol("tree")));
LLVMLayer llvm(&ast);
TypeUtils utils(&llvm);
std::vector<std::string>fields = utils.getStructFields(t2Tree);
auto field = std::find(fields.begin(), fields.end(), "children");
ASSERT_TRUE(field != fields.end());
}
diff --git a/cpp/tests/types.cpp b/cpp/tests/types.cpp
index 5ff99b6..d121a48 100644
--- a/cpp/tests/types.cpp
+++ b/cpp/tests/types.cpp
@@ -1,163 +1,161 @@
/*
* types.cpp
*
* Created on: Jun 4, 2015
* Author: pgess
*/
#include "gtest/gtest.h"
#include "passmanager.h"
#include "llvmlayer.h"
#include "Parser.h"
using namespace std;
using namespace xreate;
TEST(Types, DependantTypes1) {
string&& code = "XmlNode = type alias {\n"
" tag:: string,\n"
" /* attrs:: [string],*/\n"
" content:: string\n"
"}.\n";
std::unique_ptr<PassManager> program(PassManager::prepareForCode(move(code)));
ExpandedType typeXmlNode = program->root->findType("XmlNode");
ASSERT_EQ(TypeOperator::STRUCT, typeXmlNode->__operator);
ASSERT_EQ(2, typeXmlNode->__operands.size());
ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(0).__value);
ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(1).__value);
}
TEST(Types, DependantTypes2) {
string&& code = "XmlNode = type alias {\n"
" tag:: string,\n"
" /* attrs:: [string],*/\n"
" content:: string\n"
"}.\n"
""
"Template = type Template(Leaf) [Leaf, [Leaf[content]]]."
"Concrete = type alias Template(XmlNode).";
std::unique_ptr<PassManager> program(PassManager::prepareForCode(move(code)));
ExpandedType typeConcrete = program->root->findType("Concrete");
ASSERT_EQ(TypeOperator::TUPLE, typeConcrete->__operator);
ASSERT_EQ(2, typeConcrete->__operands.size());
ASSERT_EQ(TypeOperator::STRUCT, typeConcrete->__operands.at(0).__operator);
ASSERT_EQ(TypeOperator::ARRAY, typeConcrete->__operands.at(1).__operator);
ASSERT_EQ(TypePrimitive::String, typeConcrete->__operands.at(1).__operands.at(0).__value);
}
TEST(Types, TreeType1) {
string&& code = "XmlNode = type alias {\n"
" tag:: string,\n"
" /* attrs:: [string],*/\n"
" content:: string\n"
"}.\n"
""
"Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]."
"Concrete = type alias Tree(XmlNode).";
std::unique_ptr<PassManager> program(PassManager::prepareForCode(move(code)));
ExpandedType typeConcrete = program->root->findType("Concrete");
ASSERT_EQ(TypeOperator::TUPLE, typeConcrete->__operator);
ASSERT_EQ(2, typeConcrete->__operands.size());
ASSERT_EQ(TypeOperator::STRUCT, typeConcrete->__operands.at(0).__operator);
ASSERT_EQ(TypeOperator::ARRAY, typeConcrete->__operands.at(1).__operator);
auto typeLink = typeConcrete->__operands.at(1).__operands.at(0);
ASSERT_EQ(TypeOperator::LINK, typeLink.__operator);
ASSERT_EQ(typeConcrete->conjuctionId,typeLink.conjuctionId);
}
TEST(Types, TreeType1LLvm){
string&& code = "XmlNode = type alias {\n"
" tag:: string,\n"
" /* attrs:: [string],*/\n"
" content:: string\n"
"}.\n"
""
"Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]."
"Concrete = type alias Tree(XmlNode).";
std::unique_ptr<PassManager> program(PassManager::prepareForCode(move(code)));
ExpandedType typeConcrete = program->root->findType("Concrete");
llvm::Type* raw = program->llvm->toLLVMType(typeConcrete);
}
TEST(Types, ArrayOfExternal1){
FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r");
assert(input != nullptr);
Scanner scanner(input);
Parser parser(&scanner);
parser.Parse();
AST& ast = parser.root;
CodeScope* body = ast.findFunction("test")->getEntryScope();
- const TypeAnnotation& t = body->getDeclaration(body->getSymbol("childrenRaw")).type;
- const ExpandedType& t2 = ast.expandType(t);
+ const ExpandedType& t2 = ast.getType(body->getDeclaration(body->getSymbol("childrenRaw")));
EXPECT_EQ(t2->__operator, TypeOperator::ARRAY);
}
TEST(Types, ExternType1){
FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r");
assert(input != nullptr);
Scanner scanner(input);
Parser parser(&scanner);
parser.Parse();
AST& ast = parser.root;
CodeScope* body = ast.findFunction("test")->getEntryScope();
- const TypeAnnotation& t = body->getDeclaration(body->getSymbol("tree")).type;
- const ExpandedType& t2 = ast.expandType(t);
+ const ExpandedType& t2 = ast.getType(body->getDeclaration(body->getSymbol("tree")));
EXPECT_EQ(t2->__operator, TypeOperator::CUSTOM);
}
TEST(Types, ast_VariantType1){
string&& code =
" colors = type variant (RED, BLUE, GREEN).\n"
" test = function:: colors; entry {GREEN}";
std::unique_ptr<PassManager> program(PassManager::prepareForCode(move(code)));
ExpandedType typ = program->root->findType("colors");
EXPECT_EQ(TypeOperator::VARIANT, typ->__operator);
Expression eRed = program->root->findFunction("test")->getEntryScope()->getBody();
EXPECT_EQ(Expression::VARIANT, eRed.__state);
- const ExpandedType& typ2 = program->root->expandType(eRed.type);
+ const ExpandedType& typ2 = program->root->getType(eRed);
EXPECT_EQ(TypeOperator::VARIANT, typ2->__operator);
program->run();
}
TEST(Types, full_VariantType_Switch1){
string&& code =
" colors = type variant (RED, BLUE, GREEN). \n"
" test = function:: colors {GREEN} \n"
"main = function:: int; entry { \n"
" switch(test()):: int \n"
" case (GREEN) {0} \n"
" case default {1} \n"
"}";
PassManager* man = PassManager::prepareForCode(move(code));
int (*main)() = (int (*)()) man->run();
EXPECT_EQ(0, main());
}
//TOTEST string type
Event Timeline
Log In to Comment