diff --git a/config/default.json b/config/default.json index a73a43d..e7f99d6 100644 --- a/config/default.json +++ b/config/default.json @@ -1,73 +1,74 @@ { "containers": { "id": { "implementations": "impl_fulfill_cluster", "clusters": "var_cluster", "prototypes": "proto_cluster", "linkedlist": "linkedlist" }, "impl": { "solid": "solid", "onthefly": "on_the_fly" } }, "logging": { "id": "logging" }, "function-entry": "entry", "transcend": { "bindings" : { "variable": "bind", "function": "bind_func", "scope": "bind_scope", "function_demand" : "bind_function_demand", "scope_decision": "bind_scope_decision" }, "context" : { "decisions":{ "dependent": "resolution_dependency" } }, "nonevalue": "nonevalue", "ret": { "symbol": "retv", "tag": "ret" } }, "tests": { - "template": "latereasoning", + "template": "intrinsic-query", "templates": { "current-fix":"*", "default": "*-Adhoc.*:Containers.*:Compilation.full_IFStatementWithVariantType:Types.full_VariantType_Switch1:Context.full_LateContext:Context.pathDependentContext:CFA.testLoopContextExists", "ast": "AST.*", "effects": "Effects.*", "basic": "Attachments.*", "compilation": "Compilation.*-Compilation.full_IFStatementWithVariantType", "communication": "Communication.*", "cfa": "CFA.*", "containers": "Containers.*", "dfa": "DFA.*", "diagnostic": "Diagnostic.*", "dsl": "Association.*:Interpretation.*", "exploitation": "Exploitation.*", "ExpressionSerializer": "ExpressionSerializer.*", "externc": "InterfaceExternC.*", "loops": "Loop.*", "latereasoning": "LateReasoning.Compilation2", "modules": "Modules.*", "polymorphs": "Polymorphs.*", + "intrinsic-query": "Types.SlaveTypes*:Association.TypedQuery*", "types": "Types.*", "virtualization": "Virtualization.test2", "vendorsAPI/clang": "ClangAPI.*", "vendorsAPI/xml2": "libxml2*" } } } diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index f03ed0e..8fd4295 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -1,231 +1,232 @@ cmake_minimum_required(VERSION 2.8.11) project(xreate) cmake_policy(SET CMP0022 NEW) message("MODULES" ${CMAKE_MODULE_PATH}) # LLVM #====================== FIND_PACKAGE (LLVM REQUIRED) set(LLVM_VERSION ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message("LLVM LIB PATH:" ${LLVM_LIBRARY_DIRS}) message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") INCLUDE_DIRECTORIES(${LLVM_INCLUDE_DIRS}) message(STATUS "INCLUDE DIR: ${LLVM_INCLUDE_DIRS}") add_definitions(${LLVM_DEFINITIONS}) message(STATUS "LLVM DEFS: " ${LLVM_DEFINITIONS}) execute_process( COMMAND llvm-config --libs OUTPUT_VARIABLE LLVM_LIBS OUTPUT_STRIP_TRAILING_WHITESPACE) message(STATUS "LLVM LIBS: " ${LLVM_LIBS}) # CLANG #====================== set(CLANG_LIBS clangCodeGen clangASTMatchers clangQuery clangTooling clangFrontend clangSerialization clangDriver clangParse clangSema clangAnalysis clangAST clangEdit clangLex clangBasic ) # POTASSCO #====================== set(POTASSCO_PATH "/opt/potassco/clingo" CACHE PATH "Path to potassco sources") set(POTASSCO_INCLUDE_PATH ${POTASSCO_PATH}/libgringo ${POTASSCO_PATH}/libclasp ${POTASSCO_PATH}/libclingo ${POTASSCO_PATH}/libprogram_opts ${POTASSCO_PATH}/liblp ) INCLUDE_DIRECTORIES(${POTASSCO_INCLUDE_PATH}) set(LIBCLASP_LIBS clingo clasp gringo program_opts reify lp ) message("CLASP LIBS: " ${LIBCLASP_LIBS}) # OTHER DEPENDENCIES #=========================== set(JEAYESON_INCLUDE_PATH ${CMAKE_HOME_DIRECTORY}/../vendors/jeayeson/include/ ) INCLUDE_DIRECTORIES(${JEAYESON_INCLUDE_PATH}) # COCO #=========================== set(COCO_EXECUTABLE "" CACHE PATH "Path to coco executable") set(COCO_FRAMES_PATH "" CACHE PATH "Path to coco frames") set(COCO_GRAMMAR_PATH ${CMAKE_HOME_DIRECTORY}/../grammar/) set(COCO_SOURCE_FILES_MAIN ${COCO_GRAMMAR_PATH}/main/Parser.cpp ${COCO_GRAMMAR_PATH}/main/Scanner.cpp ) set(COCO_SOURCE_FILES_MODULES ${COCO_GRAMMAR_PATH}/modules/Parser.cpp ${COCO_GRAMMAR_PATH}/modules/Scanner.cpp ) set(COCO_SOURCE_FILES ${COCO_SOURCE_FILES_MODULES} ${COCO_SOURCE_FILES_MAIN}) INCLUDE_DIRECTORIES(${COCO_GRAMMAR_PATH}) add_custom_command(OUTPUT ${COCO_SOURCE_FILES_MAIN} COMMAND ${COCO_GRAMMAR_PATH}/gen-grammar main ${COCO_EXECUTABLE} ${COCO_FRAMES_PATH} WORKING_DIRECTORY ${COCO_GRAMMAR_PATH} MAIN_DEPENDENCY ${COCO_GRAMMAR_PATH}/xreate.ATG ) add_custom_command(OUTPUT ${COCO_SOURCE_FILES_MODULES} COMMAND ${COCO_GRAMMAR_PATH}/gen-grammar modules ${COCO_EXECUTABLE} ${COCO_FRAMES_PATH} WORKING_DIRECTORY ${COCO_GRAMMAR_PATH} MAIN_DEPENDENCY ${COCO_GRAMMAR_PATH}/modules.ATG ) message(STATUS "COCO GRAMMAR BUILD STATUS:" ${COCO_OUTPUT}) # XREATE #====================== set(SOURCE_FILES - compilation/latereasoning.cpp + compilation/interpretation-instructions.cpp analysis/typeinference.cpp + compilation/latereasoning.cpp aux/latereasoning.cpp xreatemanager.cpp transcendlayer.cpp analysis/dfagraph.cpp analysis/DominatorsTreeAnalysisProvider.cpp llvmlayer.cpp ExternLayer.cpp pass/compilepass.cpp query/polymorph.cpp analysis/utils.cpp pass/dfapass.cpp compilation/targetinterpretation.cpp pass/interpretationpass.cpp ast.cpp aux/xreatemanager-decorators.cpp compilation/operators.cpp compilation/transformations.cpp compilation/transformersaturation.cpp pass/versionspass.cpp attachments.cpp analysis/cfagraph.cpp compilation/containers.cpp compilation/advancedinstructions.cpp utils.cpp pass/abstractpass.cpp pass/cfapass.cpp contextrule.cpp query/containers.cpp aux/serialization/expressionserializer.cpp modules.cpp ) set(XREATE_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/ ) INCLUDE_DIRECTORIES(${XREATE_INCLUDE_DIRS}) set(XREATE_PRIVATE_INCLUDE_DIRS ${XREATE_INCLUDE_DIRS} ${COCO_GRAMMAR_PATH} ${JEAYESON_INCLUDE_PATH} ${LLVM_INCLUDE_DIRS} ${POTASSCO_INCLUDE_PATH} ) add_library(${PROJECT_NAME} SHARED ${COCO_SOURCE_FILES} ${SOURCE_FILES}) target_link_libraries(${PROJECT_NAME}) target_include_directories(${PROJECT_NAME} INTERFACE ${XREATE_INCLUDE_DIRS} ${COCO_GRAMMAR_PATH} ${JEAYESON_INCLUDE_PATH} ${LLVM_INCLUDE_DIRS} ${POTASSCO_INCLUDE_PATH} ) get_directory_property(DEFINITIONS_ALL DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_DEFINITIONS) message("definitions all: " ${DEFINITIONS_ALL}) target_compile_definitions(${PROJECT_NAME} INTERFACE ${DEFINITIONS_ALL}) get_directory_property(COMPILATION_OPTIONS_ALL DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_OPTIONS) message("compilations all: " ${COMPILATION_OPTIONS_ALL}) target_compile_options(${PROJECT_NAME} INTERFACE ${COMPILATION_OPTIONS_ALL}) SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY INTERFACE_LINK_LIBRARIES ${LIBCLASP_LIBS} ${CLANG_LIBS} ${LLVM_LIBS} tbb boost_system boost_filesystem ) #${CLANG_LIBS} #set (LINK_INTERFACE_LIBRARIES "") # FUNCTION(PREPEND var prefix) # SET(listVar "") # FOREACH(f ${ARGN}) # LIST(APPEND listVar "${prefix}/${f}") # ENDFOREACH(f) # SET(${var} "${listVar}" PARENT_SCOPE) # ENDFUNCTION(PREPEND) #set(COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "-j4") #cotire(xreate) # MACRO (ADD_PCH_RULE _header_filename _src_list) # SET(_gch_filename "${_header_filename}.gch") # LIST(APPEND ${_src_list} ${_gch_filename}) # SET (_args ${CMAKE_CXX_FLAGS}) # LIST(APPEND _args -c ${_header_filename} -o ${_gch_filename}) # GET_DIRECTORY_PROPERTY(DIRINC INCLUDE_DIRECTORIES) # foreach (_inc ${DIRINC}) # LIST(APPEND _args "-I" ${_inc}) # endforeach(_inc ${DIRINC}) # SEPARATE_ARGUMENTS(_args) # add_custom_command(OUTPUT ${_gch_filename} # COMMAND rm -f ${_gch_filename} # COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1} ${_args} # DEPENDS ${_header_filename}) # ENDMACRO(ADD_PCH_RULE _header_filename _src_list) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/ast.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/llvmlayer.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/clasplayer.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/pass/abstractpass.h SOURCE_FILES) diff --git a/cpp/src/analysis/typeinference.cpp b/cpp/src/analysis/typeinference.cpp index 38b3d5d..8d3992c 100644 --- a/cpp/src/analysis/typeinference.cpp +++ b/cpp/src/analysis/typeinference.cpp @@ -1,93 +1,185 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * typeinference.cpp * * Author: pgess * Created on April 16, 2017, 10:13 AM */ /** * \file typeinference.h * \brief Type inference analysis */ #include "typeinference.h" #include "llvmlayer.h" #include "llvm/IR/Function.h" #include "llvm/IR/DerivedTypes.h" #include "transcendlayer.h" using namespace std; -namespace xreate {namespace typeinference { +namespace xreate{ +namespace typeinference{ //TODO type conversion: //a) automatically expand types int -> bigger int; int -> floating //b) detect exact type of `num` based on max used numeral / function type //c) warning if need to truncate (allow/dissalow based on annotations) llvm::Value* -doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, llvm::IRBuilder<>& builder){ - if (tyTarget->isIntegerTy() && source->getType()->isIntegerTy()) - { - llvm::IntegerType* tyTargetInt = llvm::dyn_cast(tyTarget); - llvm::IntegerType* tySourceInt = llvm::dyn_cast(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); - } +doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, llvm::IRBuilder<>& builder) { + if(tyTarget->isIntegerTy() && source->getType()->isIntegerTy()) { + llvm::IntegerType* tyTargetInt = llvm::dyn_cast(tyTarget); + llvm::IntegerType* tySourceInt = llvm::dyn_cast(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()){ + if(source->getType()->isIntegerTy() && tyTarget->isFloatingPointTy()) { return builder.CreateCast(llvm::Instruction::SIToFP, source, tyTarget); } return source; } ExpandedType -getType(const Expression& expression, const AST& ast){ - if (expression.type.isValid()){ - return ast.expandType(expression.type); +getType(const Expression& expression, const AST& ast) { + if(expression.type.isValid()) { + return ast.expandType(expression.type); } - if (expression.__state == Expression::IDENT){ + if(expression.__state == Expression::IDENT) { Symbol s = Attachments::get(expression); return getType(CodeScope::getDefinition(s), ast); } - if (Attachments::exists(expression)){ + if(Attachments::exists(expression)) { return Attachments::get(expression); } - if(expression.__state==Expression::NUMBER){ - return ExpandedType (TypeAnnotation(TypePrimitive::I32)); + if(expression.__state == Expression::NUMBER) { + return ExpandedType(TypeAnnotation(TypePrimitive::I32)); } assert(false && "Type can't be determined for an expression"); } -std::vector -getSlaveVariants(ExpandedType t, const TranscendLayer* transcend){ +TypeAnnotation collapseColumn(const std::list& symbols); + +TypeAnnotation +collapseFnGroup(const std::list& symbols) { + Gringo::Symbol symbolAny = symbols.front(); + size_t operandsCount = symbolAny.args().size; + + TypeAnnotation resultT; + resultT.__operands.reserve(operandsCount); + + for(size_t operandId = 0; operandId < operandsCount; ++operandId) { + std::list column; + + for(const Gringo::Symbol& row : symbols) { + column.push_back(row.args()[operandId]); + } + + TypeAnnotation operandT = collapseColumn(column); + resultT.__operands.push_back(operandT); + } + + if(resultT.__operands.size() == 1) { + return resultT.__operands.front(); + } + + if(resultT.__operands.size() > 1) { + resultT.__operator = TypeOperator::LIST_NAMED; + return resultT; + } + + return resultT; +} + +TypeAnnotation +collapseColumn(const std::list& symbols) { + TypeAnnotation resultT; + if(!symbols.size()) return resultT; + + Gringo::Symbol symbolAny = symbols.front(); + + switch(symbolAny.type()) { + case Gringo::SymbolType::Num: + { + return TypeAnnotation(TypePrimitive::Num); + } + + case Gringo::SymbolType::Str: + { + return TypeAnnotation(TypePrimitive::String); + } + + case Gringo::SymbolType::Fun: + { + map> fnGroups; + + for(const Gringo::Symbol& row : symbols) { + fnGroups[row.name().c_str()].push_back(row); + } + + TypeAnnotation resultT; + resultT.__operands.reserve(fnGroups.size()); + resultT.bindings.reserve(fnGroups.size()); + + for(const auto& group : fnGroups) { + if(!group.second.size()) continue; + + TypeAnnotation variantT = collapseFnGroup(group.second); + Gringo::Symbol symbolAny = group.second.front(); + string variantName = symbolAny.name().c_str(); + resultT.fields.push_back(variantName); + resultT.__operands.push_back(variantT); + } + + resultT.__operator = TypeOperator::VARIANT; + if(resultT.__operands.size() == 1) { + return resultT.__operands.front(); + } + return resultT; + } + + case Gringo::SymbolType::Inf: + case Gringo::SymbolType::Special: + case Gringo::SymbolType::Sup: + { + break; + } + } + + assert(false); + return TypeAnnotation(); +} + +ExpandedType +dereferenceSlaveType(ExpandedType t, const TranscendLayer* transcend) { assert(t->__operator == TypeOperator::SLAVE); const string& domain = t->__valueCustom; StaticModel model = transcend->query(domain); + if(!model.size()) return ExpandedType(TypeAnnotation()); - vector result; - result.reserve(model.size()); - for(auto entry: model){ - result.push_back(get<0>(TranscendLayer::parse(entry.second))); + std::list symbols; + for(auto row : model) { + symbols.push_back(row.second); } - - return result; + return ExpandedType(collapseFnGroup(symbols)); } -} } //end of namespace xreate::typeinference +} +} //end of namespace xreate::typeinference diff --git a/cpp/src/analysis/typeinference.h b/cpp/src/analysis/typeinference.h index aa956a3..500fc17 100644 --- a/cpp/src/analysis/typeinference.h +++ b/cpp/src/analysis/typeinference.h @@ -1,35 +1,37 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: typeinference.h * Author: pgess * * Created on April 16, 2017, 10:17 AM */ #ifndef TYPEINFERENCE_H #define TYPEINFERENCE_H #include "ast.h" #include "llvm/IR/IRBuilder.h" -namespace llvm { - class Value; - class Type; +namespace llvm{ +class Value; +class Type; }; -namespace xreate { - class TranscendLayer; +namespace xreate{ +class TranscendLayer; }; -namespace xreate { namespace typeinference { - +namespace xreate{ +namespace typeinference{ + llvm::Value* doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, llvm::IRBuilder<>& builder); -ExpandedType getType(const Expression& expression, const AST& ast); -std::vector getSlaveVariants(ExpandedType t, const TranscendLayer* transcend); +ExpandedType getType(const Expression& expression, const AST& ast); +ExpandedType dereferenceSlaveType(ExpandedType t, const TranscendLayer* transcend); -} }//namespace xreate::typeinference +} +}//namespace xreate::typeinference #endif /* TYPEINFERENCE_H */ diff --git a/cpp/src/compilation/interpretation-instructions.cpp b/cpp/src/compilation/interpretation-instructions.cpp new file mode 100644 index 0000000..97c2634 --- /dev/null +++ b/cpp/src/compilation/interpretation-instructions.cpp @@ -0,0 +1,167 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* + * Author: pgess + * Created on June 15, 2018, 5:32 PM + * + */ + +#include "compilation/interpretation-instructions.h" +#include "analysis/typeinference.h" +#include "transcendlayer.h" +#include "targets.h" + +using namespace std; + +namespace xreate{ +namespace interpretation{ + +Expression +IntrinsicQueryInstruction::representTransExpression(const Gringo::Symbol& atom, ExpandedType schemaT) { + TranscendLayer* transcend = static_cast (__scope->function->man)->pass->man->transcend; + + switch(schemaT->__operator) { + case TypeOperator::NONE: + { + switch(schemaT->__value) { + case TypePrimitive::I8: + case TypePrimitive::I32: + case TypePrimitive::I64: + case TypePrimitive::Num: + case TypePrimitive::Int: + { + return Expression(Atom(atom.num())); + } + + case TypePrimitive::String: + { + return Expression(Atom(atom.string().c_str())); + } + + case TypePrimitive::Invalid: + case TypePrimitive::Bool: + case TypePrimitive::Float: + { + assert(false); + return Expression(); + } + } + break; + } + + case TypeOperator::SLAVE: + { + ExpandedType contentT = typeinference::dereferenceSlaveType(schemaT, transcend); + return representTransExpression(atom, contentT); + } + + case TypeOperator::VARIANT: + { + map dictVariants; + for(size_t variantId = 0; variantId < schemaT->fields.size(); ++variantId) { + dictVariants.emplace(schemaT->fields.at(variantId), variantId); + } + + string predicateName = atom.name().c_str(); + assert(dictVariants.count(predicateName)); + + size_t predicateId = dictVariants.at(predicateName); + Expression result(Operator::VARIANT,{}); + result.op = Operator::VARIANT; + result.setValueDouble(predicateId); + + if(!schemaT->__operands.size()) return result; + ExpandedType contentT = schemaT->__operands.at(0).__operator == TypeOperator::SLAVE + ? typeinference::dereferenceSlaveType(ExpandedType(schemaT->__operands.at(0)), transcend) + : ExpandedType(schemaT->__operands.at(0)); + + //edge case, content's type is LIST_NAMED: + if (contentT->__operator == TypeOperator::LIST_NAMED) { + result.operands.push_back(representTransExpression(atom, contentT)); + + } else { + assert(atom.args().size); + result.operands.push_back(representTransExpression(atom.args()[0], contentT)); + } + + return result; + } + + case TypeOperator::LIST_NAMED: + { + const Gringo::SymSpan& operandsRaw = atom.args(); + size_t opCount = operandsRaw.size; + assert(opCount == schemaT->__operands.size()); + + size_t operandId = 0; + std::vector operands; + operands.reserve(opCount); + for(const TypeAnnotation operandT : schemaT->__operands) { + operands.push_back(representTransExpression(operandsRaw[operandId], ExpandedType(operandT))); + ++operandId; + } + + Expression result(Operator::LIST_NAMED,{}); + result.operands = operands; + result.type = schemaT; + return result; + } + + case TypeOperator::LIST: + case TypeOperator::CALL: + case TypeOperator::CUSTOM: + case TypeOperator::ACCESS: + case TypeOperator::LINK: + { + assert(false); + return Expression(); + } + } + + assert(false); + return Expression(); +} + +Expression +IntrinsicQueryInstruction::process(const Expression& expression) { + AST* ast = static_cast (__scope->function->man)->ast; + TranscendLayer* transcend = static_cast (__scope->function->man)->pass->man->transcend; + InterpretationFunction* function = static_cast (__scope->function); + + ExpandedType targetT = ast->expandType(expression.type); + assert(expression.operands.size() == 1); + assert(expression.operands.front().__state == Expression::STRING); + assert(targetT->__operator == TypeOperator::LIST); + + std::string namePredicate = expression.operands.front().getValueString(); + StaticModel model = (static_cast (function->man))->pass->man->transcend->query(namePredicate); + + Expression result(Operator::LIST,{}); + result.operands.reserve(model.size()); + + ExpandedType elementT = targetT->__operands.at(0).__operator == TypeOperator::SLAVE + ? typeinference::dereferenceSlaveType(ExpandedType(targetT->__operands.at(0)), transcend) + : ExpandedType(targetT->__operands.at(0)); + + if(model.size()) { + if (elementT->__operator == TypeOperator::LIST_NAMED) { + //edge case, content's type is LIST_NAMED: + for(const auto& row : model) { + result.operands.push_back(representTransExpression(row.second, elementT)); + } + } else { + for (const auto& row : model) { + assert(row.second.args().size); + result.operands.push_back(representTransExpression(row.second.args()[0], elementT)); + } + } + } + + return result; +} +} +} //end of xreate::interpretation \ No newline at end of file diff --git a/cpp/src/compilation/interpretation-instructions.h b/cpp/src/compilation/interpretation-instructions.h new file mode 100644 index 0000000..2ff6c8c --- /dev/null +++ b/cpp/src/compilation/interpretation-instructions.h @@ -0,0 +1,39 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* + * Author: pgess + * Created on June 15, 2018, 5:28 PM + * + * \file interpretation-instructions.h + * \brief Additional intepretation statements + */ + +#ifndef INTERPRETATION_INSTRUCTIONS_H +#define INTERPRETATION_INSTRUCTIONS_H + +#include "compilation/targetinterpretation.h" +#include "ast.h" + +namespace xreate{ +namespace interpretation{ + +class IntrinsicQueryInstruction{ +public: + + IntrinsicQueryInstruction(InterpretationScope* scope): __scope(scope){ } + Expression process(const Expression& expression); + +private: + InterpretationScope* __scope; + Expression representTransExpression(const Gringo::Symbol& atom, ExpandedType schemaT); +}; + +} +} //end of xreate::interpretation + +#endif /* INTERPRETATION_INSTRUCTIONS_H */ + diff --git a/cpp/src/compilation/latereasoning.cpp b/cpp/src/compilation/latereasoning.cpp index 97a7eb6..e62201f 100644 --- a/cpp/src/compilation/latereasoning.cpp +++ b/cpp/src/compilation/latereasoning.cpp @@ -1,79 +1,79 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * latereasoning.cpp * * Author: pgess * Created on May 26, 2018, 3:54 PM */ #include "compilation/latereasoning.h" #include "aux/latereasoning.h" #include "compilation/scopedecorators.h" #include "analysis/typeinference.h" #include using namespace xreate::compilation; using namespace std; namespace xreate{ namespace latereasoning { llvm::Value* LateReasoningCompiler::compile(const Expression& expr, const std::string& identHint){ #define HINT(x) (identHint.empty()? x : identHint) LLVMLayer* llvm = context.pass->man->llvm; compilation::ICodeScopeUnit* scope = context.scope; AST* root = context.pass->man->root; llvm::IRBuilder<>& builder = llvm->builder; compilation::IFunctionUnit* function = context.function; llvm::Type* typI8= llvm::Type::getInt8Ty(llvm->llvmContext); CodeScope* scopeBody = expr.blocks.front(); Symbol guardS = Symbol{scopeBody->getSymbol(expr.bindings.front()), scopeBody}; - const ExpandedType& typCondition = root->getType(expr.operands.at(0)); - vector guardVariants = typeinference::getSlaveVariants(typCondition, context.pass->man->transcend); - const int countVariants = guardVariants.size(); + const ExpandedType& conditionT = root->getType(expr.operands.at(0)); + const ExpandedType& conditionTPlain = typeinference::dereferenceSlaveType(conditionT, context.pass->man->transcend); + const int countVariants = conditionTPlain->fields.size(); assert(countVariants); llvm::Value * conditionRaw = scope->process(expr.operands.at(0)); llvm::Value* variantRaw = builder.CreateExtractValue(conditionRaw, llvm::ArrayRef({0})); llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(variantRaw, nullptr, countVariants); llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "switchLateAfter", function->raw); builder.SetInsertPoint(blockEpilog); llvm::Type* exprSwitchType = llvm->toLLVMType(root->getType(expr)); llvm::PHINode *ret = builder.CreatePHI(exprSwitchType, countVariants, HINT("switchLate")); llvm::BasicBlock* blockDefault = nullptr; bool flagFirstPass = true; for (int variantId = 0; variantId(guardS, guardVariants.at(variantId)) - : Attachments::update(guardS, guardVariants.at(variantId)); + Attachments::put(guardS, Expression(Operator::CALL, {Expression(Atom(string(conditionTPlain->fields.at(variantId))))})) + : Attachments::update(guardS, Expression(Operator::CALL, {Expression(Atom(string(conditionTPlain->fields.at(variantId))))})); flagFirstPass = false; llvm::BasicBlock *blockCase = llvm::BasicBlock::Create( llvm->llvmContext, "case" + std::to_string(variantId), function->raw); if(variantId == 0) blockDefault = blockCase; builder.SetInsertPoint(blockCase); auto scopeBody = Decorators::getInterface<>( function->getScopeUnit(expr.blocks.back())); scopeBody->reset(); llvm::Value* resultCase = scopeBody->compile(); ret->addIncoming(resultCase, builder.GetInsertBlock()); instructionSwitch->addCase(llvm::dyn_cast(llvm::ConstantInt::get(typI8, variantId)), blockCase); builder.CreateBr(blockEpilog); } instructionSwitch->setDefaultDest(blockDefault); builder.SetInsertPoint(blockEpilog); return ret; } }} \ No newline at end of file diff --git a/cpp/src/compilation/targetinterpretation.cpp b/cpp/src/compilation/targetinterpretation.cpp index 9d7d29d..1658d2f 100644 --- a/cpp/src/compilation/targetinterpretation.cpp +++ b/cpp/src/compilation/targetinterpretation.cpp @@ -1,645 +1,593 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: targetinterpretation.cpp * Author: pgess * * Created on June 29, 2016, 6:45 PM */ /** * \file targetinterpretation.h * \brief Interpretation support. See more [details on Interpretation](/w/concepts/dsl/) */ #include "compilation/targetinterpretation.h" #include "pass/interpretationpass.h" #include "analysis/typeinference.h" #include "llvmlayer.h" #include "compilation/scopedecorators.h" +#include "compilation/interpretation-instructions.h" #include #include -#include #include using namespace std; using namespace xreate::compilation; namespace xreate{ namespace interpretation{ const Expression EXPRESSION_FALSE = Expression(Atom(0)); const Expression EXPRESSION_TRUE = Expression(Atom(1)); -Expression -representAsAnnotation(const Gringo::Symbol& atom){ - switch (atom.type()) { - case Gringo::SymbolType::Num: { - Expression result(Operator::VARIANT, {Expression(atom.num())}); - result.setValueDouble(0); - return result; - } - - case Gringo::SymbolType::Str: { - Expression result(Operator::VARIANT, {Expression(Atom(std::string(atom.string().c_str())))}); - result.setValueDouble(1); - return result; - } - - case Gringo::SymbolType::Fun: { - Expression fnDescription(Operator::LIST_NAMED, {}); - std::list> bindings{Atom("name"), Atom("arguments")}; - fnDescription.addBindings(bindings.begin(), bindings.end()); - fnDescription.addArg(Expression(Atom(std::string(atom.name().c_str())))); - - Expression args(Operator::LIST, {}); - for (const Gringo::Symbol& arg : atom.args()) { - args.addArg(representAsAnnotation(arg)); - } - - fnDescription.addArg(std::move(args)); - - Expression result(Operator::VARIANT, {fnDescription}); - result.setValueDouble(2); - return result; - } - - default: { - assert(false); - } - } -} - CodeScope* InterpretationScope::processOperatorIf(const Expression& expression){ const Expression& exprCondition = process(expression.getOperands()[0]); if (exprCondition == EXPRESSION_TRUE){ return expression.blocks.front(); } return expression.blocks.back(); } CodeScope* InterpretationScope::processOperatorSwitch(const Expression& expression) { const Expression& exprCondition = process(expression.operands[0]); bool flagHasDefault = expression.operands[1].op == Operator::CASE_DEFAULT; //TODO check that one and only one case variant is appropriate for (size_t size = expression.operands.size(), i= flagHasDefault? 2: 1; igetScope((const CodeScope*) exprCase.blocks.front())->processScope() == exprCondition){ return exprCase.blocks.back(); } } if (flagHasDefault){ const Expression& exprCaseDefault = expression.operands[1]; return exprCaseDefault.blocks.front(); } assert(false && "Switch has no appropriate variant"); return nullptr; } CodeScope* InterpretationScope::processOperatorSwitchVariant(const Expression& expression){ const Expression& condition = process(expression.operands.at(0)); assert(condition.op == Operator::VARIANT); const string& identCondition = expression.bindings.front(); Expression opExpected(Atom(condition.getValueDouble())); auto itFoundValue = std::find(++expression.operands.begin(), expression.operands.end(), opExpected); assert(itFoundValue != expression.operands.end()); int indexBlock = itFoundValue - expression.operands.begin() -1; auto blockFound = expression.blocks.begin(); std::advance(blockFound, indexBlock); InterpretationScope* scopeI12n = function->getScope(*blockFound); if(condition.operands.size()){ const Expression& value=condition.operands.at(0); scopeI12n->overrideBindings({ {value, identCondition}}); } return *blockFound; } llvm::Value* InterpretationScope::compileHybrid(const InterpretationOperator& op, const Expression& expression, const Context& context){ switch(op){ case IF_INTERPRET_CONDITION: { CodeScope* scopeResult = processOperatorIf(expression); llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); return result; } case SWITCH_INTERPRET_CONDITION:{ CodeScope* scopeResult = processOperatorSwitch(expression); llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); return result; } case SWITCH_VARIANT: { CodeScope* scopeResult = processOperatorSwitchVariant(expression); const Expression& condition = expression.operands.at(0); const Expression& valueCondition = process(condition); const string identCondition = expression.bindings.front(); auto scopeCompilation = Decorators::getInterface(context.function->getScopeUnit(scopeResult)); if(valueCondition.operands.size()){ //override value Symbol symbCondition{ScopedSymbol{scopeResult->__identifiers.at(identCondition), versions::VERSION_NONE}, scopeResult}; scopeCompilation->overrideDeclarations( {{symbCondition, Expression(valueCondition.operands.at(0))}} ); //set correct type for binding: TypeAnnotation typeVariant = typeinference::getType(condition, *function->man->ast); int conditionIndex = valueCondition.getValueDouble(); ScopedSymbol symbolInternal = scopeResult->getSymbol(identCondition); scopeResult->__declarations[symbolInternal].bindType(typeVariant.__operands.at(conditionIndex)); } llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); return result; } case FOLD_INTERPRET_INPUT: { //initialization const Expression& exprInput = process(expression.getOperands()[0]); assert(exprInput.op == Operator::LIST); CodeScope* scopeBody = expression.blocks.front(); const string& nameEl = expression.bindings[0]; Symbol symbEl{ScopedSymbol{scopeBody->__identifiers.at(nameEl), versions::VERSION_NONE}, scopeBody}; const std::string& idAccum = expression.bindings[1]; llvm::Value* rawAccum = context.scope->process(expression.getOperands()[1]); InterpretationScope* intrBody = function->getScope(scopeBody); auto unitBody = Decorators::getInterface(context.function->getScopeUnit(scopeBody)); const std::vector elementsInput= exprInput.getOperands(); for(size_t i=0; ioverrideBindings({ {exprElement, nameEl}}); unitBody->overrideDeclarations({ {symbEl, exprElement}}); //resets unitBody unitBody->bindArg(rawAccum, string(idAccum)); rawAccum=unitBody->compile(); } return rawAccum; } /* case FOLD_INF_INTERPRET_INOUT{ } */ //TODO refactor as InterpretationCallStatement class case CALL_INTERPRET_PARTIAL: { const std::string &calleeName = expression.getValueString(); ICodeScopeUnit* scopeUnitSelf = context.scope; ManagedFnPtr callee = this->function->man->ast->findFunction(calleeName); const FunctionInterpretationData& calleeData = FunctionInterpretationHelper::getSignature(callee); std::vector argsActual; PIFSignature sig; sig.declaration = callee; for(size_t no=0, size = expression.operands.size(); no < size; ++no){ const Expression& op = expression.operands[no]; if (calleeData.signature.at(no) == INTR_ONLY){ sig.bindings.push_back(process(op)); continue; } argsActual.push_back(scopeUnitSelf->process(op)); } TargetInterpretation* man = dynamic_cast(this->function->man); PIFunction* pifunction = man->getFunction(move(sig)); llvm::Function* raw = pifunction->compile(); boost::scoped_ptr statement(new CallStatementRaw(raw, man->pass->man->llvm)); return (*statement)(move(argsActual)); } default: break; } assert(false&& "Unknown hybrid operator"); return nullptr; } llvm::Value* InterpretationScope::compile(const Expression& expression, const Context& context){ const InterpretationData& data = Attachments::get(expression); if (data.op != InterpretationOperator::NONE){ return compileHybrid(data.op, expression, context); } Expression result = process(expression); return context.scope->process(result); } Expression InterpretationScope::process(const Expression& expression) { #ifndef NDEBUG if (expression.tags.count("bpoint")){ std::raise(SIGINT); } #endif PassManager* man = (static_cast (function->man))->pass->man; switch (expression.__state){ case Expression::INVALID: assert(false); case Expression::NUMBER: case Expression::STRING: return expression; case Expression::IDENT:{ Symbol s = Attachments::get(expression); return Parent::processSymbol(s); } case Expression::COMPOUND: break; default: assert(false); } switch (expression.op) { case Operator::EQU: { const Expression& left = process(expression.operands[0]); const Expression& right = process(expression.operands[1]); if (left == right) return EXPRESSION_TRUE; return EXPRESSION_FALSE; } case Operator::NE: { const Expression& left = process(expression.operands[0]); const Expression& right = process(expression.operands[1]); if (left == right) return EXPRESSION_FALSE; return EXPRESSION_TRUE; } case Operator::LOGIC_AND: { assert(expression.operands.size() == 1); return process (expression.operands[0]); } // case Operator::LOGIC_OR: case Operator::CALL: { const std::string &fnName = expression.getValueString(); ManagedFnPtr fnAst = this->function->man->ast->findFunction(fnName); InterpretationFunction* fnUnit = this->function->man->getFunction(fnAst); vector args; args.reserve(expression.getOperands().size()); for(size_t i=0, size = expression.getOperands().size(); iprocess(args); } case Operator::CALL_INTRINSIC: { std::string nameFunction = expression.getValueString(); if(nameFunction=="query"){ - assert(expression.operands.size() == 1); - assert(expression.operands.front().__state == Expression::STRING); - - std::string namePredicate = expression.operands.front().getValueString(); - StaticModel model = (static_cast(function->man))->pass->man->transcend->query(namePredicate); - - Expression result(Operator::LIST, {}); - - if(model.size()) - for (const auto& row: model) { - result.addArg(representAsAnnotation(std::get<1>(row))); - } - - return result; + return IntrinsicQueryInstruction(this).process(expression); - } else if(nameFunction=="query_scope"){ - ScopePacked scopeId = man->transcend->pack(scope); - Expression result(Operator::VARIANT, {Expression(scopeId)}); - result.setValueDouble(0); - return result; + } else if(nameFunction=="query_scope"){ + ScopePacked scopeId = man->transcend->pack(scope); + Expression result(Operator::VARIANT, {Expression(scopeId)}); + result.setValueDouble(0); + return result; } else { - assert(false && "Unknown intrinsic"); + assert(false && "Unknown intrinsic"); } } case Operator::IF:{ CodeScope* scopeResult = processOperatorIf(expression); return function->getScope(scopeResult)->processScope(); } case Operator::SWITCH: { CodeScope* scopeResult = processOperatorSwitch(expression); return function->getScope(scopeResult)->processScope(); } case Operator::SWITCH_VARIANT: { CodeScope* scopeResult = processOperatorSwitchVariant(expression); return function->getScope(scopeResult)->processScope(); } case Operator::VARIANT: { if(!expression.operands.size()) return expression; Expression variantData = process(expression.operands[0]); Expression result{Operator::VARIANT, {variantData}}; result.setValueDouble(expression.getValueDouble()); return result; } case Operator::INDEX: { Expression exprData = process(expression.operands[0]); for (size_t keyId=1; keyIdgetScope(expression.blocks.front()); Expression accum = exprInit; for(size_t size=exprInput.getOperands().size(), i=0; ioverrideBindings({ {exprInput.getOperands()[i], argEl}, {accum, argAccum} }); accum = body->processScope(); } return accum; } case Operator::LIST: case Operator::LIST_NAMED: case Operator::LIST_RANGE: { Expression result(expression.op,{}); result.operands.resize(expression.operands.size()); result.bindings=expression.bindings; result.__indexBindings=expression.__indexBindings; int keyId=0; for(const Expression& opCurrent : expression.operands) { result.operands[keyId++]=process(opCurrent); } return result; } // case Operator::MAP: { // break; // } default: break; } return expression; } InterpretationFunction* TargetInterpretation::getFunction(IFunctionUnit* unit){ if (__dictFunctionsByUnit.count(unit)) { return __dictFunctionsByUnit.at(unit); } InterpretationFunction* f = new InterpretationFunction(unit->function, this); __dictFunctionsByUnit.emplace(unit, f); assert(__functions.emplace(unit->function.id(), f).second); return f; } PIFunction* TargetInterpretation::getFunction(PIFSignature&& sig){ auto f = __pifunctions.find(sig); if (f != __pifunctions.end()){ return f->second; } PIFunction* result = new PIFunction(PIFSignature(sig), __pifunctions.size(), this); __pifunctions.emplace(move(sig), result); assert(__dictFunctionsByUnit.emplace(result->functionUnit, result).second); return result; } InterpretationScope* TargetInterpretation::transformContext(const Context& c){ return this->getFunction(c.function)->getScope(c.scope->scope); } llvm::Value* TargetInterpretation::compile(const Expression& expression, const Context& ctx){ return transformContext(ctx)->compile(expression, ctx); } InterpretationFunction::InterpretationFunction(const ManagedFnPtr& function, Target* target) : Function(function, target) {} Expression InterpretationFunction::process(const std::vector& args){ InterpretationScope* body = getScope(__function->__entry); list> bindings; for(size_t i=0, size=args.size(); iscope->__bindings.at(i))); } body->overrideBindings(bindings); return body->processScope(); } // Partial function interpretation typedef BasicFunctionUnit PIFunctionUnitParent; class PIFunctionUnit : public PIFunctionUnitParent { public: PIFunctionUnit(ManagedFnPtr f, std::set&& arguments, size_t id, CompilePass* p) : PIFunctionUnitParent(f, p), argumentsActual(move(arguments)), __id(id) { } protected: std::vector prepareArguments(){ LLVMLayer* llvm = PIFunctionUnitParent::pass->man->llvm; AST* ast = PIFunctionUnitParent::pass->man->root; CodeScope* entry = PIFunctionUnitParent::function->__entry; std::vector signature; for(size_t no: argumentsActual){ VNameId argId = entry->__identifiers.at(entry->__bindings.at(no)); ScopedSymbol arg{argId, versions::VERSION_NONE}; signature.push_back(llvm->toLLVMType(ast->expandType(entry->__declarations.at(arg).type))); } return signature; } llvm::Function::arg_iterator prepareBindings(){ CodeScope* entry = PIFunctionUnitParent::function->__entry; ICodeScopeUnit* entryCompilation = PIFunctionUnitParent::getScopeUnit(entry); llvm::Function::arg_iterator fargsI = PIFunctionUnitParent::raw->arg_begin(); for(size_t no: argumentsActual){ ScopedSymbol arg{entry->__identifiers.at(entry->__bindings.at(no)), versions::VERSION_NONE}; entryCompilation->bindArg(&*fargsI, arg); fargsI->setName(entry->__bindings.at(no)); ++fargsI; } return fargsI; } virtual std::string prepareName(){ return PIFunctionUnitParent::prepareName() + "_" + std::to_string(__id); } private: std::set argumentsActual; size_t __id; }; PIFunction::PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target) : InterpretationFunction(sig.declaration, target), signatureInstance(move(sig)) { const FunctionInterpretationData& functionData = FunctionInterpretationHelper::getSignature(signatureInstance.declaration); std::set argumentsActual; for (size_t no=0, size=functionData.signature.size(); no < size; ++no){ if (functionData.signature.at(no) != INTR_ONLY){ argumentsActual.insert(no); } } functionUnit = new PIFunctionUnit(signatureInstance.declaration, move(argumentsActual), id, target->pass); CodeScope* entry = signatureInstance.declaration->__entry; auto entryUnit = Decorators::getInterface<>(functionUnit->getEntry()); InterpretationScope* entryIntrp = InterpretationFunction::getScope(entry); list> bindingsPartial; list> declsPartial; for(size_t no=0, sigNo=0, size=entry->__bindings.size(); no__bindings[no]}); VNameId argId=entry->__identifiers.at(entry->__bindings[no]); Symbol argSymbol{ScopedSymbol {argId, versions::VERSION_NONE}, entry}; declsPartial.push_back({argSymbol, signatureInstance.bindings[sigNo]}); ++sigNo; } } entryIntrp->overrideBindings(bindingsPartial); entryUnit->overrideDeclarations(declsPartial); } llvm::Function* PIFunction::compile(){ llvm::Function* raw = functionUnit->compile(); return raw; } bool operator<(const PIFSignature& lhs, const PIFSignature& rhs){ if (lhs.declaration.id() != rhs.declaration.id()) { return lhs.declaration.id() < rhs.declaration.id(); } return lhs.bindings < rhs.bindings; } bool operator<(const PIFSignature& lhs, PIFunction* const rhs){ return lhs < rhs->signatureInstance; } bool operator<(PIFunction* const lhs, const PIFSignature& rhs){ return lhs->signatureInstance < rhs; } }} /** \class xreate::interpretation::InterpretationFunction * * Holds list of xreate::interpretation::InterpretationScope 's focused on interpretation of individual code scopes * * There is particulat subclass PIFunction intended to represent partially interpreted functions *\sa TargetInterpretation, [Interpretation Concept](/w/concepts/dfa) */ /** \class xreate::interpretation::TargetInterpretation * * Executed during compilation and intented to preprocess eligible parts of code. * Established on [Targets Infrastructure](\ref compilation::Target) * * Holds list of InterpretationFunction / PIFunction to represent interpretation process for individual functions * * In order to be activated during compilation process there is * InterpretationScopeDecorator implementation of ICodeScopeUnit * \sa InterpretationPass, compilation::Target, [Interpretation Concept](/w/concepts/dfa) * */ diff --git a/cpp/src/compilation/targetinterpretation.h b/cpp/src/compilation/targetinterpretation.h index 7634199..ba03f34 100644 --- a/cpp/src/compilation/targetinterpretation.h +++ b/cpp/src/compilation/targetinterpretation.h @@ -1,132 +1,129 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: targetstatic.h * Author: pgess * * Created on July 2, 2016, 1:25 PM */ #ifndef TARGETSTATIC_H #define TARGETSTATIC_H #include "ast.h" #include "pass/compilepass.h" #include "compilation/targets.h" #include "pass/interpretationpass.h" #include "transcendlayer.h" namespace xreate{ namespace interpretation{ class TargetInterpretation; class InterpretationScope; class InterpretationFunction; }} namespace xreate{ namespace compilation{ template <> struct TargetInfo { typedef Expression Result; typedef interpretation::InterpretationScope Scope; typedef interpretation::InterpretationFunction Function; }; }} namespace xreate{ namespace interpretation{ /** \brief Encapsulates interpretation of a single Code Scope */ class InterpretationScope: public compilation::Scope{ typedef Scope Parent; public: InterpretationScope(const CodeScope* scope, compilation::Function* f): Parent(scope, f) {} Expression process(const Expression& expression) override; llvm::Value* compile(const Expression& expression, const compilation::Context& context); private: llvm::Value* compileHybrid(const InterpretationOperator& op, const Expression& expression, const compilation::Context& context); //llvm::Value* compilePartialFnCall(const Expression& expression, const Context& context); CodeScope* processOperatorIf(const Expression& expression); CodeScope* processOperatorSwitch(const Expression& expression); CodeScope* processOperatorSwitchVariant(const Expression& expression); }; /** \brief Encapsulates interpretation of a single %Function */ class InterpretationFunction: public compilation::Function{ public: InterpretationFunction(const ManagedFnPtr& function, compilation::Target* target); Expression process(const std::vector& args); }; /** \brief Signature of a partially interpreted function */ struct PIFSignature{ ManagedFnPtr declaration; std::vector bindings; }; class PIFunctionUnit; /** \brief Partially interpreted function */ class PIFunction: public InterpretationFunction{ public: PIFunctionUnit* functionUnit; PIFSignature signatureInstance; PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target); llvm::Function* compile(); }; bool operator<(const PIFSignature& lhs, PIFunction* const rhs); bool operator<(PIFunction* const lhs, const PIFSignature& rhs); /** \brief Encapsulates actual [Interpretation](/w/concepts/dfa) based on InterpretationPass analysis results */ class TargetInterpretation: public compilation::Target{ public: TargetInterpretation(AST* root, CompilePass* passCompilation): Target(root), pass(passCompilation){} //target: public: InterpretationFunction* getFunction(compilation::IFunctionUnit* unit); PIFunction* getFunction(PIFSignature&& sig); private: std::map __pifunctions; std::map __dictFunctionsByUnit; //self: public: CompilePass* pass; llvm::Value* compile(const Expression& expression, const compilation::Context& ctx); private: InterpretationScope* transformContext(const compilation::Context& c); }; /**\brief Interpretation-aware Code Scope decorator * \extends xreate::compilation::ICodeScopeUnit */ template class InterpretationScopeDecorator: public Parent{ public: InterpretationScopeDecorator(const CodeScope* const codeScope, compilation::IFunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} virtual llvm::Value* process(const Expression& expr, const std::string& hintVarDecl){ const InterpretationData& data = Attachments::get(expr, {ANY, NONE}); bool flagInterpretationEligible = (data.resolution == INTR_ONLY || data.op != InterpretationOperator::NONE); if (flagInterpretationEligible){ compilation::Context ctx{this, this->function, this->pass}; return Parent::pass->targetInterpretation->compile(expr, ctx); } return Parent::process(expr, hintVarDecl); } }; -/** \brief translates Logic expression(Gringo::Symbol) into Xreate expression to support intrinsic function `query` */ -Expression representAsAnnotation(const Gringo::Symbol& symbol); - }} //end of xreate:: interpretation #endif /* TARGETSTATIC_H */ \ No newline at end of file diff --git a/cpp/src/compilation/targets.h b/cpp/src/compilation/targets.h index dee23be..df281ca 100644 --- a/cpp/src/compilation/targets.h +++ b/cpp/src/compilation/targets.h @@ -1,198 +1,198 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: targetabstract.h * Author: pgess * * Created on July 2, 2016, 1:25 PM */ /** * \file * \brief Compilation targets infrastructure */ #ifndef TARGETABSTRACT_H #define TARGETABSTRACT_H #include "ast.h" #include #include #include namespace xreate{ namespace compilation { template struct TargetInfo{ //typedef Result //typedef Function //typedef Scope }; template class Function; template class Target; template class Scope{ typedef typename TargetInfo::Scope Self; public: const CodeScope* scope; + Function* function=0; typename TargetInfo::Result processSymbol(const Symbol& s){ const CodeScope* scope = s.scope; Self* self = function->getScope(scope); if (self->__bindings.count(s.identifier)) { return self->__bindings[s.identifier]; } const Expression& declaration = CodeScope::getDefinition(s, true); if (!declaration.isDefined()){ assert(false); //for bindings there should be result already } return self->__bindings[s.identifier] = self->process(declaration); } typename TargetInfo::Result processScope() { return process(scope->getBody()); } // typename TargetInfo::Result // processFunction(typename TargetInfo::Function* fnRemote, const std::vector::Result>& args){ // Scope scopeRemote = fnRemote->getScope(fnRemote->__function->__entry); // // if (scopeRemote->raw){ // return scopeRemote->raw; // } // // return fnRemote->process(args); // } virtual typename TargetInfo::Result process(const Expression& expression)=0; Scope(const CodeScope* codeScope, Function* f) : scope(codeScope), function(f) {} virtual ~Scope(){} void overrideBindings(std::list::Result, std::string>> bindings){ reset(); for (auto entry: bindings){ assert(scope->__identifiers.count(entry.second)); ScopedSymbol id{scope->__identifiers.at(entry.second), versions::VERSION_NONE}; __bindings[id] = entry.first; } } void registerChildScope(std::shared_ptr scope){ __childScopes.push_back(scope); } void reset(){ __bindings.clear(); __childScopes.clear(); } protected: - Function* function=0; std::map::Result> __bindings; std::list> __childScopes; }; template class Function{ typedef typename TargetInfo::Result Result; typedef typename TargetInfo::Scope ConcreteScope; public: Function(const ManagedFnPtr& function, Target* target) : man(target), __function(function) {} virtual ~Function(){}; ConcreteScope* getScope(const CodeScope* const scope){ if (__scopes.count(scope)) { auto result = __scopes.at(scope).lock(); if (result){ return result.get(); } } std::shared_ptr 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& args)=0; Target* man=0; ManagedFnPtr __function; protected: std::map> __scopes; std::shared_ptr __entryScope; }; /** \brief Similar to xreate::IPass */ template class Target { typedef typename TargetInfo::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 __functions; }; }} #endif /* TARGETABSTRACT_H */ diff --git a/cpp/tests/association.cpp b/cpp/tests/association.cpp index 23def6a..d97d2f3 100644 --- a/cpp/tests/association.cpp +++ b/cpp/tests/association.cpp @@ -1,129 +1,133 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * association.cpp * * Author: pgess * Created on August 12, 2017, 9:28 PM */ #include "xreatemanager.h" #include "transcendlayer.h" #include using namespace xreate; using namespace std; -TEST(Association, test1){ -std::string controller= -R"Code( +TEST(Association, test1) { + std::string controller = + R"Code( program(add). )Code"; -std::string script= -R"Code( + std::string script = + R"Code( Annotation = type variant { Num:: int, String:: string, Func:: {name::string, arguments::[Annotation]} }. extractCmd = function(program::Annotation):: Annotation; interpretation(force){ switch variant(program)::Annotation case (Num){String("wrong expression")} case (String){String("wrong expression")} case (Func){program["arguments"][0]} } main= function:: int; entry{ x= 5::int. y = 6::int. program = intrinsic query("program")[0]::Annotation. cmd = extractCmd(program)::Annotation; interpretation(force). answer = switch variant(cmd)::int case (Num) {0} case (String){0} case (Func){ switch(cmd["name"])::int case("add"){x + y} case default {0} }. answer } )Code"; std::unique_ptr man(XreateManager::prepare(std::move(script))); man->transcend->addRawScript(move(controller)); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(11, result); } -TEST(Association, QueryScope1){ -std::string script = R"Code( +TEST(Association, QueryScope1) { + std::string script = R"Code( Annotation = type variant { Num:: int, String:: string, Func:: {name::string, arguments::[Annotation]} }. func = function::int{10} //aux func in order to have few scopes main = function:: int; entry { scope = intrinsic query_scope()::Annotation. answer = switch variant(scope):: int case (Num) {scope} case (String){-1} case (Func){-1}. answer } )Code"; std::unique_ptr man(XreateManager::prepare(std::move(script))); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(1, result); } -//std::string script= -//R"Code( -// -//case context:: test1 { -//test= function::bool; registerTest { -// x = 8:: int. -// -// x == 8 -//}} -// -//case context:: test2{ -//test= function::bool{ -// x = 3::int. -// y = 12::int., -// -// (x+y) <> 25 -//}} -// -//runTests= function::bool{ -// tests = intrinsic query (registeredTests)::[Expression]. -// -// loop fold(tests->test::Expression, true->result):: bool { -// shot = { -// context:: make context (test) -// test() -// } -// -// result and shot -// } -//} -// -//main= function:: int; entry{ -// runTests() -//} -//)Code"; +TEST(Association, TypedQuery_1) { + auto man = details::tier1::XreateManager::prepare(R"Code( + AtomNumT = type slave atomNumT. + AtomStrT = type slave atomStrT. + CompListT = type slave compListT. + CompArithT = type slave compArithT. + + test = function:: num; entry + { + query1 = intrinsic query("atomNumT")::[AtomNumT]. + query2 = intrinsic query("atomStrT")::[AtomStrT]. + query3 = intrinsic query("compListT")::[CompListT]. + query4 = intrinsic query("compArithT")::[CompArithT]. + test1 = query1[0] == 5:: bool. + test2 = query2[1] == "y":: bool. + test3 = query3[0, 1] == "x" :: bool. + test4 = query4[0, 0, 0] == 1:: bool. + + test1 + test2 + test3 + test4 + } + )Code"); + + man->transcend->addRawScript(R"RAW( + atomNumT(5; 8). + atomStrT("x"; "y"). + compListT(5, "x"). + compListT(8, "y"). + compArithT(add(1, 2)). + compArithT(mul(5, 6)). + )RAW"); + + man->analyse(); + int (*test)() = (int (*)())man->run(); + int result = test(); + ASSERT_EQ(4, result); +} + + + diff --git a/cpp/tests/types.cpp b/cpp/tests/types.cpp index 51facbf..5d3c9f5 100644 --- a/cpp/tests/types.cpp +++ b/cpp/tests/types.cpp @@ -1,181 +1,235 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * types.cpp * * Created on: Jun 4, 2015 * Author: pgess */ #include "gtest/gtest.h" #include "xreatemanager.h" #include "llvmlayer.h" #include "main/Parser.h" +#include "transcendlayer.h" +#include "analysis/typeinference.h" using namespace std; using namespace xreate; using namespace xreate::grammar::main; TEST(Types, DependantTypes1) { - string&& code = "XmlNode = type {\n" - " tag:: string,\n" - " attrs:: [string], \n" - " content:: string\n" - "}.\n"; - - std::unique_ptr program(XreateManager::prepare(move(code))); - ExpandedType typeXmlNode = program->root->findType("XmlNode"); - - ASSERT_EQ(TypeOperator::LIST_NAMED, typeXmlNode->__operator); - ASSERT_EQ(3, typeXmlNode->__operands.size()); - ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(0).__value); - ASSERT_EQ(TypeOperator::LIST, typeXmlNode->__operands.at(1).__operator); - ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(2).__value); + string&& code = "XmlNode = type {\n" + " tag:: string,\n" + " attrs:: [string], \n" + " content:: string\n" + "}.\n"; + + std::unique_ptr program(XreateManager::prepare(move(code))); + ExpandedType typeXmlNode = program->root->findType("XmlNode"); + + ASSERT_EQ(TypeOperator::LIST_NAMED, typeXmlNode->__operator); + ASSERT_EQ(3, typeXmlNode->__operands.size()); + ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(0).__value); + ASSERT_EQ(TypeOperator::LIST, typeXmlNode->__operands.at(1).__operator); + ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(2).__value); } TEST(Types, ast_ParameterizedTypes_FeatureTypeIndex_1) { - string&& code = "XmlNode = type {\n" - " tag:: string,\n" - " attrs:: [string],\n" - " content:: string\n" - "}.\n" - "" - "Template = type(Leaf) {Leaf, [Leaf[content]]}." - "Concrete = type Template(XmlNode)."; - - std::unique_ptr program(XreateManager::prepare(move(code))); - ExpandedType typeConcrete = program->root->findType("Concrete"); - - ASSERT_EQ(TypeOperator::LIST_NAMED, typeConcrete->__operator); - ASSERT_EQ(2, typeConcrete->__operands.size()); - ASSERT_EQ(TypeOperator::LIST_NAMED, typeConcrete->__operands.at(0).__operator); - - ASSERT_EQ(TypeOperator::LIST, typeConcrete->__operands.at(1).__operator); - ASSERT_EQ(TypePrimitive::String, typeConcrete->__operands.at(1).__operands.at(0).__value); + string&& code = "XmlNode = type {\n" + " tag:: string,\n" + " attrs:: [string],\n" + " content:: string\n" + "}.\n" + "" + "Template = type(Leaf) {Leaf, [Leaf[content]]}." + "Concrete = type Template(XmlNode)."; + + std::unique_ptr program(XreateManager::prepare(move(code))); + ExpandedType typeConcrete = program->root->findType("Concrete"); + + ASSERT_EQ(TypeOperator::LIST_NAMED, typeConcrete->__operator); + ASSERT_EQ(2, typeConcrete->__operands.size()); + ASSERT_EQ(TypeOperator::LIST_NAMED, typeConcrete->__operands.at(0).__operator); + + ASSERT_EQ(TypeOperator::LIST, typeConcrete->__operands.at(1).__operator); + ASSERT_EQ(TypePrimitive::String, typeConcrete->__operands.at(1).__operands.at(0).__value); } TEST(Types, TreeType1) { - string&& code = "XmlNode = type {\n" - " tag:: string,\n" - " attrs:: [string],\n" - " content:: string\n" - "}.\n" - "" - "Tree = type(Leaf) {Leaf, [Tree(Leaf)]}." - "Concrete = type Tree(XmlNode)."; - - std::unique_ptr program(XreateManager::prepare(move(code))); - ExpandedType typeConcrete = program->root->findType("Concrete"); - - ASSERT_EQ(TypeOperator::LIST_NAMED, typeConcrete->__operator); - ASSERT_EQ(2, typeConcrete->__operands.size()); - ASSERT_EQ(TypeOperator::LIST_NAMED, typeConcrete->__operands.at(0).__operator); - - ASSERT_EQ(TypeOperator::LIST, 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); + string&& code = "XmlNode = type {\n" + " tag:: string,\n" + " attrs:: [string],\n" + " content:: string\n" + "}.\n" + "" + "Tree = type(Leaf) {Leaf, [Tree(Leaf)]}." + "Concrete = type Tree(XmlNode)."; + + std::unique_ptr program(XreateManager::prepare(move(code))); + ExpandedType typeConcrete = program->root->findType("Concrete"); + + ASSERT_EQ(TypeOperator::LIST_NAMED, typeConcrete->__operator); + ASSERT_EQ(2, typeConcrete->__operands.size()); + ASSERT_EQ(TypeOperator::LIST_NAMED, typeConcrete->__operands.at(0).__operator); + + ASSERT_EQ(TypeOperator::LIST, typeConcrete->__operands.at(1).__operator); + + auto typeLink = typeConcrete->__operands.at(1).__operands.at(0); + ASSERT_EQ(TypeOperator::LINK, typeLink.__operator); + ASSERT_EQ(typeConcrete->conjuctionId, typeLink.conjuctionId); } -TEST(Types, TreeType1LLvm){ - string&& code = "XmlNode = type {\n" - " tag:: string,\n" - " /* attrs:: [string],*/\n" - " content:: string\n" - "}.\n" - "" - "Tree = type(Leaf) {Leaf, [Tree(Leaf)]}." - "Concrete = type Tree(XmlNode)."; +TEST(Types, TreeType1LLvm) { + string&& code = "XmlNode = type {\n" + " tag:: string,\n" + " /* attrs:: [string],*/\n" + " content:: string\n" + "}.\n" + "" + "Tree = type(Leaf) {Leaf, [Tree(Leaf)]}." + "Concrete = type Tree(XmlNode)."; - std::unique_ptr program(XreateManager::prepare(move(code))); - ExpandedType typeConcrete = program->root->findType("Concrete"); + std::unique_ptr program(XreateManager::prepare(move(code))); + ExpandedType typeConcrete = program->root->findType("Concrete"); - llvm::Type* raw = program->llvm->toLLVMType(typeConcrete); + llvm::Type* raw = program->llvm->toLLVMType(typeConcrete); } -TEST(Types, ArrayOfExternal1){ - FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r"); +TEST(Types, ArrayOfExternal1) { + FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate", "r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST* ast = parser.root->finalize(); CodeScope* body = ast->findFunction("test")->getEntryScope(); const ExpandedType& t2 = ast->getType(body->getDefinition(body->getSymbol("childrenRaw"))); EXPECT_EQ(t2->__operator, TypeOperator::LIST); } -TEST(Types, ExternType1){ - FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r"); - assert(input != nullptr); +TEST(Types, ExternType1) { + FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate", "r"); + assert(input != nullptr); - Scanner scanner(input); - Parser parser(&scanner); - parser.Parse(); + Scanner scanner(input); + Parser parser(&scanner); + parser.Parse(); - AST* ast = parser.root->finalize(); - CodeScope* body = ast->findFunction("test")->getEntryScope(); + AST* ast = parser.root->finalize(); + CodeScope* body = ast->findFunction("test")->getEntryScope(); const ExpandedType& t2 = ast->getType(body->getDefinition(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()}"; +TEST(Types, ast_VariantType1) { + string&& code = + " colors = type variant {RED, BLUE, GREEN}.\n" + " test = function:: colors; entry {GREEN()}"; - std::unique_ptr program(XreateManager::prepare(move(code))); + std::unique_ptr program(XreateManager::prepare(move(code))); - ExpandedType typ = program->root->findType("colors"); - EXPECT_EQ(TypeOperator::VARIANT, typ->__operator); + ExpandedType typ = program->root->findType("colors"); + EXPECT_EQ(TypeOperator::VARIANT, typ->__operator); - Expression eRed = program->root->findFunction("test")->getEntryScope()->getBody(); - EXPECT_EQ(Operator::VARIANT, eRed.op); + Expression eRed = program->root->findFunction("test")->getEntryScope()->getBody(); + EXPECT_EQ(Operator::VARIANT, eRed.op); - const ExpandedType& typ2 = program->root->getType(eRed); - EXPECT_EQ(TypeOperator::VARIANT, typ2->__operator); + const ExpandedType& typ2 = program->root->getType(eRed); + EXPECT_EQ(TypeOperator::VARIANT, typ2->__operator); } -TEST(Types, full_VariantType_Switch1){ - string&& code = +TEST(Types, full_VariantType_Switch1) { + string&& code = "colors = type variant{RED, BLUE, GREEN}. \n" - " test = function:: colors {GREEN()} \n" + " test = function:: colors {GREEN()} \n" - "main = function:: int; entry { \n" - " switch(test()):: int \n" - " case (GREEN()) {0} \n" - " case default {1} \n" - "}"; + "main = function:: int; entry { \n" + " switch(test()):: int \n" + " case (GREEN()) {0} \n" + " case default {1} \n" + "}"; - XreateManager* man = XreateManager::prepare(move(code)); - int (*main)() = (int (*)()) man->run(); + XreateManager* man = XreateManager::prepare(move(code)); + int (*main)() = (int (*)()) man->run(); - EXPECT_EQ(0, main()); + EXPECT_EQ(0, main()); } -TEST(Types, ast_VariantType2){ - std::string script= -R"Code( +TEST(Types, ast_VariantType2) { + std::string script = + R"Code( Annotation = type variant { Num:: int, String:: string, Func:: {name::string, arguments::[Expression]} }. )Code"; std::unique_ptr program(XreateManager::prepare(move(script))); ExpandedType typ = program->root->findType("Annotation"); ASSERT_EQ(3, typ.get().fields.size()); } -//TEST(Types, A) - - -//TOTEST string type +TEST(Types, SlaveTypes_UnwrapSlaveType1) { + auto man = details::tier1::XreateManager::prepare(R"Code( + AtomNumT = type slave atomNumT. + AtomStrT = type slave atomStrT. + CmpndIntStrT = type slave cmpndIntStrT. + + VariantT = type slave variantT. + + VariantComplicatedT = type slave variantComplicatedT. + )Code"); + + man->transcend->addRawScript(R"RAW( + atomNumT(5). atomNumT(8). + atomStrT("a"). atomStrT("b"). + cmpndIntStrT(1, "a"). + cmpndIntStrT(2, "b"). + + variantT(first). + variantT(second). + variantT(third). + + variantComplicatedT(first(1, "a")). + variantComplicatedT(second("b")). + )RAW"); + + man->analyse(); + ExpandedType AtomNumT = man->root->findType("AtomNumT"); + ASSERT_EQ(AtomNumT->__operator, TypeOperator::SLAVE); + + ExpandedType ContentAtomNumT = typeinference::dereferenceSlaveType(AtomNumT, man->transcend); + ASSERT_EQ(TypePrimitive::Num, ContentAtomNumT->__value); + + ExpandedType AtomStrT = man->root->findType("AtomStrT"); + ExpandedType ContentAtomStrT = typeinference::dereferenceSlaveType(AtomStrT, + man->transcend); + ASSERT_EQ(TypePrimitive::String, ContentAtomStrT->__value); + + ExpandedType CmpndIntStrT = man->root->findType("CmpndIntStrT"); + ExpandedType ContentCmpndIntStrT = typeinference::dereferenceSlaveType(CmpndIntStrT, + man->transcend); + ASSERT_EQ(TypeOperator::LIST_NAMED, ContentCmpndIntStrT->__operator); + ASSERT_EQ(2, ContentCmpndIntStrT->__operands.size()); + + ExpandedType VariantT = man->root->findType("VariantT"); + ExpandedType ContentVariantT = typeinference::dereferenceSlaveType(VariantT, + man->transcend); + ASSERT_EQ(TypeOperator::VARIANT, ContentVariantT->__operator); + ASSERT_EQ(3, ContentVariantT->fields.size()); + + ExpandedType VariantComplicatedT = man->root->findType("VariantComplicatedT"); + ExpandedType ContentVariantComplicatedT = typeinference::dereferenceSlaveType(VariantComplicatedT, + man->transcend); + ASSERT_EQ(TypeOperator::VARIANT, ContentVariantComplicatedT->__operator); + ASSERT_EQ(2, ContentVariantComplicatedT->fields.size()); + ASSERT_EQ(2, ContentVariantComplicatedT->__operands.at(0).__operands.size()); +} \ No newline at end of file diff --git a/git-commit-template b/git-commit-template index 94da945..567e7b8 100644 --- a/git-commit-template +++ b/git-commit-template @@ -1,12 +1,12 @@ Syntax: Transcend: Compilation: -Documentation: <...> +Documentation: : <...> Malfunctions: Tests: