diff --git a/config/default.json b/config/default.json index 3a6cf8e..a73a43d 100644 --- a/config/default.json +++ b/config/default.json @@ -1,73 +1,73 @@ { "containers": { "id": { "implementations": "impl_fulfill_cluster", "clusters": "var_cluster", "prototypes": "proto_cluster", "linkedlist": "linkedlist" }, "impl": { "solid": "solid", "onthefly": "on_the_fly" } }, "logging": { "id": "logging" }, "function-entry": "entry", "transcend": { "bindings" : { "variable": "bind", "function": "bind_func", "scope": "bind_scope", "function_demand" : "bind_function_demand", "scope_decision": "bind_scope_decision" }, "context" : { "decisions":{ "dependent": "resolution_dependency" } }, "nonevalue": "nonevalue", "ret": { "symbol": "retv", "tag": "ret" } }, "tests": { "template": "latereasoning", "templates": { - "current-fix":"Compilation.*-Compilation.Sequence1:Compilation.full_IFStatementWithVariantType", + "current-fix":"*", "default": "*-Adhoc.*:Containers.*:Compilation.full_IFStatementWithVariantType:Types.full_VariantType_Switch1:Context.full_LateContext:Context.pathDependentContext:CFA.testLoopContextExists", "ast": "AST.*", "effects": "Effects.*", "basic": "Attachments.*", "compilation": "Compilation.*-Compilation.full_IFStatementWithVariantType", "communication": "Communication.*", "cfa": "CFA.*", "containers": "Containers.*", "dfa": "DFA.*", "diagnostic": "Diagnostic.*", "dsl": "Association.*:Interpretation.*", "exploitation": "Exploitation.*", "ExpressionSerializer": "ExpressionSerializer.*", "externc": "InterfaceExternC.*", "loops": "Loop.*", - "latereasoning": "LateReasoning.Syntax1", + "latereasoning": "LateReasoning.Compilation2", "modules": "Modules.*", "polymorphs": "Polymorphs.*", "types": "Types.*", "virtualization": "Virtualization.test2", "vendorsAPI/clang": "ClangAPI.*", "vendorsAPI/xml2": "libxml2*" } } } diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index c87e905..f03ed0e 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -1,230 +1,231 @@ cmake_minimum_required(VERSION 2.8.11) project(xreate) cmake_policy(SET CMP0022 NEW) message("MODULES" ${CMAKE_MODULE_PATH}) # LLVM #====================== FIND_PACKAGE (LLVM REQUIRED) set(LLVM_VERSION ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message("LLVM LIB PATH:" ${LLVM_LIBRARY_DIRS}) message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") INCLUDE_DIRECTORIES(${LLVM_INCLUDE_DIRS}) message(STATUS "INCLUDE DIR: ${LLVM_INCLUDE_DIRS}") add_definitions(${LLVM_DEFINITIONS}) message(STATUS "LLVM DEFS: " ${LLVM_DEFINITIONS}) execute_process( COMMAND llvm-config --libs OUTPUT_VARIABLE LLVM_LIBS OUTPUT_STRIP_TRAILING_WHITESPACE) message(STATUS "LLVM LIBS: " ${LLVM_LIBS}) # CLANG #====================== set(CLANG_LIBS clangCodeGen clangASTMatchers clangQuery clangTooling clangFrontend clangSerialization clangDriver clangParse clangSema clangAnalysis clangAST clangEdit clangLex clangBasic ) # POTASSCO #====================== set(POTASSCO_PATH "/opt/potassco/clingo" CACHE PATH "Path to potassco sources") set(POTASSCO_INCLUDE_PATH ${POTASSCO_PATH}/libgringo ${POTASSCO_PATH}/libclasp ${POTASSCO_PATH}/libclingo ${POTASSCO_PATH}/libprogram_opts ${POTASSCO_PATH}/liblp ) INCLUDE_DIRECTORIES(${POTASSCO_INCLUDE_PATH}) set(LIBCLASP_LIBS clingo clasp gringo program_opts reify lp ) message("CLASP LIBS: " ${LIBCLASP_LIBS}) # OTHER DEPENDENCIES #=========================== set(JEAYESON_INCLUDE_PATH ${CMAKE_HOME_DIRECTORY}/../vendors/jeayeson/include/ ) INCLUDE_DIRECTORIES(${JEAYESON_INCLUDE_PATH}) # COCO #=========================== set(COCO_EXECUTABLE "" CACHE PATH "Path to coco executable") set(COCO_FRAMES_PATH "" CACHE PATH "Path to coco frames") set(COCO_GRAMMAR_PATH ${CMAKE_HOME_DIRECTORY}/../grammar/) set(COCO_SOURCE_FILES_MAIN ${COCO_GRAMMAR_PATH}/main/Parser.cpp ${COCO_GRAMMAR_PATH}/main/Scanner.cpp ) set(COCO_SOURCE_FILES_MODULES ${COCO_GRAMMAR_PATH}/modules/Parser.cpp ${COCO_GRAMMAR_PATH}/modules/Scanner.cpp ) set(COCO_SOURCE_FILES ${COCO_SOURCE_FILES_MODULES} ${COCO_SOURCE_FILES_MAIN}) INCLUDE_DIRECTORIES(${COCO_GRAMMAR_PATH}) add_custom_command(OUTPUT ${COCO_SOURCE_FILES_MAIN} COMMAND ${COCO_GRAMMAR_PATH}/gen-grammar main ${COCO_EXECUTABLE} ${COCO_FRAMES_PATH} WORKING_DIRECTORY ${COCO_GRAMMAR_PATH} MAIN_DEPENDENCY ${COCO_GRAMMAR_PATH}/xreate.ATG ) add_custom_command(OUTPUT ${COCO_SOURCE_FILES_MODULES} COMMAND ${COCO_GRAMMAR_PATH}/gen-grammar modules ${COCO_EXECUTABLE} ${COCO_FRAMES_PATH} WORKING_DIRECTORY ${COCO_GRAMMAR_PATH} MAIN_DEPENDENCY ${COCO_GRAMMAR_PATH}/modules.ATG ) message(STATUS "COCO GRAMMAR BUILD STATUS:" ${COCO_OUTPUT}) # XREATE #====================== set(SOURCE_FILES + compilation/latereasoning.cpp + analysis/typeinference.cpp + aux/latereasoning.cpp + xreatemanager.cpp + transcendlayer.cpp + analysis/dfagraph.cpp analysis/DominatorsTreeAnalysisProvider.cpp llvmlayer.cpp ExternLayer.cpp - compilation/latereasoning.cpp pass/compilepass.cpp query/polymorph.cpp - transcendlayer.cpp analysis/utils.cpp - analysis/dfagraph.cpp pass/dfapass.cpp compilation/targetinterpretation.cpp pass/interpretationpass.cpp ast.cpp - xreatemanager.cpp - analysis/typeinference.cpp aux/xreatemanager-decorators.cpp compilation/operators.cpp compilation/transformations.cpp compilation/transformersaturation.cpp pass/versionspass.cpp attachments.cpp analysis/cfagraph.cpp compilation/containers.cpp compilation/advancedinstructions.cpp utils.cpp pass/abstractpass.cpp pass/cfapass.cpp contextrule.cpp query/containers.cpp aux/serialization/expressionserializer.cpp modules.cpp ) set(XREATE_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/ ) INCLUDE_DIRECTORIES(${XREATE_INCLUDE_DIRS}) set(XREATE_PRIVATE_INCLUDE_DIRS ${XREATE_INCLUDE_DIRS} ${COCO_GRAMMAR_PATH} ${JEAYESON_INCLUDE_PATH} ${LLVM_INCLUDE_DIRS} ${POTASSCO_INCLUDE_PATH} ) add_library(${PROJECT_NAME} SHARED ${COCO_SOURCE_FILES} ${SOURCE_FILES}) target_link_libraries(${PROJECT_NAME}) target_include_directories(${PROJECT_NAME} INTERFACE ${XREATE_INCLUDE_DIRS} ${COCO_GRAMMAR_PATH} ${JEAYESON_INCLUDE_PATH} ${LLVM_INCLUDE_DIRS} ${POTASSCO_INCLUDE_PATH} ) get_directory_property(DEFINITIONS_ALL DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_DEFINITIONS) message("definitions all: " ${DEFINITIONS_ALL}) target_compile_definitions(${PROJECT_NAME} INTERFACE ${DEFINITIONS_ALL}) get_directory_property(COMPILATION_OPTIONS_ALL DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_OPTIONS) message("compilations all: " ${COMPILATION_OPTIONS_ALL}) target_compile_options(${PROJECT_NAME} INTERFACE ${COMPILATION_OPTIONS_ALL}) SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY INTERFACE_LINK_LIBRARIES ${LIBCLASP_LIBS} ${CLANG_LIBS} ${LLVM_LIBS} tbb boost_system boost_filesystem ) #${CLANG_LIBS} #set (LINK_INTERFACE_LIBRARIES "") # FUNCTION(PREPEND var prefix) # SET(listVar "") # FOREACH(f ${ARGN}) # LIST(APPEND listVar "${prefix}/${f}") # ENDFOREACH(f) # SET(${var} "${listVar}" PARENT_SCOPE) # ENDFUNCTION(PREPEND) #set(COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "-j4") #cotire(xreate) # MACRO (ADD_PCH_RULE _header_filename _src_list) # SET(_gch_filename "${_header_filename}.gch") # LIST(APPEND ${_src_list} ${_gch_filename}) # SET (_args ${CMAKE_CXX_FLAGS}) # LIST(APPEND _args -c ${_header_filename} -o ${_gch_filename}) # GET_DIRECTORY_PROPERTY(DIRINC INCLUDE_DIRECTORIES) # foreach (_inc ${DIRINC}) # LIST(APPEND _args "-I" ${_inc}) # endforeach(_inc ${DIRINC}) # SEPARATE_ARGUMENTS(_args) # add_custom_command(OUTPUT ${_gch_filename} # COMMAND rm -f ${_gch_filename} # COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1} ${_args} # DEPENDS ${_header_filename}) # ENDMACRO(ADD_PCH_RULE _header_filename _src_list) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/ast.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/llvmlayer.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/clasplayer.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/pass/abstractpass.h SOURCE_FILES) diff --git a/cpp/src/analysis/dfagraph.cpp b/cpp/src/analysis/dfagraph.cpp index b80240d..ef28ec9 100644 --- a/cpp/src/analysis/dfagraph.cpp +++ b/cpp/src/analysis/dfagraph.cpp @@ -1,192 +1,218 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: DFAGraph.h * Author: pgess * */ /** * \file dfagraph.h * \brief Data Flow Analysis(DFA) graph data * */ #include "analysis/dfagraph.h" #include "analysis/utils.h" using namespace std; using namespace xreate::analysis; namespace xreate { namespace dfa { void DFACallInstance::print(std::ostringstream& output) const{ boost::format formatArgs; boost::format formatInstance("dfa_callfn(%1%, %2%)."); switch (type) { case WEAK: formatArgs = boost::format("weak(dfa_callargs(%1%, %2%, %3%))."); break; case STRONG: formatArgs = boost::format("weak(dfa_callargs(%1%, %2%, %3%)).\ndfa_callargs(%1%, %2%, %3%)."); break; } output << formatInstance % analysis::writeSymbolNode(retActual) % fnName << endl; for(std::pair rec: args) { SymbolNode argFormal(rec.first); output << formatArgs % analysis::writeSymbolNode(retActual) % analysis::writeSymbolNode(argFormal) % analysis::writeSymbolNode(rec.second) << endl; } } void DFAGraph::addDependency(const SymbolNode& node, const SymbolNode& subnode){ __dependencies.emplace(node, subnode); if (boost::get(&node)){ __usedSymbols.insert(node); } if (boost::get(&subnode)){ __usedSymbols.insert(node); } } void DFAGraph::printDependencies(std::ostringstream& output) const{ for(const SymbolNode& root: __roots){ printDependency(output, root, root); } } void DFAGraph::printDependency(std::ostringstream& output, const SymbolNode& nodeCurrent, const SymbolNode& nodeDependent) const { auto range = __dependencies.equal_range(nodeCurrent); for (auto it = range.first; it != range.second; ++it){ if (boost::get(&it->second)){ if (!__usedSymbols.count(it->second)){ printDependency(output, it->second, nodeDependent); continue; } } boost::format formatDependency("dfa_depends(%1%, %2%)."); output << formatDependency % analysis::writeSymbolNode(nodeDependent) % analysis::writeSymbolNode(it->second) << endl; printDependency(output, it->second, it->second); } } void -DFAGraph::printInplaceAnnotations(SymbolNode node, const Expression& expression) { +DFAGraph::printInplaceAnnotation(const SymbolNode& node, const Expression& expression) { // write down in-place expression tags: boost::format formatBind("bind(%1%, %2%)."); + __usedSymbols.insert(node); - if (expression.tags.size()) __usedSymbols.insert(node); + for (const string& tag: xreate::analysis::compile(expression)) { + __output << formatBind + % analysis::writeSymbolNode(node) + % tag + << endl; + } +} - for (const pair& tag : expression.tags){ - for (const string& tagPart: xreate::analysis::compile(tag.second)) { - __output << formatBind - % analysis::writeSymbolNode(node) - % tagPart - << endl; - } +void +DFAGraph::printLateAnnotation(const SymbolNode& node, + const Expression& expression, + const std::list& symbols, + const std::list& domains){ + boost::format formatLateAnnotation("late(%1%, (%2%), (%3%), %4%):- %5%."); + boost::format formatDom("%1%(%2%)"); + std::list exprSerialized = xreate::analysis::compile(expression); + assert(exprSerialized.size() == 1); + + list identSymbols, identNames, domainsSerialised; + + auto domainI = domains.begin(); + for(auto symbol: symbols){ + identSymbols.push_back(analysis::writeSymbolNode(symbol.second).str()); + identNames.push_back(symbol.first); + domainsSerialised.push_back((formatDom % *domainI % symbol.first).str()); + ++domainI; } + + __output << formatLateAnnotation + % analysis::writeSymbolNode(node) + % boost::algorithm::join(identSymbols, ", ") + % boost::algorithm::join(identNames, ", ") + % exprSerialized.front() + % boost::algorithm::join(domainsSerialised, "; ") + << endl; } void DFAGraph::printAlias(const SymbolNode& symbFormal, const SymbolNode& symbActual){ __usedSymbols.insert(symbFormal); __usedSymbols.insert(symbActual); boost::format formatAlias("dfa_alias(%1%, %2%)."); __output << formatAlias % analysis::writeSymbolNode(symbFormal) % analysis::writeSymbolNode(symbActual) << endl; } void DFAGraph::printWeakAlias(const SymbolNode& symbFormal, const SymbolNode& symbActual){ __usedSymbols.insert(symbFormal); __usedSymbols.insert(symbActual); boost::format formatAlias("weak(dfa_alias(%1%, %2%))."); __output << formatAlias % analysis::writeSymbolNode(symbFormal) % analysis::writeSymbolNode(symbActual) << endl; } void DFAGraph::printFunctionRet(ManagedFnPtr function, const SymbolNode& symbolRet){ boost::format formatRet("dfa_fnret(%1%, %2%)."); __usedSymbols.insert(symbolRet); __output << formatRet % function->getName() % analysis::writeSymbolNode(symbolRet) << endl; __roots.insert(symbolRet); } void DFAGraph::addCallInstance(DFACallInstance&& instance){ __usedSymbols.insert(instance.retActual); for(const auto arg: instance.args){ __usedSymbols.insert(SymbolNode(arg.first)); __usedSymbols.insert(arg.second); } __callInstances.push_back(std::move(instance)); } void DFAGraph::print(std::ostringstream& output) const{ output << endl << "%\t\tStatic analysis: DFA" << endl; //Dependencies printDependencies(output); //Add generated report output << __output.str() << endl; //Call instances for(const DFACallInstance& instance: __callInstances){ instance.print(output); } output << endl; } void DFAGraph::printSymbols(TranscendLayer* transcend){ boost::format formatHint("shint(%1%, \"%2%\")."); for (const SymbolNode& node : __usedSymbols) { __output << "v(" << analysis::writeSymbolNode(node) << "). "; if (const SymbolPacked* symbol = boost::get(&node)){ __output << formatHint % analysis::writeSymbolNode(node) % transcend->getHintForPackedSymbol(*symbol); } __output << endl; } } }} //end of namespace xreate::dfa diff --git a/cpp/src/analysis/dfagraph.h b/cpp/src/analysis/dfagraph.h index a599ac9..00ccb67 100644 --- a/cpp/src/analysis/dfagraph.h +++ b/cpp/src/analysis/dfagraph.h @@ -1,58 +1,65 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: dfa.h * Author: pgess * * Created on June 27, 2016, 1:50 PM */ #ifndef DFA_H #define DFA_H #include "transcendlayer.h" #include +namespace xreate { namespace latereasoning { + typedef std::pair LateSymbolRecognized; +}} + namespace xreate {namespace dfa { enum DFACallInstanceType { STRONG, WEAK }; class DFACallInstance { public: std::string fnName; std::vector> args; SymbolNode retActual; DFACallInstanceType type; void print(std::ostringstream& output) const; }; /** \brief Holds DFA Analysis report produced by DFAPass */ class DFAGraph : public IAnalysisReport { public: // DFAGraph(TranscendLayer* engine): __transcend(engine){} virtual void print(std::ostringstream& output) const override; void addCallInstance(DFACallInstance && instance); void addDependency(const SymbolNode& node, const SymbolNode& subnodeBlock); - void printInplaceAnnotations(SymbolNode node, const Expression& expression); + void printInplaceAnnotation(const SymbolNode& node, const Expression& expression); + void printLateAnnotation(const SymbolNode& node, const Expression& expression, + const std::list& symbols, + const std::list& domains); void printAlias(const SymbolNode& symbFormal, const SymbolNode& symbActual); void printWeakAlias(const SymbolNode& symbFormal, const SymbolNode& symbActual); void printFunctionRet(ManagedFnPtr function, const SymbolNode& symbolRet); void printDependencies(std::ostringstream& output) const; void printSymbols(TranscendLayer* transcend); private: mutable std::ostringstream __output; std::list __callInstances; std::unordered_multimap __dependencies; std::unordered_set __usedSymbols; std::unordered_set __roots; void printDependency(std::ostringstream& output, const SymbolNode& nodeCurrent, const SymbolNode& nodeDependent) const; }; }} // end of namespace xreate::dfa #endif /* DFA_H */ diff --git a/cpp/src/analysis/typeinference.cpp b/cpp/src/analysis/typeinference.cpp index 2b48e10..38b3d5d 100644 --- a/cpp/src/analysis/typeinference.cpp +++ b/cpp/src/analysis/typeinference.cpp @@ -1,75 +1,93 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * typeinference.cpp * * Author: pgess * Created on April 16, 2017, 10:13 AM */ /** * \file typeinference.h * \brief Type inference analysis */ #include "typeinference.h" #include "llvmlayer.h" #include "llvm/IR/Function.h" #include "llvm/IR/DerivedTypes.h" +#include "transcendlayer.h" + +using namespace std; namespace xreate {namespace typeinference { //TODO type conversion: //a) automatically expand types int -> bigger int; int -> floating //b) detect exact type of `num` based on max used numeral / function type //c) warning if need to truncate (allow/dissalow based on annotations) llvm::Value* doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, llvm::IRBuilder<>& builder){ if (tyTarget->isIntegerTy() && source->getType()->isIntegerTy()) { llvm::IntegerType* tyTargetInt = llvm::dyn_cast(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()){ return builder.CreateCast(llvm::Instruction::SIToFP, source, tyTarget); } return source; } ExpandedType getType(const Expression& expression, const AST& ast){ if (expression.type.isValid()){ return ast.expandType(expression.type); } if (expression.__state == Expression::IDENT){ Symbol s = Attachments::get(expression); return getType(CodeScope::getDefinition(s), ast); } if (Attachments::exists(expression)){ return Attachments::get(expression); } 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){ + assert(t->__operator == TypeOperator::SLAVE); + const string& domain = t->__valueCustom; + StaticModel model = transcend->query(domain); + + vector result; + result.reserve(model.size()); + for(auto entry: model){ + result.push_back(get<0>(TranscendLayer::parse(entry.second))); + } + + return result; +} + } } //end of namespace xreate::typeinference diff --git a/cpp/src/analysis/typeinference.h b/cpp/src/analysis/typeinference.h index 1b8cece..aa956a3 100644 --- a/cpp/src/analysis/typeinference.h +++ b/cpp/src/analysis/typeinference.h @@ -1,30 +1,35 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: typeinference.h * Author: pgess * * Created on April 16, 2017, 10:17 AM */ #ifndef TYPEINFERENCE_H #define TYPEINFERENCE_H #include "ast.h" #include "llvm/IR/IRBuilder.h" namespace llvm { class Value; class Type; }; +namespace xreate { + class TranscendLayer; +}; + namespace xreate { namespace typeinference { llvm::Value* doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, llvm::IRBuilder<>& builder); ExpandedType getType(const Expression& expression, const AST& ast); +std::vector getSlaveVariants(ExpandedType t, const TranscendLayer* transcend); } }//namespace xreate::typeinference #endif /* TYPEINFERENCE_H */ diff --git a/cpp/src/analysis/utils.cpp b/cpp/src/analysis/utils.cpp index 63592f5..471e24d 100644 --- a/cpp/src/analysis/utils.cpp +++ b/cpp/src/analysis/utils.cpp @@ -1,160 +1,159 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * aux.cpp * * Author: pgess */ /** * \file aux.h * \brief Data representation in ASP format ready for use by reasoner */ #include "utils.h" #include namespace xreate { namespace analysis { using namespace std; list multiplyLists(list> &&lists) { typedef list StringList; assert(lists.size()); StringList result(*lists.begin()); lists.pop_front(); boost::format concat("%s, %s"); for (StringList &list: lists) { StringList::const_iterator end = result.end(); for (StringList::iterator expr1I = result.begin(); expr1I != end; ++expr1I) { if (list.size() == 0) continue; StringList::const_iterator expr2I = list.begin(); for (int expr2No = 0, size = list.size() - 1; expr2No < size; ++expr2No, ++expr1I) result.push_back(str(concat %(*expr1I) %(*expr2I))); *expr1I = str(concat %(*expr1I) %(*expr2I)); } } return result; } std::list compile(const Expression &e){ list result; switch (e.op) { case Operator::CALL: { - assert(e.__state == Expression::COMPOUND); - if(!e.operands.size()){ result.push_back(e.getValueString()); break; } std::list> operands; std::transform(e.operands.begin(), e.operands.end(), std::inserter(operands, operands.begin()), [](const Expression &e) { return compile(e); }); list &&operands_ = multiplyLists(std::move(operands)); result.push_back(boost::str(boost::format("%1%(%2%)") % (e.getValueString()) % (boost::algorithm::join(operands_, ", ")))); break; } + case Operator::NEG: { assert(e.operands.size() == 1); const Expression &op = e.operands.at(0); list &&rawOp = compile(op); assert(rawOp.size() == 1); result.push_back((boost::format("not %1%")%(rawOp.front())).str()); break; }; case Operator::INVALID: { switch (e.__state) { case Expression::IDENT: result.push_back(e.getValueString()); break; case Expression::NUMBER: result.push_back(to_string(e.getValueDouble())); break; default: assert(true); } break; } default: break; } assert(result.size()); return result; } std::list compileNeg(const Expression &e){ list result; switch (e.op) { case Operator::IMPL: { assert(e.__state == Expression::COMPOUND); assert(e.operands.size() == 2); list operands1 = compile(e.operands.at(0)); list operands2 = compile(e.operands.at(1)); boost::format formatNeg("%1%, not %2%"); for (const auto &op1: operands1) for (const auto &op2: operands2) { result.push_back(boost::str(formatNeg %(op1) % (op2))); } break; } case Operator::NEG: { assert(e.operands.size() == 1); const Expression &op = e.operands.at(0); list &&rawOp = compile(op); assert(rawOp.size() == 1); result.push_back(rawOp.front()); break; }; default: assert(true); } return result; } //NOTE: Any changes should be reflected in ParseImplAtom, // ParseImplAtom class VisitorFormatSymbol: public boost::static_visitor { public: boost::format operator()(const SymbolPacked& node) const { boost::format formatSymbNamed("s(%1%,%2%,%3%)"); return formatSymbNamed % node.identifier % node.version % node.scope ; } boost::format operator()(const SymbolAnonymous& node) const { boost::format formatSymbAnonymous("a(%1%)"); return formatSymbAnonymous % node.id; } }; boost::format writeSymbolNode(const SymbolNode& symbol){ return boost::apply_visitor(VisitorFormatSymbol(), symbol); } }} //end of xreate::analysis diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp index d73895f..8a91699 100644 --- a/cpp/src/ast.cpp +++ b/cpp/src/ast.cpp @@ -1,977 +1,982 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * File: ast.cpp */ /** * \file ast.h * \brief Syntax Tree and related code * * \sa xreate::AST */ #include "ast.h" #include "ExternLayer.h" #include "analysis/typeinference.h" #include #include //TODO BDecl. forbid multiple body declaration (ExprTyped) namespace std { std::size_t hash::operator()(xreate::ScopedSymbol const& s) const { return s.id ^ (s.version << 2); } bool equal_to::operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const { return __x.id == __y.id && __x.version == __y.version; } size_t hash::operator()(xreate::Symbol const& s) const { return hash()(s.identifier) ^ ((long int) s.scope << 1); } bool equal_to::operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const { return __x == __y; }; } using namespace std; namespace xreate { Atom::Atom(const std::wstring& value) { __value = wstring_to_utf8(value); } Atom::Atom(std::string && name) : __value(name) { } const std::string& Atom::get() const { return __value; } Atom::Atom(wchar_t* value) { //DEBT reconsider number literal recognition __value = wcstol(value, 0, 10); } Atom::Atom(int value) : __value(value) { } double Atom::get()const { return __value; } Atom::Atom(const std::wstring& value) { assert(value.size() >= 2); __value = wstring_to_utf8(value.substr(1, value.size() - 2)); } Atom::Atom(std::string && name) : __value(name) {} const std::string& Atom::get() const { return __value; } class ExpressionHints { public: static bool isStringValueValid(const Expression& e) { switch (e.__state) { case Expression::INVALID: assert(false); case Expression::IDENT: case Expression::STRING: return true; case Expression::NUMBER: case Expression::BINDING: return false; case Expression::COMPOUND: { switch (e.op) { case Operator::CALL: return true; default: return false; } } } return false; } static bool isDoubleValueValid(const Expression& e) { switch (e.__state) { case Expression::NUMBER: return true; case Expression::INVALID: assert(false); case Expression::IDENT: case Expression::STRING: case Expression::BINDING: return false; case Expression::COMPOUND: { switch (e.op) { case Operator::VARIANT: return true; default: return false; } } } return false; } }; class TypesResolver { private: const AST* ast; std::map scope; std::map signatures; ExpandedType expandType(const TypeAnnotation &t, const std::vector &args = std::vector()) { return TypesResolver(ast, scope, signatures)(t, args); } std::vector expandOperands(const std::vector& operands) { std::vector 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& scopeOuter = std::map(), std::map signaturesOuter = std::map()) : ast(root), scope(scopeOuter), signatures(signaturesOuter) { } ExpandedType operator()(const TypeAnnotation &t, const std::vector &args = std::vector()) { //assert(args.size() == t.bindings.size()); // invalid number of arguments for (size_t i = 0; i < args.size(); ++i) { scope[t.bindings.at(i)] = args.at(i); } switch (t.__operator) { case TypeOperator::LIST: { assert(t.__operands.size() == 1); Expanded elTy = expandType(t.__operands.at(0)); return ExpandedType(TypeAnnotation(tag_array, elTy, 0)); } case TypeOperator::LIST_NAMED: { std::vector&& packOperands = expandOperands(t.__operands); auto typNew = TypeAnnotation(TypeOperator::LIST_NAMED, move(packOperands)); typNew.fields = t.fields; return ExpandedType(move(typNew)); }; case TypeOperator::VARIANT: { std::vector&& packOperands = expandOperands(t.__operands); auto typNew = TypeAnnotation(TypeOperator::VARIANT, move(packOperands)); typNew.fields = t.fields; return ExpandedType(move(typNew)); }; case TypeOperator::CALL: { std::string alias = t.__valueCustom; //find in local scope: TypeAnnotation ty; if (scope.count(alias)) { ty = scope.at(alias); } else if (ast->__indexTypeAliases.count(alias)) { ty = ast->__indexTypeAliases.at(alias); } else { assert(false && "Undefined or external type"); } std::vector&& operands = expandOperands(t.__operands); TypeAnnotation signature(TypeOperator::CALL, move(operands)); signature.__valueCustom = alias; if (signatures.count(signature)) { auto link = TypeAnnotation(TypeOperator::LINK,{}); link.conjuctionId = signatures.at(signature); return ExpandedType(move(link)); } int cid = signatures.size(); signatures[signature] = cid; TypeAnnotation tyResult = expandType(ty, operands); tyResult.conjuctionId = cid; return ExpandedType(move(tyResult)); }; case TypeOperator::CUSTOM: { if (signatures.count(t)) { return ExpandedType(TypeAnnotation(TypeOperator::LINK, {t})); } signatures.emplace(t, signatures.size()); std::string alias = t.__valueCustom; //find in local scope: if (scope.count(alias)) { return expandType(scope.at(alias)); } //find in general scope: if (ast->__indexTypeAliases.count(alias)) { return expandType(ast->__indexTypeAliases.at(t.__valueCustom)); } //if type is unknown keep it as is. return ExpandedType(TypeAnnotation(t)); }; case TypeOperator::ACCESS: { std::string alias = t.__valueCustom; ExpandedType tyAlias = ExpandedType(TypeAnnotation()); //Find in local scope: if (scope.count(alias)) { tyAlias = expandType(scope.at(alias)); //Find in global scope: } else if ((ast->__indexTypeAliases.count(alias))) { tyAlias = expandType(ast->__indexTypeAliases.at(alias)); } else { assert(false && "Undefined or external type"); } assert(tyAlias->__operator == TypeOperator::LIST_NAMED); for (const string& field : t.fields) { auto fieldIt = std::find(tyAlias->fields.begin(), tyAlias->fields.end(), field); assert(fieldIt != tyAlias->fields.end() && "unknown field"); int fieldId = fieldIt - tyAlias->fields.begin(); tyAlias = expandType(tyAlias->__operands.at(fieldId)); } return tyAlias; } case TypeOperator::NONE: { return ExpandedType(TypeAnnotation(t)); } + case TypeOperator::SLAVE: + { + return ExpandedType(t); + } + default: assert(false); } assert(false); return ExpandedType(TypeAnnotation()); } }; TypeAnnotation::TypeAnnotation() : __operator(TypeOperator::NONE), __value(TypePrimitive::Invalid) { } TypeAnnotation::TypeAnnotation(TypePrimitive typ) : __value(typ) { } TypeAnnotation::TypeAnnotation(TypeOperator op, std::initializer_list operands) : __operator(op), __operands(operands) { } TypeAnnotation::TypeAnnotation(TypeOperator op, std::vector&& operands) : __operator(op), __operands(operands) { } TypeAnnotation::TypeAnnotation(llvm_array_tag, TypeAnnotation typ, int size) : TypeAnnotation(TypeOperator::LIST,{typ}) { __size = size; } bool TypeAnnotation::isValid() const { return !(__value == TypePrimitive::Invalid && __operator == TypeOperator::NONE); } bool TypeAnnotation::operator<(const TypeAnnotation& t) const { if (__operator != t.__operator) return __operator < t.__operator; if (__operator == TypeOperator::NONE) return __value < t.__value; if (__operator == TypeOperator::CALL || __operator == TypeOperator::CUSTOM || __operator == TypeOperator::ACCESS) { if (__valueCustom != t.__valueCustom) return __valueCustom < t.__valueCustom; } return __operands < t.__operands; } /* TypeAnnotation (struct_tag, std::initializer_list) {} */ void TypeAnnotation::addBindings(std::vector>&& params) { bindings.reserve(bindings.size() + params.size()); std::transform(params.begin(), params.end(), std::inserter(bindings, bindings.end()), [](const Atom& ident) { return ident.get(); }); } void TypeAnnotation::addFields(std::vector>&& listFields) { fields.reserve(fields.size() + listFields.size()); std::transform(listFields.begin(), listFields.end(), std::inserter(fields, fields.end()), [](const Atom& ident) { return ident.get(); }); } unsigned int Expression::nextVacantId = 0; Expression::Expression(const Atom& number) : Expression() { __state = NUMBER; op = Operator::INVALID; __valueD = number.get(); } Expression::Expression(const Atom& a) : Expression() { __state = STRING; op = Operator::INVALID; __valueS = a.get(); } Expression::Expression(const Atom &ident) : Expression() { __state = IDENT; op = Operator::INVALID; __valueS = ident.get(); } Expression::Expression(const Operator &oprt, std::initializer_list params) : Expression() { __state = COMPOUND; op = oprt; if (op == Operator::CALL) { assert(params.size() > 0); Expression arg = *params.begin(); assert(arg.__state == Expression::IDENT); __valueS = std::move(arg.__valueS); operands.insert(operands.end(), params.begin() + 1, params.end()); return; } operands.insert(operands.end(), params.begin(), params.end()); } void Expression::setOp(Operator oprt) { op = oprt; switch (op) { case Operator::INVALID: __state = INVALID; break; default: __state = COMPOUND; break; } } void Expression::addArg(Expression &&arg) { operands.push_back(arg); } void Expression::addTags(const std::list 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> 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::getOperands() const { return operands; } double Expression::getValueDouble() const { return __valueD; } const std::string& Expression::getValueString() const { return __valueS; } void Expression::setValue(const Atom&& v) { __valueS = v.get(); } void Expression::setValueDouble(double value) { __valueD = value; } bool Expression::isValid() const { return (__state != INVALID); } bool Expression::isDefined() const { return (__state != BINDING && __state != INVALID); } Expression::Expression() : __state(INVALID), op(Operator::INVALID), id(nextVacantId++) { } namespace details { namespace inconsistent { AST::AST() { Attachments::init(); Attachments::init(); Attachments::init(); Attachments::init(); } 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 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 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(range.first->second, &this->__functions); } std::list AST::getAllFunctions() const { const size_t size = __functions.size(); std::list result; for (size_t i = 0; i < size; ++i) { result.push_back(ManagedFnPtr(i, &this->__functions)); } return result; } //TASK select default specializations std::list AST::getFunctionSpecializations(const std::string& fnName) const { auto functions = __indexFunctions.equal_range(fnName); std::list result; std::transform(functions.first, functions.second, inserter(result, result.end()), [this](auto f) { return ManagedFnPtr(f.second, &this->__functions); }); return result; } template<> ManagedPtr AST::begin() { return ManagedPtr(0, &this->__functions); } template<> ManagedPtr AST::begin() { return ManagedPtr(0, &this->__scopes); } template<> ManagedPtr AST::begin() { return ManagedPtr(0, &this->__rules); } void AST::recognizeVariantConstructor(Expression& function) { assert(function.op == Operator::CALL); std::string variant = function.getValueString(); if (!__dictVariants.count(variant)) { return; } auto record = __dictVariants.at(variant); const TypeAnnotation& typ = record.first; function.op = Operator::VARIANT; function.setValueDouble(record.second); function.type = typ; } Atom AST::recognizeVariantConstructor(Atom ident) { std::string variant = ident.get(); assert(__dictVariants.count(variant) && "Can't recognize variant constructor"); auto record = __dictVariants.at(variant); return Atom(record.second); } void AST::postponeIdentifier(CodeScope* scope, const Expression& id) { bucketUnrecognizedIdentifiers.emplace(scope, id); } void AST::recognizePostponedIdentifiers() { for (const auto& identifier : bucketUnrecognizedIdentifiers) { if (!identifier.first->recognizeIdentifier(identifier.second)) { //exception: Ident not found std::cout << "Unknown symbol: " << identifier.second.getValueString() << std::endl; assert(false && "Symbol not found"); } } } xreate::AST* AST::finalize() { //all finalization steps: recognizePostponedIdentifiers(); return reinterpret_cast (this); } } } //namespace details::incomplete Expanded AST::findType(const std::string& name) { // find in general scope: if (__indexTypeAliases.count(name)) return expandType(__indexTypeAliases.at(name)); //if type is unknown keep it as is. TypeAnnotation t(TypeOperator::CUSTOM,{}); t.__valueCustom = name; return ExpandedType(move(t)); } Expanded AST::expandType(const TypeAnnotation &t) const { return TypesResolver(this)(t); } ExpandedType AST::getType(const Expression& expression) { return typeinference::getType(expression, *this); } Function::Function(const Atom& 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& Function::getTags() const { return __tags; } CodeScope* Function::getEntryScope() const { return __entry; } void Function::addBinding(Atom && name, Expression&& argument) { __entry->addBinding(move(name), move(argument)); } const std::string& Function::getName() const { return __name; } ScopedSymbol CodeScope::registerIdentifier(const Expression& identifier) { versions::VariableVersion version = Attachments::get(identifier, versions::VERSION_NONE); auto result = __identifiers.emplace(identifier.getValueString(), __vCounter); if (result.second) { ++__vCounter; return { __vCounter - 1, version }; } return { result.first->second, version }; } bool CodeScope::recognizeIdentifier(const Expression& identifier) const { versions::VariableVersion version = Attachments::get(identifier, versions::VERSION_NONE); const std::string& name = identifier.getValueString(); //search identifier in the current block if (__identifiers.count(name)) { VNameId id = __identifiers.at(name); Symbol s; s.identifier = ScopedSymbol{id, version}; s.scope = const_cast (this); Attachments::put(identifier, s); return true; } //search in the parent scope if (__parent) { return __parent->recognizeIdentifier(identifier); } return false; } ScopedSymbol CodeScope::getSymbol(const std::string& alias) { assert(__identifiers.count(alias)); VNameId id = __identifiers.at(alias); return {id, versions::VERSION_NONE }; } void CodeScope::addBinding(Expression&& var, Expression&& argument) { argument.__state = Expression::BINDING; __bindings.push_back(var.getValueString()); ScopedSymbol binding = registerIdentifier(var); __declarations[binding] = move(argument); } Symbol CodeScope::addDefinition(Expression&& var, Expression&& body) { ScopedSymbol s = registerIdentifier(var); __declarations[s] = move(body); return Symbol{s, this}; } CodeScope::CodeScope(CodeScope* parent) : __parent(parent) { } CodeScope::~CodeScope() { } void CodeScope::setBody(const Expression &body) { assert(__declarations.count(ScopedSymbol::RetSymbol)==0 && "Attempt to reassign scope body"); __declarations[ScopedSymbol::RetSymbol] = body; } const Expression& CodeScope::getBody() const{ return __declarations.at(ScopedSymbol::RetSymbol); } const Expression& CodeScope::getDefinition(const Symbol& symbol, bool flagAllowUndefined){ const CodeScope* self = symbol.scope; return self->getDefinition(symbol.identifier, flagAllowUndefined); } const Expression& CodeScope::getDefinition(const ScopedSymbol& symbol, bool flagAllowUndefined) const{ static Expression expressionInvalid; if (!__declarations.count(symbol)){ if (flagAllowUndefined) return expressionInvalid; assert(false && "Symbol's declaration not found"); } return __declarations.at(symbol); } void RuleArguments::add(const Atom &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&& message) : MetaRuleAbstract(std::move(args), std::move(guards)), __message(message.get()), __condition(condition) { } RuleWarning::~RuleWarning() { } void RuleWarning::compile(TranscendLayer& layer) { //TODO restore addRuleWarning //layer.addRuleWarning(*this); } bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2) { return (s1.id < s2.id) || (s1.id == s2.id && s1.version < s2.version); } bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2) { return (s1.id == s2.id) && (s1.version == s2.version); } bool operator<(const Symbol& s1, const Symbol& s2) { return (s1.scope < s2.scope) || (s1.scope == s2.scope && s1.identifier < s2.identifier); } bool operator==(const Symbol& s1, const Symbol& s2) { return (s1.scope == s2.scope) && (s1.identifier == s2.identifier); } bool operator<(const Expression&a, const Expression&b) { if (a.__state != b.__state) return a.__state < b.__state; assert(a.__state != Expression::INVALID); switch (a.__state) { case Expression::IDENT: case Expression::STRING: return a.getValueString() < b.getValueString(); case Expression::NUMBER: return a.getValueDouble() < b.getValueDouble(); case Expression::COMPOUND: { assert(a.blocks.size() == 0); assert(b.blocks.size() == 0); if (a.op != b.op) { return a.op < b.op; } bool flagAValid = ExpressionHints::isStringValueValid(a); bool flagBValid = ExpressionHints::isStringValueValid(b); if (flagAValid != flagBValid) { return flagAValid < flagBValid; } if (flagAValid) { if (a.getValueString() != b.getValueString()) { return a.getValueString() < b.getValueString(); } } flagAValid = ExpressionHints::isDoubleValueValid(a); flagBValid = ExpressionHints::isDoubleValueValid(b); if (flagAValid != flagBValid) { return flagAValid < flagBValid; } if (flagAValid) { if (a.getValueDouble() != b.getValueDouble()) { return a.getValueDouble() < b.getValueDouble(); } } if (a.operands.size() != b.operands.size()) { return (a.operands.size() < b.operands.size()); } for (size_t i = 0; i < a.operands.size(); ++i) { bool result = a.operands[i] < b.operands[i]; if (result) return true; } return false; } case Expression::BINDING: case Expression::INVALID: assert(false); } return false; } bool Expression::operator==(const Expression& other) const { if (this->__state != other.__state) return false; if (ExpressionHints::isStringValueValid(*this)) { if (this->__valueS != other.__valueS) return false; } if (ExpressionHints::isDoubleValueValid(*this)) { if (this->__valueD != other.__valueD) return false; } if (this->__state != Expression::COMPOUND) { return true; } if (this->op != other.op) { return false; } if (this->operands.size() != other.operands.size()) { return false; } for (size_t i = 0; ioperands.size(); ++i) { if (!(this->operands[i] == other.operands[i])) return false; } assert(!this->blocks.size()); assert(!other.blocks.size()); return true; } const ScopedSymbol ScopedSymbol::RetSymbol = ScopedSymbol{0, versions::VERSION_NONE}; } //end of namespace xreate diff --git a/cpp/src/ast.h b/cpp/src/ast.h index e37d755..7052451 100644 --- a/cpp/src/ast.h +++ b/cpp/src/ast.h @@ -1,741 +1,741 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * File: ast.h */ #ifndef AST_H #define AST_H #include "attachments.h" #include #include #include #include #include #include #include #include "utils.h" #include namespace llvm { class Value; } namespace xreate { struct ScopedSymbol; struct Symbol; } namespace std { template<> struct hash { std::size_t operator()(xreate::ScopedSymbol const& s) const; }; template<> struct equal_to { bool operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const; }; template<> struct hash { size_t operator()(xreate::Symbol const& s) const; }; template<> struct equal_to { bool operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const; }; } namespace xreate { struct String_t { }; struct Identifier_t { }; struct Number_t { }; struct Type_t { }; template class Atom { }; //DEBT store line:col for all atoms/identifiers template<> class Atom { public: Atom(const std::wstring& value); Atom(std::string && name); const std::string& get() const; private: std::string __value; }; template<> class Atom { public: Atom(wchar_t* value); Atom(int value); double get()const; private: double __value; }; template<> class Atom { public: Atom(const std::wstring& value); Atom(std::string && name); const std::string& get() const; private: std::string __value; }; enum class TypePrimitive { Invalid, Bool, I8, I32, I64, Num, Int, Float, String }; enum class TypeOperator { - NONE, CALL, CUSTOM, VARIANT, LIST, LIST_NAMED, ACCESS, LINK + NONE, CALL, CUSTOM, VARIANT, LIST, LIST_NAMED, ACCESS, LINK, SLAVE }; struct llvm_array_tag { }; struct struct_tag { }; const llvm_array_tag tag_array = llvm_array_tag(); const struct_tag tag_struct = struct_tag(); /** * \brief Represents type to support type system * * This class represents type in denormalized form, i.e. without arguments and aliases substitution * \sa AST::expandType() */ class TypeAnnotation { public: TypeAnnotation(); TypeAnnotation(const Atom& typ); TypeAnnotation(TypePrimitive typ); TypeAnnotation(llvm_array_tag, TypeAnnotation typ, int size); TypeAnnotation(TypeOperator op, std::initializer_list operands); TypeAnnotation(TypeOperator op, std::vector&& operands); void addBindings(std::vector>&& params); void addFields(std::vector>&& listFields); bool operator<(const TypeAnnotation& t) const; // TypeAnnotation (struct_tag, std::initializer_list); bool isValid() const; TypeOperator __operator = TypeOperator::NONE; std::vector __operands; TypePrimitive __value; std::string __valueCustom; int conjuctionId = -1; //conjunction point id (relevant for recursive types) uint64_t __size = 0; std::vector fields; std::vector bindings; private: }; enum class Operator { INVALID, UNDEF, ADD, SUB, MUL, DIV, EQU, NE, NEG, LSS, LSE, GTR, GTE, LIST, LIST_RANGE, LIST_NAMED, CALL, CALL_INTRINSIC, IMPL/* implication */, MAP, FOLD, FOLD_INF, INDEX, IF, SWITCH, SWITCH_VARIANT, SWITCH_LATE, CASE, CASE_DEFAULT, LOGIC_AND, CONTEXT_RULE, VARIANT, SEQUENCE }; class Function; class AST; class CodeScope; class MetaRuleAbstract; typedef ManagedPtr ManagedFnPtr; typedef ManagedPtr ManagedScpPtr; typedef ManagedPtr ManagedRulePtr; const ManagedScpPtr NO_SCOPE = ManagedScpPtr(UINT_MAX, 0); /** * \brief Represents every instruction in Xreate's syntax tree * \attention In case of any changes update xreate::ExpressionHints auxiliary helper as well * * Expression is generic building block of syntax tree able to hold node data * as well as child nodes as operands. Not only instructions use expression for representation in syntax tree * but annotation as well. * * Additionally, `types` as a special kind of annotations use Expression-like data structure TypeAnnotation * \sa xreate::AST, xreate::TypeAnnotation */ // struct Expression { friend class CodeScope; friend class TranscendLayer; friend class CFAPass; friend class ExpressionHints; Expression(const Operator &oprt, std::initializer_list params); Expression(const Atom& ident); Expression(const Atom& number); Expression(const Atom& a); Expression(); void setOp(Operator oprt); void addArg(Expression&& arg); void addBindings(std::initializer_list> params); void bindType(TypeAnnotation t); template void addBindings(InputIt paramsBegin, InputIt paramsEnd); void addTags(const std::list tags) const; void addBlock(ManagedScpPtr scope); const std::vector& getOperands() const; double getValueDouble() const; void setValueDouble(double value); const std::string& getValueString() const; void setValue(const Atom&& v); bool isValid() const; bool isDefined() const; bool operator==(const Expression& other) const; /** * \brief is it string, number, compound operation and so on */ enum { INVALID, COMPOUND, IDENT, NUMBER, STRING, BINDING } __state = INVALID; /** * \brief Valid for compound State. Holds type of compound operator */ Operator op; /** * \brief Unique id to identify expression within syntax tree */ unsigned int id; /** * \brief Exact meaning depends on particular instruction * \details As an example, named lists/structs hold field names in bindings */ std::vector bindings; std::map __indexBindings; /** * \brief Holds child instructions as arguments */ std::vector operands; /** * \brief Holds type of instruction's result */ TypeAnnotation type; /** * \brief Holds additional annotations */ mutable std::map tags; /** * \brief Child code blocks * \details For example, If statement holds TRUE-branch as first and FALSE-branch as second block here */ std::list blocks; private: std::string __valueS; double __valueD; static unsigned int nextVacantId; }; bool operator<(const Expression&, const Expression&); template 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 atom) { std::string key = atom.get(); this->__indexBindings[key] = index++; return key; }); } typedef std::list ExpressionList; enum class TagModifier { NONE, ASSERT, REQUIRE }; enum class DomainAnnotation { FUNCTION, VARIABLE }; class RuleArguments : public std::vector> { public: void add(const Atom& name, DomainAnnotation typ); }; class RuleGuards : public std::vector { public: void add(Expression&& e); }; class TranscendLayer; class LLVMLayer; class MetaRuleAbstract { public: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards); virtual ~MetaRuleAbstract(); virtual void compile(TranscendLayer& layer) = 0; protected: RuleArguments __args; RuleGuards __guards; }; class RuleWarning : public MetaRuleAbstract { friend class TranscendLayer; public: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message); virtual void compile(TranscendLayer& layer); ~RuleWarning(); private: std::string __message; Expression __condition; }; typedef unsigned int VNameId; namespace versions { typedef int VariableVersion; const VariableVersion VERSION_NONE = -2; const VariableVersion VERSION_INIT = 0; } template<> struct AttachmentsDict { typedef versions::VariableVersion Data; static const unsigned int key = 6; }; struct ScopedSymbol { VNameId id; versions::VariableVersion version; static const ScopedSymbol RetSymbol; }; struct Symbol { ScopedSymbol identifier; const CodeScope * scope; }; struct IdentifierSymbol{}; struct SymbolAlias{}; template<> struct AttachmentsDict { typedef Symbol Data; static const unsigned int key = 7; }; template<> struct AttachmentsDict { typedef Symbol Data; static const unsigned int key = 9; }; typedef std::pair Tag; bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2); bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2); bool operator<(const Symbol& s1, const Symbol& s2); bool operator==(const Symbol& s1, const Symbol& s2); /** * \brief Represents code block and single scope of visibility * * Holds single expression as a *body* and set of variable assignments(declarations) used in body's expression * \sa xreate::AST */ class CodeScope { friend class Function; friend class PassManager; public: CodeScope(CodeScope* parent = 0); ~CodeScope(); /** \brief Set expression as a body */ void setBody(const Expression& body); /** \brief Returns current code scope body */ const Expression& getBody() const; /** \brief Adds variable definition to be used in body as well as in other declarations */ Symbol addDefinition(Expression&& var, Expression&& body); /** \brief Returns symbols' definition */ static const Expression& getDefinition(const Symbol& symbol, bool flagAllowUndefined = false); const Expression& getDefinition(const ScopedSymbol& symbol, bool flagAllowUndefined = false) const; /** \brief Adds variable defined elsewhere */ void addBinding(Expression&& var, Expression&& argument); std::vector __bindings; std::map __identifiers; CodeScope* __parent; //TODO move __definitions to SymbolsAttachments data //NOTE: definition of return type has index 0 std::unordered_map __declarations; std::vector tags; std::vector contextRules; private: VNameId __vCounter = 1; ScopedSymbol registerIdentifier(const Expression& identifier); public: bool recognizeIdentifier(const Expression& identifier) const; ScopedSymbol getSymbol(const std::string& alias); }; /** * \brief Represents single function in Xreate's syntax tree * * Holds an entry code scope and `guardContext` required for function to operate * \sa xreate::AST */ class Function { friend class Expression; friend class CodeScope; friend class AST; public: Function(const Atom& name); /** * \brief Adds function arguments */ void addBinding(Atom && name, Expression&& argument); /** * \brief Adds additional function annotations */ void addTag(Expression&& tag, const TagModifier mod); const std::string& getName() const; const std::map& getTags() const; CodeScope* getEntryScope() const; CodeScope* __entry; std::string __name; bool isPrefunction = false; //SECTIONTAG adhoc Function::isPrefunction flag Expression guard; private: std::map __tags; }; class ExternData; struct ExternEntry { std::string package; std::vector headers; }; typedef Expanded ExpandedType; struct TypeInferred{}; template<> struct AttachmentsDict { typedef ExpandedType Data; static const unsigned int key = 11; }; enum ASTInterface { CFA, DFA, Extern, Adhoc }; struct FunctionSpecialization { std::string guard; size_t id; }; struct FunctionSpecializationQuery { std::unordered_set context; }; template<> struct AttachmentsId{ static unsigned int getId(const Expression& expression){ return expression.id; } }; template<> struct AttachmentsId{ static unsigned int getId(const Symbol& s){ return s.scope->__declarations.at(s.identifier).id; } }; template<> struct AttachmentsId{ static unsigned int getId(const ManagedFnPtr& f){ const Symbol symbolFunction{ScopedSymbol::RetSymbol, f->getEntryScope()}; return AttachmentsId::getId(symbolFunction); } }; template<> struct AttachmentsId{ static unsigned int getId(const CodeScope* scope){ const Symbol symbolScope{ScopedSymbol::RetSymbol, scope}; return AttachmentsId::getId(symbolScope); } }; template<> struct AttachmentsId{ static unsigned int getId(const unsigned int id){ return id; } }; class TypesResolver; namespace details { namespace inconsistent { /** * \brief Syntax tree under construction in inconsistent form * * Represents Syntax Tree under construction(**inconsistent state**). * \attention Clients should use rather xreate::AST unless client's code explicitly works with Syntax Tree during construction. * * Typically instance only created by xreate::XreateManager and filled in by Parser * \sa xreate::XreateManager::prepare(std::string&&) */ class AST { friend class xreate::TypesResolver; public: AST(); /** * \brief Adds new function to AST * \param f Function to register */ void add(Function* f); /** * \brief Adds new declarative rule to AST * \param r Declarative Rule */ void add(MetaRuleAbstract* r); /** \brief Registers new code block */ ManagedScpPtr add(CodeScope* scope); /** * \brief Add new type to AST * @param t Type definition * @param alias Typer name */ void add(TypeAnnotation t, Atom alias); /** \brief Current module's name */ std::string getModuleName(); /** * \brief Looks for function with given name * \param name Function name to find * \note Requires that only one function exists under given name * \return Found function */ ManagedPtr findFunction(const std::string& name); /** \brief Returns all function in AST */ std::list getAllFunctions() const; /** * \brief Returns all specializations of a function with a given name * \param fnName function to find * \return list of found function specializations */ std::list getFunctionSpecializations(const std::string& fnName) const; /** * \return First element in Functions/Scopes/Rules list depending on template parameter * \tparam Target either Function or CodeScope or MetaRuleAbstract */ template ManagedPtr begin(); /** * \brief Performs all necessary steps after AST is built * * Performs all finzalisation steps and move AST into consistent state represented by xreate::AST * \sa xreate::AST * \return AST in consistent state */ xreate::AST* finalize(); typedef std::multimap FUNCTIONS_REGISTRY; std::vector __externdata; std::list __dfadata; //TODO move to more appropriate place std::list __rawImports; //TODO move to more appropriate place std::multimap __interfacesData; //TODO CFA data here. private: std::vector __rules; std::vector __functions; std::vector __scopes; FUNCTIONS_REGISTRY __indexFunctions; protected: std::map __indexTypeAliases; public: /** * \brief Stores DFA scheme for later use by DFA Pass * * Treats expression as a DFA scheme and feeds to a DFA Pass later * \paramn Expression DFA Scheme * \sa xreate::DFAPass */ void addDFAData(Expression&& data); /** \brief Stores data for later use by xreate::ExternLayer */ void addExternData(ExternData&& data); /** * \brief Generalized function to store particular data for later use by particular pass * \param interface Particular Interface * \param data Particular data */ void addInterfaceData(const ASTInterface& interface, Expression&& data); /**\name Symbols Recognition */ ///@{ public: //TODO revisit enums/variants, move to codescope /** * \brief Tries to find out whether expression is Variant constructor */ void recognizeVariantConstructor(Expression& function); Atom recognizeVariantConstructor(Atom ident); private: std::map> __dictVariants; public: std::set> bucketUnrecognizedIdentifiers; public: /** * \brief Postpones unrecognized identifier for future second round of recognition * \param scope Code block identifier is encountered * \param id Identifier */ void postponeIdentifier(CodeScope* scope, const Expression& id); /** \brief Second round of identifiers recognition done right after AST is fully constructed */ void recognizePostponedIdentifiers(); ///@} }; template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); } } // namespace details::incomplete /** * \brief Xreate's Syntax Tree in consistent state * * Syntax Tree has two mutually exclusive possible states: * - inconsistent state while AST is under construction. Represented by xreate::details::inconsistent::AST * - consistent state when AST is built and finalize() is done. * * This class represents consistent state and should be used everywhere unless client's code explicitly works with AST under construction. * Consistent AST enables access to additional functions(currently related to type management). * \sa xreate::details::inconsistent::AST */ class AST : public details::inconsistent::AST { public: AST() : details::inconsistent::AST() {} /** * \brief Computes fully expanded form of type by substituting all arguments and aliases * \param t Type to expand * \return Expdanded or normal form of type * \sa TypeAnnotation */ ExpandedType expandType(const TypeAnnotation &t) const; /** * Searches type by given name * \param name Typename to search * \return Expanded or normal form of desired type * \note if type name is not found returns new undefined type with this name */ ExpandedType findType(const std::string& name); /** * Invokes Type Inference Analysis to find out expanded(normal) form expressions's type * \sa typeinference.h * \param expression * \return Type of expression */ ExpandedType getType(const Expression& expression); }; } #endif // AST_H diff --git a/cpp/src/attachments.h b/cpp/src/attachments.h index 643f718..3b82d43 100644 --- a/cpp/src/attachments.h +++ b/cpp/src/attachments.h @@ -1,180 +1,202 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * File: attachments.h * Date: 3/15/15 */ #ifndef _XREATE_ATTACHMENTS_H_ #define _XREATE_ATTACHMENTS_H_ #include #include #include #include namespace xreate { //Attachments dictionary template struct AttachmentsDict { // typedef void Data; // static const unsigned int key (next vacant id - 13); // Defined attachments: //----------------------------------------------------- // 1 containers::Implementation // 3 interpretation::InterpretationData // 5 interpretation::FunctionInterpretationData // 6 VariableVersion // 7 IdentifierSymbol // 8 versions::VersionImposedDependency // 9 SymbolAlias // 11 TypeInferred -// 12 LateBinding +// 12 LateBindingT }; template struct AttachmentsId{ //static unsigned int getId(const Object& object); }; template class IAttachmentsContainer{ protected: virtual bool __exists(const unsigned int object)=0; virtual Data& __get(const unsigned int object)=0; virtual void __put(const unsigned int object, Data data)=0; + virtual void __update(const unsigned int object, Data data)=0; public: template bool exists(const Id& object){ unsigned int id = AttachmentsId::getId(object); return __exists(id); } template Data& get(const Id& object){ unsigned int id = AttachmentsId::getId(object); return __get(id); } template Data get(const Id& object, const Data& dataDefault){ unsigned int id = AttachmentsId::getId(object); if (! __exists(id)){ return dataDefault; } return __get(id); } template void put(const Id& object, Data data){ unsigned int id = AttachmentsId::getId(object); __put(id, data); } + + template + void update(const Id& object, Data data){ + unsigned int id = AttachmentsId::getId(object); + + __update(id, data); + } virtual ~IAttachmentsContainer(){}; }; template class AttachmentsContainerDefault: public IAttachmentsContainer{ private: std::unordered_map __data; virtual bool __exists(const unsigned int id){ return __data.count(id); } virtual Data& __get(const unsigned int id){ return __data.at(id); } virtual void __put(const unsigned int id, Data data){ auto result = __data.emplace(id, data); assert(result.second); } + virtual void __update(const unsigned int id, Data data){ + assert(__data.count(id)); + __data.at(id) = data; + } + public: std::unordered_map& getRawStorage() { return __data; } }; class Attachments{ private: static std::vector __storage; template using Data = typename AttachmentsDict::Data; public: template static bool exists(const Id& object) { assert(AttachmentsDict::key < __storage.size()); assert(__storage.at(AttachmentsDict::key)); IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); return self->exists(object); } template static Data& get(const Id& object){ assert(AttachmentsDict::key < __storage.size()); assert(__storage.at(AttachmentsDict::key)); IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); return self->get(object); } template static Data get(const Id& object, const Data& dataDefault){ assert(AttachmentsDict::key < __storage.size()); assert(__storage.at(AttachmentsDict::key)); IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); return self->get(object, dataDefault); } template static void put(const Id& object, Data data){ assert(AttachmentsDict::key < __storage.size()); assert(__storage.at(AttachmentsDict::key)); IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); self->put(object, data); } + + template + static void update(const Id& object, Data data){ + assert(AttachmentsDict::key < __storage.size()); + assert(__storage.at(AttachmentsDict::key)); + + IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); + self->update(object, data); + } template static void init(){ unsigned int keyStorage = AttachmentsDict::key; if (keyStorage+1 > __storage.size()){ __storage.resize(keyStorage + 1, nullptr); } __storage[keyStorage] = new AttachmentsContainerDefault>(); } template static void init(IAttachmentsContainer>* container){ unsigned int keyStorage = AttachmentsDict::key; if (keyStorage+1 > __storage.size()){ __storage.resize(keyStorage + 1, nullptr); } __storage[keyStorage] = container; } }; } #endif //_XREATE_ATTACHMENTS_H_ diff --git a/cpp/src/aux/latereasoning.cpp b/cpp/src/aux/latereasoning.cpp new file mode 100644 index 0000000..8dc3366 --- /dev/null +++ b/cpp/src/aux/latereasoning.cpp @@ -0,0 +1,40 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: pgess + * Created on June 7, 2018, 6:01 PM + * + * \file latereasoning.cpp + * \brief Late reasoninf support + */ + +#include "aux/latereasoning.h" +#include "ast.h" + +namespace xreate {namespace latereasoning { + +boost::optional +LateAnnotation::select(const std::list& keys) const { + for(const auto& entry : guardedSymbols) { + const std::list& keysExpected = entry.first; + + auto keysIt = keys.begin(); + bool result = true; + for(const Expression& keyExpected : keysExpected) { + if(!(keyExpected == *keysIt)) { + result = false; + break; + } + ++keysIt; + } + if(!result) continue; + return entry.second; + } + + return boost::none; +} + +}} + diff --git a/cpp/src/aux/latereasoning.h b/cpp/src/aux/latereasoning.h new file mode 100644 index 0000000..5eb2f21 --- /dev/null +++ b/cpp/src/aux/latereasoning.h @@ -0,0 +1,113 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \file latereasoning.h + * \brief Late reasoning support + * + * Author: pgess + * + * Created on June 2, 2018, 1:08 PM + */ + +#ifndef LATEREASONING_H +#define LATEREASONING_H + +#include "transcendlayer.h" + +namespace xreate { + struct LateBindingT; + + template<> + struct AttachmentsDict{ + typedef Expression Data; + static const unsigned int key = 12; + }; +} + +namespace xreate{ namespace latereasoning{ + +struct LateAnnotation{ + std::list, Gringo::Symbol>> guardedSymbols; + boost::optional select(const std::list& keys) const; +}; + +struct LateAnnotationsGroup{ + std::unordered_map annotations; + std::unordered_map> bindings; +}; + +//DEBT implement querying as a view/joining iterators without actual data copying +//DEBT how to implement late model RESET(invalidate all child models) +template +class LateReasoningTranscendDecorator: public Parent{ +public: + StaticModel queryLate(const std::string& alias, const SymbolNode& symbol) const{ + StaticModel result; + if(!__modelLate.count(alias)) return StaticModel(); + + const LateAnnotationsGroup& group = __modelLate.at(alias); + assert(group.bindings.count(symbol)); + const std::list& bindings = group.bindings.at(symbol); + std::list&& keys = findKeys(bindings); + + const LateAnnotation& annLate = group.annotations.at(symbol); + auto ann = annLate.select(keys); + if(ann){ + result.emplace(std::make_pair(alias, *ann)); + } + + return result; + } + +protected: + virtual bool processSolution(Gringo::Model const &model) override{ + const std::string& atomLateStatement = "late"; + + for(const Gringo::Symbol& atom: model.atoms(clingo_show_type_atoms)){ + std::string atomName(atom.name().c_str()); + + SymbolPacked aaaa; + if(atomName == atomLateStatement){ + //late atom's format: (Symbol, (tuple of keys), (tuple of values), late-annotation) + auto atomLate = TranscendLayer::parse, std::list, Gringo::Symbol>(atom); + const std::string& atomAlias = std::get<3>(atomLate).name().c_str(); + addLateAtom(atomAlias, std::get<0>(atomLate), + std::get<3>(atomLate), std::get<1>(atomLate), + std::get<2>(atomLate)); + } + } + + return Parent::processSolution(model); + } + +private: + std::map __modelLate; + + void addLateAtom(const std::string& alias, const SymbolNode& symbol, + const Gringo::Symbol& atom, const std::list& guardKeys, + const std::list& guardBindings){ + LateAnnotationsGroup& group = __modelLate[alias]; + if(!group.bindings.count(symbol)){ + group.bindings.emplace(symbol, guardKeys); + } + + LateAnnotation& annotation = group.annotations[symbol]; + annotation.guardedSymbols.push_back(std::make_pair(guardBindings, atom)); + } + + std::list findKeys(const std::list& keys) const{ + std::list result; + std::transform(keys.begin(), keys.end(), std::inserter(result, result.end()), [this](const SymbolPacked & key){ + return Attachments::get(Parent::unpack(key)); + }); + + return result; + } +}; + +}} // end of xreate::latereasoning + +#endif /* LATEREASONING_H */ + diff --git a/cpp/src/aux/transcend-decorators.h b/cpp/src/aux/transcend-decorators.h new file mode 100644 index 0000000..77a04d6 --- /dev/null +++ b/cpp/src/aux/transcend-decorators.h @@ -0,0 +1,27 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* + * Author: pgess + * Created on June 7, 2018, 6:47 PM + * + * \file transcend-decorators.h + * \brief TranscendLevel decorators management + */ + +#include "transcendlayer.h" +#include "aux/latereasoning.h" + +#ifndef TRANSCEND_DECORATORS_H +#define TRANSCEND_DECORATORS_H + +namespace xreate { + typedef latereasoning::LateReasoningTranscendDecorator + DefaultTranscendLayerImpl; +} + +#endif /* TRANSCEND_DECORATORS_H */ + diff --git a/cpp/src/aux/xreatemanager-decorators.cpp b/cpp/src/aux/xreatemanager-decorators.cpp index 3e40b1a..2b3a9ba 100644 --- a/cpp/src/aux/xreatemanager-decorators.cpp +++ b/cpp/src/aux/xreatemanager-decorators.cpp @@ -1,73 +1,72 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * xreatemanager-decorators.cpp * * Author: pgess * Created on July 16, 2017, 4:40 PM */ /** * \file xreatemanager-decorators.h * \brief \ref xreate::XreateManager decorators to provide various functionality */ #include "aux/xreatemanager-decorators.h" #include "main/Parser.h" #include "pass/compilepass.h" #include "pass/cfapass.h" #include "pass/dfapass.h" #include "pass/interpretationpass.h" #include "pass/versionspass.h" - namespace xreate { void XreateManagerDecoratorBase::prepareCode(std::string&& code){ grammar::main::Scanner scanner(reinterpret_cast(code.c_str()), code.size()); grammar::main::Parser parser(&scanner); parser.Parse(); assert(!parser.errors->count && "Parser errors"); PassManager::prepare(parser.root->finalize()); } void XreateManagerDecoratorBase::prepareCode(FILE* code){ grammar::main::Scanner scanner(code); grammar::main::Parser parser(&scanner); parser.Parse(); assert(!parser.errors->count && "Parser errors"); PassManager::prepare(parser.root->finalize()); } void XreateManagerDecoratorBase::analyse(){ CompilePass::prepareQueries(transcend); transcend->run(); } void XreateManagerDecoratorFull::initPasses(){ cfa::CFAPass* passCFG = new cfa::CFAPass(this); //TODO is it really DFGPass needs CFGpass? - registerPass(new dfa::DFAPass(this), PassId::DFGPass, passCFG); - registerPass(passCFG, PassId::CFGPass); + registerPass(new dfa::DFAPass(this), PassId::DFAPass, passCFG); + registerPass(passCFG, PassId::CFAPass); this->registerPass(new interpretation::InterpretationPass(this), PassId::InterpretationPass); this->registerPass(new versions::VersionsPass(this), PassId::VersionsPass); } void* XreateManagerDecoratorFull::run() { std::unique_ptr compiler(new compilation::CompilePassCustomDecorators<>(this)); compiler->run(); llvm->print(); llvm->initJit(); return llvm->getFunctionPointer(compiler->getEntryFunction()); } } //namespace xreate diff --git a/cpp/src/compilation/latereasoning.cpp b/cpp/src/compilation/latereasoning.cpp index 496a97c..97a7eb6 100644 --- a/cpp/src/compilation/latereasoning.cpp +++ b/cpp/src/compilation/latereasoning.cpp @@ -1,53 +1,79 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * latereasoning.cpp * * Author: pgess * 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 : hintRetVar) -// -// LLVMLayer* llvm = context.pass->man->llvm; -// compilation::ICodeScopeUnit* scope = context.scope; -// AST* root = context.pass->man->root; -// llvm::IRBuilder<>& builder = llvm->builder; -// -// const ExpandedType& typCondition = root->getType(expr.operands.at(0)); -// const int countVariants = typCondition->fields.size(); -// -// llvm::Value * conditionRaw = scope->process(expr.operands.at(0)); -// llvm::Value* variantRaw = builder.CreateExtractValue(conditionRaw, llvm::ArrayRef({0})); -// llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(variantRaw, nullptr, countVariants); -// //llvm::BasicBlock* blockProlog = builder.GetInsertBlock(); -// -// llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "switchLateAfter", function->raw); -// builder.SetInsertPoint(blockEpilog); -// llvm::Type* exprSwitchType = llvm->toLLVMType(root->getType(expr)); -// llvm::PHINode *ret = builder.CreatePHI(exprSwitchType, countVariants, HINT("switchLate")); -// //builder.SetInsertPoint(blockProlog); -// -// for (int variantId = 0; variantIdraw); -// builder.SetInsertPoint(blockCase); -// CodeScope scopeBody = function->getScopeUnit(exp.blocks.back()); -// scopeBody->reset(); -// -// llvm::Value* resultCase = scopeBody->compile(); -// ret->addIncoming(resultCase, builder.GetInsertBlock()); -// instructionSwitch->addCase(dyn_cast(llvm::ConstantInt::get(typI8, variantId), blockCase); -// -// builder.CreateBr(blockEpilog); -// } + #define HINT(x) (identHint.empty()? x : identHint) + + LLVMLayer* llvm = context.pass->man->llvm; + compilation::ICodeScopeUnit* scope = context.scope; + AST* root = context.pass->man->root; + llvm::IRBuilder<>& builder = llvm->builder; + compilation::IFunctionUnit* function = context.function; + llvm::Type* typI8= llvm::Type::getInt8Ty(llvm->llvmContext); + CodeScope* scopeBody = expr.blocks.front(); + Symbol guardS = Symbol{scopeBody->getSymbol(expr.bindings.front()), scopeBody}; + + const ExpandedType& typCondition = root->getType(expr.operands.at(0)); + vector guardVariants = typeinference::getSlaveVariants(typCondition, context.pass->man->transcend); + const int countVariants = guardVariants.size(); + assert(countVariants); + + llvm::Value * conditionRaw = scope->process(expr.operands.at(0)); + llvm::Value* variantRaw = builder.CreateExtractValue(conditionRaw, llvm::ArrayRef({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)); + 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/latereasoning.h b/cpp/src/compilation/latereasoning.h index 8a7be74..84adc4f 100644 --- a/cpp/src/compilation/latereasoning.h +++ b/cpp/src/compilation/latereasoning.h @@ -1,33 +1,33 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: latereasoning.h * Author: pgess * * Created on May 26, 2018, 3:44 PM */ -#ifndef LATEREASONING_H -#define LATEREASONING_H +#ifndef CMPLLATEREASONING_H +#define CMPLLATEREASONING_H #include "ast.h" #include "pass/compilepass.h" #include "llvmlayer.h" namespace xreate{ namespace latereasoning { class LateReasoningCompiler { public: LateReasoningCompiler(compilation::Context ctx): context(ctx){} llvm::Value* compile(const Expression& expr, const std::string& identHint); private: compilation::Context context; }; }} -#endif /* LATEREASONING_H */ +#endif /* CMPLLATEREASONING_H */ diff --git a/cpp/src/compilation/targetinterpretation.h b/cpp/src/compilation/targetinterpretation.h index 377993e..7634199 100644 --- a/cpp/src/compilation/targetinterpretation.h +++ b/cpp/src/compilation/targetinterpretation.h @@ -1,139 +1,132 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: targetstatic.h * Author: pgess * * 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 */ - - -//transformers: -// template<> -// struct TransformerInfo { -// static const int id = 1; -// }; +#endif /* TARGETSTATIC_H */ \ No newline at end of file diff --git a/cpp/src/pass/abstractpass.h b/cpp/src/pass/abstractpass.h index d09f83b..9c8648b 100644 --- a/cpp/src/pass/abstractpass.h +++ b/cpp/src/pass/abstractpass.h @@ -1,207 +1,206 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess */ #ifndef ABSTRACTPASS_H #define ABSTRACTPASS_H #include "ast.h" #include "xreatemanager.h" #include namespace xreate { /** \brief Holds current position in %AST while traversing*/ struct PassContext { const CodeScope* scope = 0; ManagedFnPtr function; ManagedRulePtr rule; std::string varDecl; PassContext() {} PassContext updateScope(const CodeScope* scopeNew) { PassContext context2{*this}; context2.scope = scopeNew; return context2; } ~PassContext(){} }; /** \brief Base class for all passes to inherit */ class IPass { public: IPass(PassManager* manager); virtual ~IPass(){} /** \brief Executes pass */ virtual void run()=0; /** \brief Finalizes pass. Empty by default*/ virtual void finish(); PassManager* man; }; template Output defaultValue(); template<> void defaultValue(); /** \brief Stores processing results for already visited nodes */ template class SymbolCache: private std::map{ public: bool isCached(const Symbol& symbol){ return this->count(symbol); } Output setCachedValue(const Symbol& symbol, Output&& value){ (*this)[symbol] = value; return value; } Output getCachedValue(const Symbol& symbol){ assert(this->count(symbol)); return this->at(symbol); } }; /** \brief Set of already visited nodes */ template<> class SymbolCache: private std::set{ public: bool isCached(const Symbol& symbol){ bool result = this->count(symbol) > 0; return result; } void setCachedValue(const Symbol& symbol){ this->insert(symbol); } void getCachedValue(const Symbol& symbol){ } }; /** \brief Minimal useful IPass implementation*/ template class AbstractPass: public IPass { SymbolCache __visitedSymbols; protected: virtual Output processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol=""){ if (__visitedSymbols.isCached(symbol)) return __visitedSymbols.getCachedValue(symbol); - const Expression& declaration = CodeScope::getDefinition(symbol, true); if (declaration.isDefined()){ PassContext context2 = context.updateScope(symbol.scope); Output&& result = process(declaration, context2, hintSymbol); return __visitedSymbols.setCachedValue(symbol, std::move(result)); } return defaultValue(); } Output processExpressionCall(const Expression& expression, PassContext context){ const std::string &calleeName = expression.getValueString(); std::list callees = man->root->getFunctionSpecializations(calleeName); if (callees.size() == 1 && callees.front()){ return processFnCall(callees.front(), context); } else { for (const ManagedFnPtr& callee: callees){ processFnCallUncertain(callee, context); } return defaultValue(); } } SymbolCache& getSymbolCache(){ return __visitedSymbols; } public: AbstractPass(PassManager* manager) : IPass(manager){} /** \brief Processes function invocation instruction */ virtual Output processFnCall(ManagedFnPtr functionCallee, PassContext context){ return defaultValue(); } /** \brief Processes function invocation instruction in uncertain cases * \details Executed when it's impossible statically determine exact function invocation. * In this case get executed for all possible candidates */ virtual void processFnCallUncertain(ManagedFnPtr functionCallee, PassContext context) {} /** \brief Processes Logic Rule */ virtual void process(ManagedRulePtr rule) {} /** \brief Processes Function */ virtual Output process(ManagedFnPtr function) { PassContext context; context.function = function; return process(function->getEntryScope(), context); } /** \brief Processes single CodeScope */ virtual Output process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl=""){ context.scope = scope; return processSymbol(Symbol{ScopedSymbol::RetSymbol, scope}, context); } //TODO expose Symbol instead of varDecl. Required by DFAPass. /** \brief Processes single Expression */ virtual Output process(const Expression& expression, PassContext context, const std::string& varDecl=""){ if (expression.__state == Expression::IDENT){ assert(context.scope); return processSymbol(Attachments::get(expression), context, expression.getValueString()); } assert(false); return defaultValue(); } /** \brief Executes AST traverse */ void run() { ManagedRulePtr rule = man->root->begin(); while (rule.isValid()) { process(rule); ++rule; } ManagedFnPtr f = man->root->begin(); while (f.isValid()) { process(f); ++f; } } }; template<> void AbstractPass::processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol); template<> void AbstractPass::process(const Expression& expression, PassContext context, const std::string& hintSymbol); } #endif diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp index f39e74c..21d3234 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,716 +1,720 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * * compilepass.cpp */ /** * \file compilepass.h * \brief Compilation pass */ #include "compilepass.h" #include "transcendlayer.h" #include #include "llvmlayer.h" #include "query/containers.h" #include "compilation/containers.h" #include "ExternLayer.h" #include "compilation/targetinterpretation.h" #include "pass/versionspass.h" #include "compilation/scopedecorators.h" #include "compilation/operators.h" +#include "aux/latereasoning.h" #include "compilation/latereasoning.h" #include "analysis/typeinference.h" - #include #include #include using namespace std; using namespace llvm; namespace xreate { namespace compilation{ std::string BasicFunctionUnit::prepareName(){ AST* ast = IFunctionUnit::pass->man->root; string name = ast->getFunctionSpecializations(IFunctionUnit::function->__name).size() > 1 ? IFunctionUnit::function->__name + std::to_string(IFunctionUnit::function.id()) : IFunctionUnit::function->__name; return name; } std::vector BasicFunctionUnit::prepareArguments() { LLVMLayer* llvm = IFunctionUnit::pass->man->llvm; AST* ast = IFunctionUnit::pass->man->root; CodeScope* entry = IFunctionUnit::function->__entry; std::vector signature; std::transform(entry->__bindings.begin(), entry->__bindings.end(), std::inserter(signature, signature.end()), [llvm, ast, entry](const std::string & arg)->llvm::Type* { assert(entry->__identifiers.count(arg)); ScopedSymbol argid{entry->__identifiers.at(arg), versions::VERSION_NONE}; return llvm->toLLVMType(ast->expandType(entry->__declarations.at(argid).type)); }); return signature; } llvm::Type* BasicFunctionUnit::prepareResult() { LLVMLayer* llvm = IFunctionUnit::pass->man->llvm; AST* ast = IFunctionUnit::pass->man->root; CodeScope* entry = IFunctionUnit::function->__entry; return llvm->toLLVMType(ast->expandType(entry->__declarations.at(ScopedSymbol::RetSymbol).type)); } llvm::Function::arg_iterator BasicFunctionUnit::prepareBindings() { CodeScope* entry = IFunctionUnit::function->__entry; ICodeScopeUnit* entryCompilation = IFunctionUnit::getScopeUnit(entry); llvm::Function::arg_iterator fargsI = IFunctionUnit::raw->arg_begin(); for (std::string &arg : entry->__bindings) { ScopedSymbol argid{entry->__identifiers[arg], versions::VERSION_NONE}; entryCompilation->bindArg(&*fargsI, argid); fargsI->setName(arg); ++fargsI; } return fargsI; } //DEBT compiler rigidly depends on exact definition of DefaultFunctionUnit typedef BasicFunctionUnit DefaultFunctionUnit; ICodeScopeUnit::ICodeScopeUnit(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass) : pass(compilePass), function(f), scope(codeScope), currentBlockRaw(nullptr) { } llvm::Value* CallStatementRaw::operator()(std::vector&& args, const std::string& hintDecl) { llvm::Function* calleeInfo = dyn_cast(__callee); if (calleeInfo) { auto argsFormal = calleeInfo->args(); int pos = 0; //SECTIONTAG types/convert function ret value for (auto argFormal = argsFormal.begin(); argFormal != argsFormal.end(); ++argFormal, ++pos) { args[pos] = typeinference::doAutomaticTypeConversion(args[pos], argFormal->getType(), llvm->builder); } } //Do not name function call that returns Void. std::string nameStatement = hintDecl; if (calleeInfo->getReturnType()->isVoidTy()){ nameStatement.clear(); } return llvm->builder.CreateCall(__calleeTy, __callee, args, nameStatement); } //DESABLEDFEATURE implement inlining class CallStatementInline : public ICallStatement { public: CallStatementInline(IFunctionUnit* caller, IFunctionUnit* callee, LLVMLayer* l) : __caller(caller), __callee(callee), llvm(l) { } llvm::Value* operator()(std::vector&& args, const std::string& hintDecl) { //TOTEST inlining // CodeScopeUnit* entryCompilation = outer->getScopeUnit(function->__entry); // for(int i=0, size = args.size(); ibindArg(args.at(i), string(entryCompilation->scope->__bindings.at(i))); // } // // // return entryCompilation->compile(); return nullptr; } private: IFunctionUnit* __caller; IFunctionUnit* __callee; LLVMLayer* llvm; bool isInline() { // Symbol ret = Symbol{0, function->__entry}; // bool flagOnTheFly = SymbolAttachments::get(ret, false); //TODO consider inlining return false; } }; BasicCodeScopeUnit::BasicCodeScopeUnit(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass) : ICodeScopeUnit(codeScope, f, compilePass) { } llvm::Value* BasicCodeScopeUnit::processSymbol(const Symbol& s, std::string hintRetVar) { Expression declaration = CodeScope::getDefinition(s); const CodeScope* scope = s.scope; ICodeScopeUnit* scopeExternal = ICodeScopeUnit::function->getScopeUnit(scope); llvm::Value* resultRaw; if (scopeExternal == this){ resultRaw = process(declaration, hintRetVar); currentBlockRaw = pass->man->llvm->builder.GetInsertBlock(); } else { assert(scopeExternal->currentBlockRaw); llvm::BasicBlock* blockOwn = pass->man->llvm->builder.GetInsertBlock(); pass->man->llvm->builder.SetInsertPoint(scopeExternal->currentBlockRaw); resultRaw = scopeExternal->processSymbol(s, hintRetVar); pass->man->llvm->builder.SetInsertPoint(blockOwn); } return resultRaw; } ICallStatement* BasicCodeScopeUnit::findFunction(const Expression& opCall) { const std::string& calleeName = opCall.getValueString(); LLVMLayer* llvm = pass->man->llvm; const std::list& specializations = pass->man->root->getFunctionSpecializations(calleeName); //if no specializations registered - check external function if (specializations.size() == 0) { llvm::Function* external = llvm->layerExtern->lookupFunction(calleeName); llvm::outs() << "Debug/External function: " << calleeName; external->getType()->print(llvm::outs(), true); llvm::outs() << "\n"; return new CallStatementRaw(external, llvm); } //There should be only one specialization without any valid guards at this point return new CallStatementRaw(pass->getFunctionUnit( pass->man->root->findFunction(calleeName))->compile(), llvm); } //DISABLEDFEATURE transformations // if (pass->transformations->isAcceptable(expr)){ // return pass->transformations->transform(expr, result, ctx); // } llvm::Value* BasicCodeScopeUnit::process(const Expression& expr, const std::string& hintVarDecl) { #define DEFAULT(x) (hintVarDecl.empty()? x: hintVarDecl) llvm::Value *left; llvm::Value *right; LLVMLayer& l = *pass->man->llvm; xreate::compilation::AdvancedInstructions instructions = xreate::compilation::AdvancedInstructions({this, function, pass}); switch (expr.op) { case Operator::SUB: case Operator::MUL: case Operator::DIV: case Operator::EQU: case Operator::LSS: case Operator::GTR: case Operator::NE: case Operator::LSE: case Operator::GTE: assert(expr.__state == Expression::COMPOUND); assert(expr.operands.size() == 2); left = process(expr.operands[0]); right = process(expr.operands[1]); //SECTIONTAG types/convert binary operation right = typeinference::doAutomaticTypeConversion(right, left->getType(), l.builder); break; default:; } switch (expr.op) { case Operator::ADD: { left = process(expr.operands[0]); Context context{this, function, pass}; llvm::Value* resultSU = StructUpdate::add(expr.operands[0], left, expr.operands[1], context, DEFAULT("tmp_add")); if (resultSU) return resultSU; right = process(expr.operands[1]); llvm::Value* resultAddPA = pointerarithmetic::PointerArithmetic::add(left, right, context, DEFAULT("tmp_add")); if (resultAddPA) { return resultAddPA; } return l.builder.CreateAdd(left, right, DEFAULT("tmp_add")); break; } case Operator::SUB: return l.builder.CreateSub(left, right, DEFAULT("tmp_sub")); break; case Operator::MUL: return l.builder.CreateMul(left, right, DEFAULT("tmp_mul")); break; case Operator::DIV: return l.builder.CreateSDiv(left, right, DEFAULT("tmp_div")); break; case Operator::EQU: if (left->getType()->isIntegerTy()) return l.builder.CreateICmpEQ(left, right, DEFAULT("tmp_equ")); if (left->getType()->isFloatingPointTy()) return l.builder.CreateFCmpOEQ(left, right, DEFAULT("tmp_equ")); break; case Operator::NE: return l.builder.CreateICmpNE(left, right, DEFAULT("tmp_ne")); break; case Operator::LSS: return l.builder.CreateICmpSLT(left, right, DEFAULT("tmp_lss")); break; case Operator::LSE: return l.builder.CreateICmpSLE(left, right, DEFAULT("tmp_lse")); break; case Operator::GTR: return l.builder.CreateICmpSGT(left, right, DEFAULT("tmp_gtr")); break; case Operator::GTE: return l.builder.CreateICmpSGE(left, right, DEFAULT("tmp_gte")); break; case Operator::NEG: left = process(expr.operands[0]); return l.builder.CreateNeg(left, DEFAULT("tmp_neg")); break; case Operator::CALL: { assert(expr.__state == Expression::COMPOUND); shared_ptr callee(findFunction(expr)); const std::string& nameCallee = expr.getValueString(); //prepare arguments std::vector args; args.reserve(expr.operands.size()); std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()), [this](const Expression & operand) { return process(operand); } ); return (*callee)(move(args), DEFAULT("res_" + nameCallee)); } case Operator::IF: { return instructions.compileIf(expr, DEFAULT("tmp_if")); } case Operator::SWITCH: { return instructions.compileSwitch(expr, DEFAULT("tmp_switch")); } case Operator::LOGIC_AND: { assert(expr.operands.size() == 1); return process(expr.operands[0]); } case Operator::LIST: { return instructions.compileListAsSolidArray(expr, DEFAULT("tmp_list")); }; case Operator::LIST_RANGE: { assert(false); //no compilation phase for a range list // return InstructionList(this).compileConstantArray(expr, l, hintRetVar); }; case Operator::LIST_NAMED: { typedef Expanded ExpandedType; ExpandedType tyStructLiteral = l.ast->getType(expr); const std::vector fieldsFormal = (tyStructLiteral.get().__operator == TypeOperator::CUSTOM) ? l.layerExtern->getStructFields(l.layerExtern->lookupType(tyStructLiteral.get().__valueCustom)) : tyStructLiteral.get().fields; std::map indexFields; for (size_t i = 0, size = fieldsFormal.size(); i < size; ++i) { indexFields.emplace(fieldsFormal[i], i); } llvm::StructType* tyLiteralRaw = llvm::cast(l.toLLVMType(tyStructLiteral)); llvm::Value* record = llvm::UndefValue::get(tyLiteralRaw); for (size_t i = 0; i < expr.operands.size(); ++i) { const Expression& operand = expr.operands.at(i); unsigned int fieldId = indexFields.at(expr.bindings.at(i)); llvm::Value* result = process(operand); assert(result); record = l.builder.CreateInsertValue(record, result, llvm::ArrayRef({fieldId})); } return record; }; case Operator::MAP: { assert(expr.blocks.size()); return instructions.compileMapSolidOutput(expr, DEFAULT("map")); }; case Operator::FOLD: { return instructions.compileFold(expr, DEFAULT("fold")); }; case Operator::FOLD_INF: { return instructions.compileFoldInf(expr, DEFAULT("fold")); }; case Operator::INDEX: { //TASK allow multiindex compilation assert(expr.operands.size() == 2); assert(expr.operands[0].__state == Expression::IDENT); const std::string& hintIdent = expr.operands[0].getValueString(); Symbol s = Attachments::get(expr.operands[0]); const ExpandedType& t2 = pass->man->root->getType(expr.operands[0]); llvm::Value* aggr = processSymbol(s, hintIdent); switch (t2.get().__operator) { case TypeOperator::LIST_NAMED: case TypeOperator::CUSTOM: { std::string idxField; const Expression& idx = expr.operands.at(1); switch (idx.__state) { //named struct field case Expression::STRING: idxField = idx.getValueString(); break; //anonymous struct field case Expression::NUMBER: idxField = to_string((int) idx.getValueDouble()); break; default: assert(false && "Wrong index for a struct"); } return instructions.compileStructIndex(aggr, t2, idxField); }; case TypeOperator::LIST: { std::vector indexes; std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()), [this] (const Expression & op) { return process(op); } ); return instructions.compileArrayIndex(aggr, indexes, DEFAULT(string("el_") + hintIdent)); }; default: assert(false); } }; case Operator::CALL_INTRINSIC: { const std::string op = expr.getValueString(); if (op == "copy") { llvm::Value* result = process(expr.getOperands().at(0)); auto decoratorVersions = Decorators::getInterface(this); llvm::Value* storage = decoratorVersions->processIntrinsicInit(result->getType()); decoratorVersions->processIntrinsicCopy(result, storage); return l.builder.CreateLoad(storage, hintVarDecl); } assert(false && "undefined intrinsic"); } case Operator::VARIANT: { const ExpandedType& typVariant = pass->man->root->getType(expr); llvm::Type* typVariantRaw = l.toLLVMType(typVariant); llvm::Type* typIdRaw = llvm::cast(typVariantRaw)->getElementType(0); uint64_t id = expr.getValueDouble(); llvm::Value* variantRaw = llvm::UndefValue::get(typVariantRaw); variantRaw = l.builder.CreateInsertValue(variantRaw, llvm::ConstantInt::get(typIdRaw, id), llvm::ArrayRef({0})); const bool flagDoReference = expr.operands.size(); if (flagDoReference){ const ExpandedType& subtyp = ExpandedType(typVariant->__operands.at(id)); llvm::Type* subtypRaw = l.toLLVMType(subtyp); Attachments::put(expr.operands.at(0), subtyp); llvm::Value* subtypValue = process(expr.operands.at(0)); llvm::Type* typStorageRaw = llvm::cast(typVariantRaw)->getElementType(1); llvm::Value* addrAsStorage = l.builder.CreateAlloca(typStorageRaw); llvm::Value* addrAsSubtyp = l.builder.CreateBitOrPointerCast(addrAsStorage, subtypRaw->getPointerTo()); l.builder.CreateStore(subtypValue, addrAsSubtyp); llvm::Value* storageRaw = l.builder.CreateLoad(typStorageRaw, addrAsStorage); variantRaw = l.builder.CreateInsertValue(variantRaw, storageRaw, llvm::ArrayRef({1})); } return variantRaw; } case Operator::SWITCH_VARIANT: { return instructions.compileSwitchVariant(expr, DEFAULT("tmpswitch")); } case Operator::SWITCH_LATE: { latereasoning::LateReasoningCompiler compiler({this, function, pass}); return compiler.compile(expr, DEFAULT("switchlate")); } case Operator::SEQUENCE: { return instructions.compileSequence(expr); } case Operator::UNDEF: { llvm::Type* typExprUndef = l.toLLVMType(typeinference::getType(expr, *pass->man->root)); return llvm::UndefValue::get(typExprUndef); } case Operator::INVALID: assert(expr.__state != Expression::COMPOUND); switch (expr.__state) { case Expression::IDENT: { Symbol s = Attachments::get(expr); return processSymbol(s, expr.getValueString()); } case Expression::NUMBER: { llvm::Type* typConst = l.toLLVMType(typeinference::getType(expr, *pass->man->root)); int literal = expr.getValueDouble(); return llvm::ConstantInt::get(typConst, literal); } case Expression::STRING: { return instructions.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str")); }; default: { break; } }; break; default: break; } assert(false && "Can't compile expression"); return 0; } llvm::Value* BasicCodeScopeUnit::compile(const std::string& hintBlockDecl) { LLVMLayer* llvm = pass->man->llvm; - + if (!hintBlockDecl.empty()) { llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm->llvmContext, hintBlockDecl, function->raw); pass->man->llvm->builder.SetInsertPoint(block); } currentBlockRaw = pass->man->llvm->builder.GetInsertBlock(); Symbol symbScope = Symbol{ScopedSymbol::RetSymbol, scope}; return processSymbol(symbScope); } ICodeScopeUnit::~ICodeScopeUnit() { } IFunctionUnit::~IFunctionUnit() { } llvm::Function* IFunctionUnit::compile() { if (raw != nullptr) return raw; LLVMLayer* llvm = pass->man->llvm; llvm::IRBuilder<>& builder = llvm->builder; string&& functionName = prepareName(); std::vector&& types = prepareArguments(); llvm::Type* expectedResultType = prepareResult(); llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false); raw = llvm::cast(llvm->module->getOrInsertFunction(functionName, ft)); prepareBindings(); const std::string&blockName = "entry"; llvm::BasicBlock* blockCurrent = builder.GetInsertBlock(); llvm::Value* result = getScopeUnit(function->__entry)->compile(blockName); assert(result); //SECTIONTAG types/convert function ret value builder.CreateRet(typeinference::doAutomaticTypeConversion(result, expectedResultType, llvm->builder)); if (blockCurrent) { builder.SetInsertPoint(blockCurrent); } llvm->moveToGarbage(ft); return raw; } ICodeScopeUnit* IFunctionUnit::getScopeUnit(const CodeScope * const scope) { if (__scopes.count(scope)) { auto result = __scopes.at(scope).lock(); if (result) { return result.get(); } } std::shared_ptr unit(pass->buildCodeScopeUnit(scope, this)); if (scope->__parent != nullptr) { auto parentUnit = Decorators::getInterface(getScopeUnit(scope->__parent)); parentUnit->registerChildScope(unit); } else { __orphanedScopes.push_back(unit); } if (!__scopes.emplace(scope, unit).second) { __scopes[scope] = unit; } return unit.get(); } ICodeScopeUnit* IFunctionUnit::getScopeUnit(ManagedScpPtr scope) { return getScopeUnit(&*scope); } ICodeScopeUnit* IFunctionUnit::getEntry() { return getScopeUnit(function->getEntryScope()); } template<> compilation::IFunctionUnit* CompilePassCustomDecorators::buildFunctionUnit(const ManagedFnPtr& function){ return new DefaultFunctionUnit(function, this); } template<> compilation::ICodeScopeUnit* CompilePassCustomDecorators::buildCodeScopeUnit(const CodeScope* const scope, IFunctionUnit* function){ return new DefaultCodeScopeUnit(scope, function, this); } } // end of compilation compilation::IFunctionUnit* CompilePass::getFunctionUnit(const ManagedFnPtr& function) { unsigned int id = function.id(); if (!functions.count(id)) { compilation::IFunctionUnit* unit = buildFunctionUnit(function); functions.emplace(id, unit); return unit; } return functions.at(id); } void CompilePass::run() { + //Initialization: managerTransformations = new xreate::compilation::TransformationsManager(); targetInterpretation = new interpretation::TargetInterpretation(this->man->root, this); + Attachments::init(); - //Find out main function; + //Determine entry function: StaticModel model = man->transcend->query(Config::get("function-entry")); assert(model.size() && "Error: No entry function found"); assert(model.size() == 1 && "Error: Ambiguous entry function"); string nameMain = std::get<0>(TranscendLayer::parse(model.begin()->second)); compilation::IFunctionUnit* unitMain = getFunctionUnit(man->root->findFunction(nameMain)); + + //Compilation itself: entry = unitMain->compile(); } llvm::Function* CompilePass::getEntryFunction() { assert(entry); return entry; } void CompilePass::prepareQueries(TranscendLayer* transcend) { transcend->registerQuery(new containers::Query(), QueryId::ContainersQuery); transcend->registerQuery(new polymorph::PolymorphQuery(), QueryId::PolymorphQuery); } } //end of namespace xreate /** * \class xreate::CompilePass * \brief Encapsulates all compilation activities * * xreate::CompilePass iterates over xreate::AST tree and produces executable code fed by data(via xreate::Attachments) gathered by previous passes as well as data via queries(xreate::IQuery) from xreate:TranscendLayer reasoner. * Compilation's done using xreate::LLVMLayer(wrapper over LLVM toolchain) and based on following aspects: * - Containers support. See \ref compilation/containers.h * - Late Conext compilation. See xreate::context::LateContextCompiler2 * - Interpretation support. See xreate::interpretation::TargetInterpretation * - Loop saturation support. See xreate::compilation::TransformerSaturation * - External Code access. See xreate::ExternLayer(wrapper over Clang library) * * \section adaptability_sect Adaptability * xreate::CompilePass's architecture provides adaptability by employing: * - %Function Decorators to alter function-level compilation. See xreate::compilation::IFunctionUnit * - Code Block Decorators to alter code block level compilation. See xreate::compilation::ICodeScopeUnit * Default functionality defined by \ref xreate::compilation::DefaultCodeScopeUnit * - Targets to allow more versitile extensions. * Currently only xreate::interpretation::TargetInterpretation use Targets infrastructure. See xreate::compilation::Target * - %Altering Function invocation. xreate::compilation::ICallStatement * * Client able to construct compiler with desired decorators using xreate::compilation::CompilePassCustomDecorators. * As a handy alias, `CompilePassCustomDecorators` constructs default compiler * */ diff --git a/cpp/src/pass/dfapass.cpp b/cpp/src/pass/dfapass.cpp index a4a6747..26ca47b 100644 --- a/cpp/src/pass/dfapass.cpp +++ b/cpp/src/pass/dfapass.cpp @@ -1,233 +1,241 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * * dfapass.cpp */ /** * \file dfapass.h * \brief Data Flow Analysis(DFA) */ //DEBT DFA represent VersionaPass in declarative form using applyDependencies // applyDependencies(expression, context, cache, decl); //DEBT DFA prepare static annotations and represent InterpretationPass in declarative form // applyStaticAnnotations(expression, context, cache, decl); //DEBT DFA Eliminate dfa schemes #include "pass/dfapass.h" #include "xreatemanager.h" #include "transcendlayer.h" #include #include using namespace std; namespace xreate {namespace dfa { DFAPass::DFAPass(PassManager* manager) : AbstractPass(manager) , graph{new DFAGraph()} , transcend(manager->transcend) { } void DFAPass::processCallInstance(const Expression& expr, PassContext context, const SymbolNode& result) { const string &nameCalleeFunction=expr.getValueString(); //TODO implement processFnCall/Uncertain list variantsCalleeFunction=man->root->getFunctionSpecializations(nameCalleeFunction); vector operands; operands.reserve(expr.getOperands().size()); for(const Expression& arg : expr.getOperands()) { operands.push_back(process(arg, context)); } //Set calling relations: DFACallInstanceType type=variantsCalleeFunction.size()>1?WEAK:STRONG; for(ManagedFnPtr function : variantsCalleeFunction) { CodeScope *scopeRemote=function->getEntryScope(); DFACallInstance callInstance; callInstance.fnName=function->getName(); callInstance.type=type; std::vector::const_iterator nodeActual=operands.begin(); for(const std::string &identFormal : scopeRemote->__bindings) { const ScopedSymbol symbolFormal{scopeRemote->__identifiers.at(identFormal), versions::VERSION_NONE}; SymbolPacked symbolFormalPacked=transcend->pack(Symbol{symbolFormal, scopeRemote}, nameCalleeFunction+":"+identFormal); callInstance.args.push_back(std::make_pair(symbolFormalPacked, *nodeActual)); ++nodeActual; } callInstance.retActual=result; SymbolNode retFormal=SymbolNode(transcend->pack(Symbol{ScopedSymbol::RetSymbol, scopeRemote}, nameCalleeFunction+":[ret]")); graph->addCallInstance(std::move(callInstance)); } } void DFAPass::processDependencies(const SymbolNode& node, const Expression& expression, PassContext context, ProcessingCache& cache) { cache.operands.reserve(expression.getOperands().size()); for(const Expression &op : expression.getOperands()) { const SymbolNode& subnodeOperand=process(op, context); cache.operands.push_back(subnodeOperand); graph->addDependency(node, subnodeOperand); } cache.blocks.reserve(expression.blocks.size()); for(CodeScope* block : expression.blocks) { const SymbolNode& subnodeBlock=process(block, context); cache.blocks.push_back(subnodeBlock); graph->addDependency(node, subnodeBlock); } } +void +DFAPass::processAnnotations(const Expression& expression, PassContext context, const SymbolNode& ident){ + for (const pair& tag : expression.tags){ + graph->printInplaceAnnotation(ident, tag.second); + } +} + SymbolNode DFAPass::process(const Expression& expression, PassContext context, const std::string& varDecl) { SymbolNode result; if(Attachments::exists(expression)){ Symbol varSymbol=Attachments::get(expression); result=transcend->pack(varSymbol, varDecl); } else if(expression.__state==Expression::IDENT&&expression.tags.size()==0){ Symbol varSymbol=Attachments::get(expression); result=transcend->pack(varSymbol, expression.getValueString()); } else { result=SymbolAnonymous{expression.id}; } - graph->printInplaceAnnotations(result, expression); + processAnnotations(expression, context, result); switch(expression.__state) { case Expression::COMPOUND: { switch(expression.op) { case Operator::CALL: { processCallInstance(expression, context, result); break; } case Operator::IF: { const SymbolNode& scopeA=process(expression.blocks.front(), context, "ifTrue" + std::to_string(expression.id)); const SymbolNode& scopeB=process(expression.blocks.back(), context, "ifFalse" + std::to_string(expression.id)); const SymbolNode& condition=process(expression.operands.at(0), context); graph->addDependency(result, scopeA); graph->addDependency(result, scopeB); graph->addDependency(result, condition); graph->printWeakAlias(result, scopeA); graph->printWeakAlias(result, scopeB); break; } case Operator::SWITCH: case Operator::SWITCH_VARIANT: { for(CodeScope* block : expression.blocks) { const SymbolNode& subnodeBlock=process(block, context, "case"+to_string(block->getBody().id)); graph->addDependency(result, subnodeBlock); graph->printWeakAlias(result, subnodeBlock); } const SymbolNode& condition=process(expression.operands.at(0), context); graph->addDependency(result, condition); break; } default: { ProcessingCache cache; processDependencies(result, expression, context, cache); break; } } break; } case Expression::IDENT: { SymbolNode symbIdent=AbstractPass::process(expression, context, varDecl); if(!(result==symbIdent)){ graph->addDependency(result, symbIdent); graph->printAlias(result, symbIdent); } break; } case Expression::NUMBER: case Expression::STRING: { break; } case Expression::INVALID: case Expression::BINDING: { assert(false); break; } } return result; } SymbolNode DFAPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl) { if (!hintBlockDecl.empty()) { Symbol symbRet{ScopedSymbol::RetSymbol, scope}; transcend->pack(symbRet, hintBlockDecl + ":[ret]"); } for(const std::string& binding : scope->__bindings) { - Symbol bindingSymbol{scope->getSymbol(binding), scope}; - SymbolPacked bindingPacked=transcend->pack(bindingSymbol, binding); + Symbol bindingSymb{scope->getSymbol(binding), scope}; + SymbolPacked bindingSymbP=transcend->pack(bindingSymb, binding); - getSymbolCache().setCachedValue(bindingSymbol, SymbolNode(bindingPacked)); + getSymbolCache().setCachedValue(bindingSymb, SymbolNode(bindingSymbP)); + processAnnotations(scope->getDefinition(bindingSymb), context, SymbolNode(bindingSymbP)); } return AbstractPass::process(scope, context, hintBlockDecl); } SymbolNode DFAPass::process(ManagedFnPtr function) { transcend->pack(Symbol{ScopedSymbol::RetSymbol, function->getEntryScope()}, function->getName()+to_string(function.id())+":[ret]"); SymbolNode result=AbstractPass::process(function); graph->printFunctionRet(function, result); return result; } void DFAPass::finish() { transcend->registerReport(graph); //Declare symbols: graph->printSymbols(transcend); AbstractPass::finish(); } } //end of namespace dfa template<> SymbolNode defaultValue() { assert(false); } } //end of xreate namespace /** * \class xreate::dfa::DFAPass * \details Provides DFA, important analysis for reasoning. Iterates over AST and stores collected data in DFAGraph */ diff --git a/cpp/src/pass/dfapass.h b/cpp/src/pass/dfapass.h index 09f5538..0626a26 100644 --- a/cpp/src/pass/dfapass.h +++ b/cpp/src/pass/dfapass.h @@ -1,51 +1,52 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * * dfapass.h * Data Flow Graph building pass */ #ifndef DFGPASS_H #define DFGPASS_H #include "abstractpass.h" #include "analysis/dfagraph.h" namespace xreate { class TranscendLayer; } namespace xreate { namespace dfa { struct ProcessingCache { std::vector operands; std::vector blocks; }; /** \brief Data Flow Analysis Pass(%DFA) */ class DFAPass: public AbstractPass { public: DFAPass(PassManager* manager); protected: + virtual void processAnnotations(const Expression& expression, PassContext context, const SymbolNode& ident); virtual SymbolNode process(const Expression& expression, PassContext context, const std::string& varDecl="") override; virtual SymbolNode process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl="") override; virtual SymbolNode process(ManagedFnPtr function) override; void init(); void finish() override; + DFAGraph* graph; + TranscendLayer* transcend; + private: void processCallInstance(const Expression& expr, PassContext context, const SymbolNode& result); void processDependencies(const SymbolNode& node, const Expression& expression, PassContext context, ProcessingCache& cache); - - DFAGraph* graph; - TranscendLayer* transcend; }; }} //end of xreate::dfa namespace #endif diff --git a/cpp/src/pass/latereasoningpass.h b/cpp/src/pass/latereasoningpass.h new file mode 100644 index 0000000..c005673 --- /dev/null +++ b/cpp/src/pass/latereasoningpass.h @@ -0,0 +1,179 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* + * Author: pgess + * Created on June 7, 2018, 7:20 PM + * + * \file latereasoningpass.h + * \brief latereasoningpass + */ + +#ifndef LATEREASONINGPASS_H +#define LATEREASONINGPASS_H + +#include "pass/dfapass.h" + +namespace xreate { namespace latereasoning { + +class LateReasoningScope{ +public: + LateReasoningScope(LateReasoningScope* parent): __parent(parent){ } + + boost::optional + recognizeIdentifier(const std::string& identifier){ + + //Search identifier in the current scope + if(__identifiers.count(identifier)){ + return make_pair(identifier, __identifiers.at(identifier)); + } + + //Search in the parent scope + if(__parent){ + return __parent->recognizeIdentifier(identifier); + } + + return boost::none; + } + + void + addIdentifier(std::string idenName, const SymbolPacked& identSymbol){ + __identifiers.emplace(idenName, identSymbol); + } + +private: + std::map __identifiers; + LateReasoningScope *__parent; +}; + +template +class LateReasoningDFAPassDecorator: public Parent{ +public: + LateReasoningDFAPassDecorator(PassManager* manager): Parent(manager){ } + + void + registerLateScope(CodeScope* scope, LateReasoningScope* scopeLate){ + __dictScopes.emplace(scope, scopeLate); + } + +private: + LateReasoningScope* + liftScope(const CodeScope* scope){ + while(scope){ + if(__dictScopes.count(scope)) return __dictScopes.at(scope); + scope = scope->__parent; + } + + return nullptr; + } + + std::list + recognizeLateIdentifiers(const Expression& expression, LateReasoningScope* scope){ + std::list result; + + switch(expression.op){ + case Operator::CALL: + { + for(const auto& op: expression.operands){ + std::list opResult = recognizeLateIdentifiers(op, scope); + result.insert(result.end(), opResult.begin(), opResult.end()); + } + + if(!expression.operands.size()){ + if(auto symbolRecognized = scope->recognizeIdentifier(expression.getValueString())){ + result.push_back(*symbolRecognized); + } + } + break; + } + + case Operator::NEG: + { + assert(expression.operands.size() == 1); + + const Expression &op = expression.operands.at(0); + std::list opResult = recognizeLateIdentifiers(op, scope); + result.insert(result.end(), opResult.begin(), opResult.end()); + }; + + case Operator::INVALID: + { + switch(expression.__state){ + case Expression::NUMBER: + break; + + default: + assert(true); + } + break; + } + + default: break; + } + + return result; + } + +protected: + virtual SymbolNode process(const Expression& expression, PassContext context, const std::string& varDecl="") override{ + if(expression.__state == Expression::COMPOUND && expression.op == Operator::SWITCH_LATE){ + //Reserve late scope: + LateReasoningScope* scopeLate = new LateReasoningScope(liftScope(context.scope)); + CodeScope* scopeBody = expression.blocks.front(); + registerLateScope(scopeBody, scopeLate); + + //Assign late identifiers + for(const std::string& identLate: expression.bindings){ + ScopedSymbol identLateS = scopeBody->getSymbol(identLate); + SymbolPacked identLateSP = Parent::man->transcend->pack(Symbol{identLateS, scopeBody}); + + scopeLate->addIdentifier(identLate, identLateSP); + } + } + + return Parent::process(expression, context, varDecl); + } + + virtual void + processAnnotations(const Expression& expression, + PassContext context, + const SymbolNode& ident){ + + LateReasoningScope* scopeLate = liftScope(context.scope); + + if(!expression.tags.size() || !scopeLate) + return Parent::processAnnotations(expression, context, ident); + + for(const std::pair& tag: expression.tags){ + std::list symbols = recognizeLateIdentifiers(tag.second, scopeLate); + if(!symbols.size()){ + //Standard compilation + Parent::graph->printInplaceAnnotation(ident, tag.second); + + } else{ + //Late compilation + std::list domains; + for(const auto& symbol: symbols){ + Symbol symbolUnpacked = Parent::man->transcend->unpack(symbol.second); + ExpandedType typSymbol = Parent::man->root->getType(CodeScope::getDefinition(symbolUnpacked)); + assert(typSymbol->__operator == TypeOperator::SLAVE); + + domains.push_back(typSymbol->__valueCustom); + } + + Parent::graph->printLateAnnotation(ident, tag.second, symbols, domains); + } + } + } + +private: + std::unordered_map __dictScopes; +}; + +}} + +#endif /* LATEREASONINGPASS_H */ + diff --git a/cpp/src/query/polymorph.cpp b/cpp/src/query/polymorph.cpp index ca9bc4c..794b237 100644 --- a/cpp/src/query/polymorph.cpp +++ b/cpp/src/query/polymorph.cpp @@ -1,55 +1,57 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: polymorph.cpp * Author: pgess * * Created on November 9, 2017, 12:14 PM */ #include "polymorph.h" - +#include "aux/transcend-decorators.h" using namespace std; namespace xreate { namespace polymorph { const std::string atomPolymorph = "dfa_callguard"; void PolymorphQuery::init(TranscendLayer* transcend){ __transcend = transcend; StaticModel queryResult = transcend->query(atomPolymorph); if (queryResult.size()){ for (auto entry: queryResult){ auto answer = TranscendLayer::parse(entry.second); SymbolNode symbCaller = std::get<0>(answer); SymbolGeneralized symbCallerUnpacked = transcend->unpack(symbCaller); Expression guard = std::get<1>(answer); __cacheEarlyReasoning.emplace(symbCallerUnpacked, guard); } } } Expression PolymorphQuery::get(const Expression& e){ SymbolGeneralized symbol=Attachments::exists(e)? SymbolGeneralized(Attachments::get(e)) : SymbolGeneralized(SymbolAnonymous{e.id}); if (__cacheEarlyReasoning.count(symbol)){ return __cacheEarlyReasoning.at(symbol); } + DefaultTranscendLayerImpl* transcendLate = dynamic_cast(__transcend); SymbolNode symbolPacked = __transcend->pack(symbol, ""); - StaticModel answer = __transcend->queryCompiled().queryLate(atomPolymorph, symbolPacked); + + StaticModel answer = transcendLate->queryLate(atomPolymorph, symbolPacked); assert(answer.size() && "Can't find a guard"); - Expression result; - tie(result) = TranscendLayer::parse(answer.begin()->second); - return result; + Expression guard; + tie(guard) = TranscendLayer::parse(answer.begin()->second); + return guard; } }} //end of xreate::polymorph diff --git a/cpp/src/transcendlayer.cpp b/cpp/src/transcendlayer.cpp index 2d86470..3058778 100644 --- a/cpp/src/transcendlayer.cpp +++ b/cpp/src/transcendlayer.cpp @@ -1,560 +1,486 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * File: transcendlayer.cpp */ /** * \file transcendlayer.h - * \brief Resoner. Wrapper over the external Clasp reasoner library + * \brief Reasoner. Wrapper over the external Clasp reasoner library */ #include "transcendlayer.h" #include "analysis/utils.h" #include "utils.h" #include #include #include #include #include #include using namespace std; //TODO escape identifiers started with upper case symbol -namespace xreate { - bool operator==(const SymbolAnonymous& s1, const SymbolAnonymous& s2){ - return s1.id == s2.id && s1.flagIsUsed == s2.flagIsUsed; - } - - struct VisitorSymbolNodeHash : public boost::static_visitor { - std::size_t operator()(const xreate::SymbolPacked& node) const noexcept{ - return 2* (node.identifier + 3 * node.scope + 5 * std::abs(node.version)); - } +namespace xreate{ - std::size_t operator()(const xreate::SymbolAnonymous& node) const noexcept{ - return 7 * node.id; - } - }; +bool operator==(const SymbolAnonymous& s1, const SymbolAnonymous& s2) { + return s1.id == s2.id && s1.flagIsUsed == s2.flagIsUsed; } -namespace std { - std::size_t - hash::operator()(xreate::SymbolNode const& s) const noexcept { - return boost::apply_visitor(xreate::VisitorSymbolNodeHash(), s); +struct VisitorSymbolNodeHash : public boost::static_visitor{ + + std::size_t operator()(const xreate::SymbolPacked& node) const noexcept { + return 2 * (node.identifier + 3 * node.scope + 5 * std::abs(node.version)); } - std::size_t - hash::operator()(xreate::SymbolGeneralized const& s) const noexcept { - return xreate::AttachmentsId::getId(s); + std::size_t operator()(const xreate::SymbolAnonymous& node) const noexcept { + return 7 * node.id; } +}; } -namespace xreate { +namespace std{ + +std::size_t +hash::operator()(xreate::SymbolNode const& s) const noexcept { + return boost::apply_visitor(xreate::VisitorSymbolNodeHash(), s); +} + +std::size_t +hash::operator()(xreate::SymbolGeneralized const& s) const noexcept { + return xreate::AttachmentsId::getId(s); +} +} + +namespace xreate{ + void TranscendLayer::printWarnings(std::ostream& out) { const std::string warningTag = "warning"; auto warningsModel = query(warningTag); if(warningsModel.size()) - for (auto warning: warningsModel) { - unsigned int warningId; + for(auto warning : warningsModel) { + unsigned int warningId; - Gringo::Symbol params; - std::tie(warningId, params) = parse(warning.second); + Gringo::Symbol params; + std::tie(warningId, params) = parse(warning.second); - cout << "Warning: " << __warnings.at(warningId) << " "; - params.print(out); - out<(parse(atom)).name().c_str(); - __model.addStaticAtom(atomAlias, atom); - - } else if(atomName == atomLateStatement){ - //late atom format: (Symbol, (tuple of keys), (tuple of values), late-annotation) - auto atomLate = parse, std::list, Gringo::Symbol>(atom); - const string& atomAlias = get<3>(atomLate).name().c_str(); - __model.addLateAtom(atomAlias, get<0>(atomLate), - get<3>(atomLate), get<1>(atomLate), - get<2>(atomLate)); + __model.emplace(atomAlias, atom); + continue; } - __model.addStaticAtom(atomName, atom); + __model.emplace(atomName, atom); } return true; } void -TranscendLayer::registerReport(IAnalysisReport* report){ +TranscendLayer::registerReport(IAnalysisReport * report) { __reports.push_back(report); } void -TranscendLayer::runReports(){ - for(IAnalysisReport* report: __reports){ +TranscendLayer::runReports() { + for(IAnalysisReport* report : __reports) { report->print(__partGeneral); delete report; } __reports.clear(); } void -TranscendLayer::addRuleWarning(const RuleWarning &rule) { +TranscendLayer::addRuleWarning(const RuleWarning & rule) { //__partGeneral << rule << endl; list domains; boost::format formatDef("%1%(%2%)"); std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(domains, domains.begin()), [&formatDef](const std::pair &argument) { string domain; - switch (argument.second) { - case DomainAnnotation::FUNCTION: - domain = "function"; - break; - case DomainAnnotation::VARIABLE: - domain = "variable"; - break; + switch(argument.second) { + case DomainAnnotation::FUNCTION: + domain = "function"; + break; + case DomainAnnotation::VARIABLE: + domain = "variable"; + break; } return boost::str(formatDef % domain % argument.first); }); list vars; std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(vars, vars.begin()), [](const std::pair &argument) { return argument.first.c_str(); }); - list> guardsRaw; + list> guardsRaw; std::transform(rule.__guards.begin(), rule.__guards.end(), std::inserter(guardsRaw, guardsRaw.begin()), - [this](const Expression &guard) { + [this](const Expression & guard) { return xreate::analysis::compile(guard); }); const list& guards = xreate::analysis::multiplyLists(std::move(guardsRaw)); list &&branches = xreate::analysis::compileNeg(rule.__condition); boost::format formatWarning("warning(%1%, (%2%)):- %3%, %4%, %5%."); - for (const string &guardsJoined: guards) - for (const string &branch: branches) { + for(const string &guardsJoined : guards) + for(const string &branch : branches) { unsigned int hook = registerWarning(string(rule.__message)); - __partGeneral << formatWarning - %(hook) - %(boost::algorithm::join(vars, ", ")) - %(branch) - %(guardsJoined) - %(boost::algorithm::join(domains, ", ")) - <__rawImports) - { + for(string fn : ast->__rawImports) { std::ifstream file(fn); - if (!file){ + if(!file) { std::cout << "Can't process script file: " << fn << std::endl; assert(false); } - while(!file.eof()){ + while(!file.eof()) { string line; std::getline(file, line); out << line << endl; } } } void -TranscendLayer::addRawScript(std::string&& script){ +TranscendLayer::addRawScript(std::string && script) { __partGeneral << script; } void TranscendLayer::run() { involveImports(); runReports(); ostringstream program; program << __partTags.str() << __partGeneral.str(); cout << FYEL(program.str()) << endl; std::vector args{"clingo", nullptr}; DefaultGringoModule moduleDefault; Gringo::Scripts scriptsDefault(moduleDefault); - ClingoLib ctl(scriptsDefault, 0, args.data(), {}, 0); - ctl.add("base", {}, program.str()); - ctl.ground({{"base", {}}}, nullptr); + ClingoLib ctl(scriptsDefault, 0, args.data(), { }, 0); + + ctl.add("base",{}, program.str()); + ctl.ground({ + {"base", + {}}}, nullptr); -// solve + // solve Gringo::SolveResult result = ctl.solve([this](Gringo::Model const &model) { - this->handleSolution(model); + this->processSolution(model); return true; }, {}); - if (result.satisfiable() == Gringo::SolveResult::Satisfiable) { + if(result.satisfiable() == Gringo::SolveResult::Satisfiable) { cout << FGRN("SUCCESSFULLY") << endl; } else { cout << FRED("UNSUCCESSFULLY") << endl; } -// invoke all query plugins to process solution - for (auto q: __queries) - { + // invoke all query plugins to process solution + for(auto q : __queries) { q.second->init(this); } } -TranscendLayer::TranscendLayer(): __model(this), ast(nullptr){ -} - -const ReasoningModel& -TranscendLayer::queryCompiled() { - return __model; -} +TranscendLayer::TranscendLayer(): ast(nullptr) { } StaticModel -TranscendLayer::query(const std::string& atom){ - return __model.queryStatic(atom); +TranscendLayer::query(const std::string & atom) const{ + StaticModel result; + + if (! __model.count(atom)){ + return result; + } + + auto currentDataRange = __model.equal_range(atom); + std::copy(currentDataRange.first, currentDataRange.second, std::inserter(result, result.end())); + return result; } ScopePacked -TranscendLayer::pack(const CodeScope* const scope) { +TranscendLayer::pack(const CodeScope * const scope) { auto pos = __indexScopes.emplace(scope, __indexScopes.size()); - if (pos.second) + if(pos.second) __registryScopes.push_back(scope); return pos.first->second; } size_t -TranscendLayer::getScopesCount() const{ +TranscendLayer::getScopesCount() const { return __registryScopes.size(); } SymbolPacked -TranscendLayer::pack(const Symbol& symbol, std::string hintSymbolName) -{ +TranscendLayer::pack(const Symbol& symbol, std::string hintSymbolName) { SymbolPacked result(symbol.identifier.id, symbol.identifier.version, pack(symbol.scope)); __indexSymbolNameHints.emplace(result, hintSymbolName); return result; } Symbol -TranscendLayer::unpack(const SymbolPacked& symbol) -{ - return Symbol{ScopedSymbol{symbol.identifier, symbol.version}, __registryScopes[symbol.scope]}; +TranscendLayer::unpack(const SymbolPacked & symbol) const{ + return Symbol{ScopedSymbol + {symbol.identifier, symbol.version}, __registryScopes[symbol.scope]}; }; std::string -TranscendLayer::getHintForPackedSymbol(const SymbolPacked& symbol){ +TranscendLayer::getHintForPackedSymbol(const SymbolPacked & symbol) { auto result = __indexSymbolNameHints.find(symbol); - return (result == __indexSymbolNameHints.end())? "" : result->second; + return(result == __indexSymbolNameHints.end()) ? "" : result->second; } -IQuery* -TranscendLayer::registerQuery(IQuery *query, const QueryId& id) { +IQuery * + TranscendLayer::registerQuery(IQuery *query, const QueryId & id) { return __queries.emplace(id, query).first->second; } -IQuery* -TranscendLayer::getQuery(const QueryId& id){ +IQuery * + TranscendLayer::getQuery(const QueryId & id) { assert(__queries.count(id) && "Undefined query"); return __queries.at(id); } -class VisitorUnpackSymbol: public boost::static_visitor { +class VisitorUnpackSymbol : public boost::static_visitor{ public: - VisitorUnpackSymbol(TranscendLayer* transcend): __transcend(transcend) {} + + VisitorUnpackSymbol(const TranscendLayer* transcend) : __transcend(transcend) { } SymbolGeneralized operator()(const SymbolPacked& symbol) const { return __transcend->unpack(symbol); } SymbolGeneralized operator()(const SymbolAnonymous& symbol) const { return symbol; } private: - TranscendLayer* __transcend; + const TranscendLayer* __transcend; }; -class VisitorPackSymbol: public boost::static_visitor { +class VisitorPackSymbol : public boost::static_visitor{ public: + VisitorPackSymbol(TranscendLayer* transcend, const std::string& hintSymbolName) - : __transcend(transcend), __hint(hintSymbolName) {} + : __transcend(transcend), __hint(hintSymbolName) { } SymbolNode operator()(const Symbol& symbol) const { return __transcend->pack(symbol, __hint); } SymbolNode operator()(const SymbolAnonymous& symbol) const { return symbol; } private: TranscendLayer* __transcend; std::string __hint; }; -SymbolNode TranscendLayer::pack(const SymbolGeneralized& symbol, const std::string& hintSymbolName){ +SymbolNode +TranscendLayer::pack(const SymbolGeneralized& symbol, const std::string & hintSymbolName) { return boost::apply_visitor(VisitorPackSymbol(this, hintSymbolName), symbol); } -SymbolGeneralized TranscendLayer::unpack(const SymbolNode& symbol) -{ +SymbolGeneralized +TranscendLayer::unpack(const SymbolNode & symbol) const{ return boost::apply_visitor(VisitorUnpackSymbol(this), symbol); } -boost::optional -GuardedAnnotation::get(const std::list& keys) const{ - for (const auto& entry: guardedSymbols){ - const std::list& keysExpected = entry.first; - - auto keysIt = keys.begin(); - bool result = true; - for(const Expression& keyExpected: keysExpected){ - if(! (keyExpected == *keysIt)) {result = false; break; } - ++keysIt; - } - if(!result) continue; - return entry.second; - } - - return boost::none; -} - -std::list -ReasoningModel::findKeys(const std::list& keys) const{ - std::list result; - std::transform(keys.begin(), keys.end(), std::inserter(result, result.end()), [this](const SymbolPacked& key){ - return Attachments::get(this->transcend->unpack(key)); - }); - - return result; +bool +operator==(const SymbolPacked& s1, const SymbolPacked & s2) { + return s1.identifier == s2.identifier && s1.scope == s2.scope; } -void ReasoningModel::addStaticAtom(const std::string& atomAlias, const Gringo::Symbol& atom){ - modelStatic.emplace(atomAlias, atom); +bool +operator<(const SymbolPacked& s1, const SymbolPacked & s2) { + return s1.scope < s2.scope || (s1.scope == s2.scope && s1.identifier < s2.identifier); } -void ReasoningModel::addLateAtom(const std::string& alias, const SymbolNode& symbol, - const Gringo::Symbol& atom, const std::list& guardKeys, - const std::list& guardBindings){ - LateModel& model = modelGuarded[alias]; - if(!model.bindings.count(symbol)){ - model.bindings.emplace(symbol, guardKeys); - } - - GuardedAnnotation& annotation = model.annotations[symbol]; - annotation.guardedSymbols.push_back(make_pair(guardBindings, atom)); -} +Expression +ParseImplAtom::get(const Gringo::Symbol & atom) { + switch(atom.type()) { + case Gringo::SymbolType::Num: return Expression(atom.num()); + case Gringo::SymbolType::Str: return Expression(Atom(std::string(atom.string().c_str()))); -StaticModel -ReasoningModel::queryStatic(const std::string& alias) const{ - StaticModel result; + case Gringo::SymbolType::Fun: + { + //FUNC + Expression result(Operator::CALL,{Expression(Atom(std::string(atom.name().c_str())))}); + for(const Gringo::Symbol& arg : atom.args()) { + result.addArg(ParseImplAtom::get(arg)); + } - if (! modelStatic.count(alias)){ return result; } - auto currentDataRange = modelStatic.equal_range(alias); - std::copy(currentDataRange.first, currentDataRange.second, std::inserter(result, result.end())); - return result; -} - -StaticModel -ReasoningModel::queryLate(const std::string& alias, const SymbolNode& symbol) const{ - StaticModel result; - if (!modelGuarded.count(alias)) return StaticModel(); - - const LateModel& model = modelGuarded.at(alias); - assert(model.bindings.count(symbol)); - const list& bindings = model.bindings.at(symbol); - list&& keys = findKeys(bindings); - - const GuardedAnnotation& annGuarded = model.annotations.at(symbol); - auto ann = annGuarded.get(keys); - if(ann){ - result.emplace(make_pair(alias, *ann)); + default: + { + assert(false); } - - return result; -} - -bool operator==(const SymbolPacked& s1, const SymbolPacked& s2) -{ - return s1.identifier == s2.identifier && s1.scope == s2.scope; -} - -bool operator<(const SymbolPacked& s1, const SymbolPacked& s2) -{ - return s1.scope < s2.scope || (s1.scope == s2.scope && s1.identifier < s2.identifier); -} - -Expression -ParseImplAtom::get(const Gringo::Symbol& atom) { - switch (atom.type()) { - case Gringo::SymbolType::Num: return Expression(atom.num()); - case Gringo::SymbolType::Str: return Expression(Atom(std::string(atom.string().c_str()))); - - case Gringo::SymbolType::Fun: - { - //FUNC - Expression result(Operator::CALL,{Expression(Atom(std::string(atom.name().c_str())))}); - for (const Gringo::Symbol& arg : atom.args()) { - result.addArg(ParseImplAtom::get(arg)); - } - - return result; - } - - default: - { - assert(false); - } } } int -ParseImplAtom::get(const Gringo::Symbol& atom) { - switch (atom.type()){ - case Gringo::SymbolType::Num: return atom.num(); - default: break; +ParseImplAtom::get(const Gringo::Symbol & atom) { + switch(atom.type()) { + case Gringo::SymbolType::Num: return atom.num(); + default: break; } assert(false && "Inappropriate symbol type"); } std::string -ParseImplAtom::get(const Gringo::Symbol& atom) { - switch (atom.type()) { - case Gringo::SymbolType::Str: return atom.string().c_str(); - case Gringo::SymbolType::Fun: return atom.name().c_str(); +ParseImplAtom::get(const Gringo::Symbol & atom) { + switch(atom.type()) { + case Gringo::SymbolType::Str: return atom.string().c_str(); + case Gringo::SymbolType::Fun: return atom.name().c_str(); - default: break; + default: break; } assert(false && "Inappropriate symbol type"); } SymbolPacked -ParseImplAtom::get(const Gringo::Symbol& atom) { +ParseImplAtom::get(const Gringo::Symbol & atom) { auto result = TranscendLayer::parse(atom); return SymbolPacked(std::get<0>(result), std::get<1>(result), std::get<2>(result)); }; Gringo::Symbol -ParseImplAtom::get(const Gringo::Symbol& atom) { +ParseImplAtom::get(const Gringo::Symbol & atom) { return atom; } SymbolNode -ParseImplAtom::get(const Gringo::Symbol& atom) { +ParseImplAtom::get(const Gringo::Symbol & atom) { assert(atom.type() == Gringo::SymbolType::Fun - && "Inappropriate symbol type"); + && "Inappropriate symbol type"); - if (atom.name() == "a"){ + if(atom.name() == "a") { return SymbolAnonymous{(unsigned int) std::get<0>(TranscendLayer::parse(atom))}; - } else if (atom.name() == "s"){ + } else if(atom.name() == "s") { return ParseImplAtom::get(atom); } assert(false && "Wrong symbol format"); } -class VisitorSymbolId: public boost::static_visitor { +class VisitorSymbolId : public boost::static_visitor{ public: + unsigned int operator()(const Symbol& symbol) const { return AttachmentsId::getId(symbol); } unsigned int operator()(const SymbolAnonymous& symbol) const { return symbol.id; } }; unsigned int -AttachmentsId::getId(const SymbolGeneralized& symbol){ +AttachmentsId::getId(const SymbolGeneralized & symbol) { return boost::apply_visitor(VisitorSymbolId(), symbol); } } //end of xreate namespace /** * \class xreate::TranscendLayer * \brief Reasoning and logic Solver. * * Wraps external brilliant fantastic tool [Clasp solver](https://potassco.org/clasp/) * * For building *logic program* for reasoning TranscendLayer takes input from: * - Raw scripts. Client could append arbitrary ASP script to _logic program_. \ref addRawScript() * - Includes. There is possibility to specify external files with ASP scripts * to append to _logic program_. \ref involveImports() (private member) * - Diagnostic rules. Rules that produce diagnostic messages during * compilation(warnings) or even able to halt compilation with errors. * addRuleWarning(), \ref registerWarning() * - DFA data. \ref setDFAData() * - CFA data. \ref setCFAData() * - Dominators Analysis. See xreate::dominators::DominatorsTreeAnalysisProvider. * Executed by \ref run() * - Context rules. See xreate::ContextRule and general [Context Explanation](/w/concepts/context) * * Data sources implement xreate::IAnalysisReport. Generally, input could be loosely divided into three categories: * - *Internally derived* data. CFA, DFA, Dominators analyses *automatically* feed reasoner by * useful insights about data, structure and algorithms of a program * - *User provided* data. CFA, DFA, Diagnostic/Context rules feed reasoner by * annotations Developer specifically provides manually * - *External* data. Raw scripts and includes feed reasoner with third-party data * related to a different aspects of a program possibly produced by external analyzers * * Once TranscendLayer got input from all providers and logic program is fully constructed * it runs external Clasp reasoner and receives back desired solutions. * * Output of the external Clasp reasoner is recognized and accessed via *queries*. * IQuery represents an interface between reasoner's output and rest of Xreate. * Each query inherits xreate::IQuery interface. Currently there are queries as follows: * - xreate::containers::Query to catch solutions regarding Containers implementation. See [Containers Explanation](/w/concepts/containers) * - xreate::context::ContextQuery to catch solution regarding Context. See [Context Explanation](/w/concepts/context) * * \sa See xreate::dfa::DFAPass, xreate::cfa::CFAPass, xreate::IQuery, xreate::IAnalysisReport, xreate::dominators::DominatorsTreeAnalysisProvider */ diff --git a/cpp/src/transcendlayer.h b/cpp/src/transcendlayer.h index 5f20f89..e52d91d 100644 --- a/cpp/src/transcendlayer.h +++ b/cpp/src/transcendlayer.h @@ -1,316 +1,282 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * File: transcendlayer.h */ #ifndef transcendLAYER_H #define transcendLAYER_H #include "ast.h" #include "contextrule.h" #include #include #include #include #include #include #include #include #include #include namespace xreate { typedef unsigned int ScopePacked; const ScopePacked SCOPE_ABSTRACT_GLOBAL = std::numeric_limits::max(); struct SymbolPacked { SymbolPacked(){} SymbolPacked(ScopedSymbol i, ScopePacked s): identifier(i.id), version(i.version), scope(s){} SymbolPacked(VNameId symbolId, versions::VariableVersion symbolVersion, ScopePacked symbolScope) : identifier(symbolId), version(symbolVersion), scope(symbolScope){} VNameId identifier; versions::VariableVersion version; ScopePacked scope; }; bool operator==(const SymbolPacked& s1, const SymbolPacked& s2); bool operator<(const SymbolPacked& s1, const SymbolPacked& s2); struct SymbolAnonymous { unsigned int id; bool flagIsUsed = false; }; bool operator==(const SymbolAnonymous& s1, const SymbolAnonymous& s2); typedef boost::variant SymbolNode; //DEBT use SymbolGeneralized communicating with Analysis rather than Symbol typedef boost::variant SymbolGeneralized; template<> struct AttachmentsId{ static unsigned int getId(const SymbolGeneralized& symbol); }; } namespace std { template<> struct hash { std::size_t operator()(xreate::SymbolNode const& s) const noexcept; }; template<> struct hash { std::size_t operator()(xreate::SymbolGeneralized const& s) const noexcept; }; } namespace xreate { enum class DFGConnection { STRONG, WEAK, PROTOTYPE }; /** \brief Designated to mark analysis results that can be composed as *logic program* */ class IAnalysisReport { public: /** \brief Composes *logic program* based on analysis data into ASP format and appends to a stream*/ virtual void print(std::ostringstream& output) const = 0; virtual ~IAnalysisReport(){}; }; /** \brief Logic program query interface */ class IQuery { public: virtual void init(TranscendLayer* transcend) = 0; virtual ~IQuery() {} }; enum class QueryId { ContainersQuery, PolymorphQuery }; namespace dfa{ class DFAGraph; } namespace cfa { class CFAGraph; } typedef std::multimap StaticModel; typedef StaticModel::const_iterator StaticModelIterator; -struct GuardedAnnotation{ - std::list, Gringo::Symbol>> guardedSymbols; - boost::optional get(const std::list& keys) const; -}; - -struct LateModel{ - std::unordered_map annotations; - std::unordered_map> bindings; -}; - -//DEBT implement querying as a view/joining iterators without actual data copying -//DEBT how to implement late model RESET(invalidate all child models) -class ReasoningModel{ -public: - ReasoningModel(TranscendLayer* transcendLayer): transcend(transcendLayer) {} - void addLateAtom(const std::string& alias, const SymbolNode& symbol, - const Gringo::Symbol& atom, const std::list& guardKeys, - const std::list& guardBindings); - void addStaticAtom(const std::string& atomAlias, const Gringo::Symbol& atom); - StaticModel queryStatic(const std::string& atom) const; - StaticModel queryLate(const std::string& alias, const SymbolNode& symbol) const; - -private: - TranscendLayer* transcend; - StaticModel modelStatic; - std::map modelGuarded; - std::list findKeys(const std::list& keys) const; -}; - -struct LateBinding; - -template<> -struct AttachmentsDict{ - typedef Expression Data; - static const unsigned int key = 12; -}; - class TranscendLayer { friend class ContextRule; /**\name Data Providers Management */ ///@{ public: void registerReport(IAnalysisReport* report); void runReports(); /** \brief Appends arbitrary string to *logic program* */ void addRawScript(std::string&& script); private: std::list __reports; /** Includes external text files to a *logic program* */ void involveImports(); ///@} /**\name Queries Management */ ///@{ public: /** \brief Adds query. See xreate::IQuery */ IQuery* registerQuery(IQuery* query, const QueryId& id); /** \brief Returns particular query. See xreate::IQuery */ IQuery* getQuery(const QueryId& id); - + template static std::tuple parse(const Gringo::Symbol& atom); - - StaticModel query(const std::string& atom); - const ReasoningModel& queryCompiled(); - + StaticModel query(const std::string& atom) const; size_t getScopesCount() const; SymbolPacked pack(const Symbol& symbol, std::string hintSymbolName = ""); ScopePacked pack(const CodeScope * const scope); - Symbol unpack(const SymbolPacked& symbol); + Symbol unpack(const SymbolPacked& symbol) const; SymbolNode pack(const SymbolGeneralized& symbol, const std::string& hintSymbolName); - SymbolGeneralized unpack(const SymbolNode& symbol); + SymbolGeneralized unpack(const SymbolNode& symbol) const; std::string getHintForPackedSymbol(const SymbolPacked& symbol); ///@} private: std::map __queries; - ReasoningModel __model; std::map __indexSymbolNameHints; std::unordered_map __indexScopes; std::vector __registryScopes; /**\name Diagnostic */ ///@{ //TODO diagnostic move over to separate provider/query public: /** \brief Adds diagnostic rule */ void addRuleWarning(const RuleWarning &rule); /** \brief Registers diagnostic messages */ unsigned int registerWarning(std::string &&message); private: std::map __warnings; void printWarnings(std::ostream& out); ///@} ///@{ public: TranscendLayer(); /** \brief Executes reasoning */ void run(); ///@} AST *ast; -private: +protected: + virtual bool processSolution(Gringo::Model const &model); +private: + StaticModel __model; std::ostringstream __partTags; std::ostringstream __partGeneral; - - bool handleSolution(Gringo::Model const &model); }; template struct ParseImplAtom { static typ get(const Gringo::Symbol& atom) { return atom.num(); } }; template<> struct ParseImplAtom { static int get(const Gringo::Symbol& atom); }; template<> struct ParseImplAtom { static std::string get(const Gringo::Symbol& atom); }; template<> struct ParseImplAtom { static SymbolPacked get(const Gringo::Symbol& atom); }; template<> struct ParseImplAtom { static SymbolNode get(const Gringo::Symbol& atom); }; template<> struct ParseImplAtom { static Gringo::Symbol get(const Gringo::Symbol& atom); }; template struct ParseImplAtom>{ static std::list get(const Gringo::Symbol& atom){ - assert (atom.type() == Gringo::SymbolType::Fun); + bool flagIsList = (atom.type() == Gringo::SymbolType::Fun) && atom.name().empty(); std::list result; + if(!flagIsList) { + //treat as degenerate case: list with a single element + result.push_back(ParseImplAtom::get(atom)); + return result; + } + for (const Gringo::Symbol& arg: atom.args()) { result.push_back(ParseImplAtom::get(arg)); } return result; } }; template<> struct ParseImplAtom { static Expression get(const Gringo::Symbol& atom); }; template struct Parse_Impl { static void parse(Tuple& tup, Gringo::SymSpan::iterator arg) { const size_t tupleSize = std::tuple_size::value; typedef typename std::tuple_element < tupleSize - index, Tuple>::type ElType; ElType& el = std::get < tupleSize - index > (tup); Gringo::Symbol atom = *arg; el = ParseImplAtom::get(atom); Parse_Impl ::parse(tup, ++arg); } }; template struct Parse_Impl { static void parse(Tuple& tup, Gringo::SymSpan::iterator arg) { } }; template std::tuple TranscendLayer::parse(const Gringo::Symbol& atom) { typedef std::tuple < Types...> Tuple; Tuple tup; Parse_Impl::value>::parse(tup, atom.args().first); return tup; } } //end of xreate namespace #endif diff --git a/cpp/src/xreatemanager.cpp b/cpp/src/xreatemanager.cpp index 1b5cddf..fe81268 100644 --- a/cpp/src/xreatemanager.cpp +++ b/cpp/src/xreatemanager.cpp @@ -1,157 +1,156 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * xreatemanager.cpp * * Author: pgess * Created on July 3, 2017, 6:03 PM */ #include "xreatemanager.h" #include "pass/abstractpass.h" -#include "transcendlayer.h" +#include "aux/transcend-decorators.h" #include "aux/xreatemanager-decorators.h" #include "llvmlayer.h" -#include "main/Parser.h" #include #include namespace xreate { void PassManager::registerPass(IPass* pass, const PassId& id, IPass* parent) { __passes.emplace(id, pass); __passDependencies.emplace(parent, pass); } IPass* PassManager::getPassById(const PassId& id){ assert(__passes.count(id)); return __passes[id]; } bool PassManager::isPassRegistered(const PassId& id){ return __passes.count(id); } void PassManager::executePasses(){ std::list passes{nullptr}; while (passes.size()){ IPass* parent = passes.front(); auto range = __passDependencies.equal_range(parent); for (auto i=range.first; i!=range.second; ++i){ IPass* pass = i->second; pass->run(); pass->finish(); passes.push_back(pass); } passes.pop_front(); } } void PassManager::prepare(AST* ast){ root = ast; - transcend = new TranscendLayer(); + transcend = new DefaultTranscendLayerImpl(); transcend->ast = ast; llvm = new LLVMLayer(ast); } PassManager::~PassManager(){} typedef XreateManagerDecoratorFull XreateManagerDecoratorDefault; namespace details{ namespace tier2{ XreateManager* XreateManager::prepare(std::string&& code){ auto man = new XreateManagerImpl; man->prepareCode(std::move(code)); return man; } XreateManager* XreateManager::prepare(FILE* code){ auto man = new XreateManagerImpl; man->prepareCode(code); return man; } }} namespace details { namespace tier1 { XreateManager* XreateManager::prepare(std::string&& code){ auto man = new XreateManagerImpl; man->prepareCode(std::move(code)); return man; } XreateManager* XreateManager::prepare(FILE* code){ auto man = new XreateManagerImpl; man->prepareCode(code); return man; } }} /** * \class xreate::XreateManager * \brief Entry point of Xreate API * * Manages whole Xreate's internal workflow. There are 4 distinctive stages covered by XreateManager: * - initPasses() To init passes * - executePasses() To execute passes * - analyse() To run reasoner * - run() To run compiler * * For adaptability manager comes with several *Frontends*: * - xreate::details::tier2::XreateManager has all stages accessible by client for full control * - xreate::details::tier1::XreateManager has only analyse() and run(), where analyse() combines execution of all previous stages * - xreate::XreateManager has only run() to combine all stages for convenient use * * Moreover there are *Backends*: * - xreate::XreateManagerDecoratorBase Simple backend intended for inheritance without much functionality * - XreateManagerDecoratorFull Backend intended to initialize all builtin passes * * Thus, client's code could combine desired frontend and desired backend as see fit. * Default xreate::XreateManager connects full backend to init all builtin passes * to a simplest frontend with only run() available to execute all stages at once */ /** *\brief Constructs XreateManager for a given code */ XreateManager* XreateManager::prepare(std::string&& code) { auto man = new XreateManagerImpl; man->prepareCode(std::move(code)); return man; } /** *\brief Constructs XreateManager for a given script file */ XreateManager* XreateManager::prepare(FILE* code){ auto man = new XreateManagerImpl; man->prepareCode(code); return man; } } diff --git a/cpp/src/xreatemanager.h b/cpp/src/xreatemanager.h index 1dfdc80..5609a31 100644 --- a/cpp/src/xreatemanager.h +++ b/cpp/src/xreatemanager.h @@ -1,141 +1,141 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * xreatemanager.h * * Author: pgess * Created on July 3, 2017, 6:03 PM */ /** * \file * \brief Entry point of Xreate API. * */ #ifndef PASSMANAGER_H #define PASSMANAGER_H #include #include //stdio external struct _IO_FILE; typedef struct _IO_FILE FILE; namespace xreate { namespace grammar { namespace main { class Scanner; }}} namespace xreate { class IPass; class TranscendLayer; class LLVMLayer; class AST; enum class PassId { - CFGPass, + CFAPass, CompilePass, - DFGPass, + DFAPass, EnvironmentTestsPass, LoggerPass, RulesPass, InterpretationPass, VersionsPass }; /** * \class PassManager * \brief Base class to control passes */ class PassManager{ public: void prepare(AST* ast); void registerPass(IPass* pass, const PassId& id, IPass* prerequisite=nullptr); IPass* getPassById(const PassId& id); bool isPassRegistered(const PassId& id); void executePasses(); virtual ~PassManager(); TranscendLayer* transcend; LLVMLayer* llvm; AST* root; private: std::map __passes; std::multimap __passDependencies; }; namespace details{ namespace tier2{ class XreateManager: public virtual PassManager{ public: virtual ~XreateManager(){}; virtual void initPasses()=0; // virtual void executePasses()=0; virtual void analyse()=0; virtual void* run()=0; static XreateManager* prepare(std::string&& code); static XreateManager* prepare(FILE* code); }; template class XreateManagerImpl: public Decorator { public: }; }} //namespace details::tier2 namespace details{ namespace tier1{ class XreateManager: public virtual PassManager{ public: virtual void analyse()=0; virtual void* run()=0; static XreateManager* prepare(std::string&& code); static XreateManager* prepare(FILE* code); }; template class XreateManagerImpl: public XreateManager, public details::tier2::XreateManagerImpl { typedef details::tier2::XreateManagerImpl PARENT; public: void analyse(){ PARENT::initPasses(); PARENT::executePasses(); PARENT::analyse(); } void* run(){ return PARENT::run(); } }; }} //namespace details::tier1 class XreateManager: public virtual PassManager{ public: virtual void* run()=0; static XreateManager* prepare(std::string&& code); static XreateManager* prepare(FILE* code); }; template class XreateManagerImpl: public XreateManager, public details::tier1::XreateManagerImpl{ typedef details::tier1::XreateManagerImpl PARENT; public: void* run(){ PARENT::analyse(); return PARENT::run(); } }; } //namespace xreate #endif diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt index afac651..8124d0b 100644 --- a/cpp/tests/CMakeLists.txt +++ b/cpp/tests/CMakeLists.txt @@ -1,54 +1,55 @@ cmake_minimum_required(VERSION 2.8.11) project(xreate-tests) find_package(GTest REQUIRED) INCLUDE_DIRECTORIES(${GTEST_INCLUDE_DIRS}) INCLUDE_DIRECTORIES("/usr/include/libxml2") INCLUDE_DIRECTORIES($) # TESTS #========================= FIND_PACKAGE (LLVM REQUIRED) message("LLVM_LIBRARY_DIRS: " ${LLVM_LIBRARY_DIRS}) link_directories(${LLVM_LIBRARY_DIRS}) set (LIBCLASP_PATH ${POTASSCO_PATH}/build/debug) link_directories(${LIBCLASP_PATH}) #aux_source_directory(. TEST_FILES) set(TEST_FILES + transcend.cpp latereasoning.cpp virtualization.cpp exploitation.cpp - communication.cpp + effects-communication.cpp polymorph.cpp association.cpp main.cpp modules.cpp attachments.cpp ast.cpp cfa.cpp dfa.cpp compilation.cpp ExpressionSerializer.cpp externc.cpp types.cpp #vendorsAPI/clangAPI.cpp #vendorsAPI/xml2.cpp #vendorsAPI/json.cpp containers.cpp interpretation.cpp loops.cpp #supplemental/versions-algorithm-data_dependency.cpp effects-versions.cpp ) add_executable(${PROJECT_NAME} ${TEST_FILES}) target_link_libraries(${PROJECT_NAME} xreate ${GTEST_LIBRARIES} pthread xml2 gcov) add_custom_target (coverage COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/src/code-coverage.sh WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/cpp/tests/cfa.cpp b/cpp/tests/cfa.cpp index 1672da0..002cae2 100644 --- a/cpp/tests/cfa.cpp +++ b/cpp/tests/cfa.cpp @@ -1,190 +1,190 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * testsCFG.cpp * * Created on: Jul 17, 2015 * Author: pgess */ #include "xreatemanager.h" #include "pass/dfapass.h" #include "pass/cfapass.h" #include "analysis/DominatorsTreeAnalysisProvider.h" #include "analysis/cfagraph.h" #include "gtest/gtest.h" #include #include using namespace xreate; using namespace xreate::cfa; using namespace std; TEST(CFA, testFunctionAnnotationstranscend){ string&& program = "f2 = function::int; annotationF2 {\n" " 0\n" "}\n" "\n" "f1 = function:: int; entry; annotationF1 {\n" " f2() + 10\n" "}"; details::tier1::XreateManager* man = details::tier1::XreateManager::prepare(move(program)); man->analyse(); StaticModel answer = man->transcend->query("annotationF1"); EXPECT_EQ(1, answer.size()); answer = man->transcend->query("annotationF2"); EXPECT_EQ(1, answer.size()); } TEST(CFA, testLoopContextExists){ details::tier1::XreateManager* man = details::tier1::XreateManager::prepare ( "interface(cfa){\n" " operator fold:: annotation1.\n" "}\n" "\n" "main = function:: int; entry {\n" " x = [1..10]:: [int].\n" " sum = loop fold (x->el:: int, 0->sum):: int {\n" " el + sum + f1()\n" " }. \n" " sum\n" "}" "case context:: annotation1 {" " f1 = function::int {\n" " x = 0:: int. " " x\n" " }" "}" ); man->analyse(); StaticModel model = man->transcend->query("annotation1"); ScopePacked scopeIdActual = std::get<0>(TranscendLayer::parse(model.begin()->second)); CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope(); const Expression& exprSum = scopeEntry->getDefinition(scopeEntry->getSymbol("sum")); CodeScope* scopeExpected = exprSum.blocks.front(); ScopePacked scopeIdExpected = man->transcend->pack(scopeExpected); ASSERT_EQ(scopeIdExpected, scopeIdActual); } TEST(CFA, DependenciesFnCall){ details::tier2::XreateManager* man = details::tier2::XreateManager::prepare( R"Code( a = function::int{ seq {x = 0:: int. x} {x = b():: int. x}::int } b = function::int {y = 0. y} )Code"); CodeScope* scopeSeq1 = man->root->findFunction("a")->getEntryScope()->getBody().blocks.front(); CodeScope* scopeSeq2 = *(++man->root->findFunction("a")->getEntryScope()->getBody().blocks.begin()); CodeScope* scopeB = man->root->findFunction("b")->getEntryScope(); ScopePacked psSeq1 = man->transcend->pack(scopeSeq1); ScopePacked psSeq2 = man->transcend->pack(scopeSeq2); ScopePacked psB = man->transcend->pack(scopeB); CFAPass* pass = new CFAPass(man); - man->registerPass(pass, PassId::CFGPass); + man->registerPass(pass, PassId::CFAPass); man->executePasses(); - const CFAGraph* report = dynamic_cast(man->getPassById(PassId::CFGPass))->getReport(); + const CFAGraph* report = dynamic_cast(man->getPassById(PassId::CFAPass))->getReport(); auto dependencies = report->__dependencyRelations; delete pass; ASSERT_EQ(1, dependencies.count(psSeq2)); ASSERT_EQ(1, dependencies.count(psB)); } TEST(CFA, DependenciesChildScope){ details::tier2::XreateManager* man = details::tier2::XreateManager::prepare( R"Code( a = function::int{ seq {x = 0:: int. x} {x=0::int. if(x>0)::int{1} else {0}}::int } )Code"); CodeScope* scopeSeq1 = man->root->findFunction("a")->getEntryScope()->getBody().blocks.front(); CodeScope* scopeSeq2 = *(++man->root->findFunction("a")->getEntryScope()->getBody().blocks.begin()); CodeScope* scopeIf1 = scopeSeq2->getBody().blocks.front(); CodeScope* scopeIf2 = *(++scopeSeq2->getBody().blocks.begin()); ScopePacked psSeq1 = man->transcend->pack(scopeSeq1); ScopePacked psSeq2 = man->transcend->pack(scopeSeq2); ScopePacked psIf1 = man->transcend->pack(scopeIf1); ScopePacked psIf2 = man->transcend->pack(scopeIf2); CFAPass* pass = new CFAPass(man); - man->registerPass(pass, PassId::CFGPass); + man->registerPass(pass, PassId::CFAPass); man->executePasses(); - const CFAGraph* report = dynamic_cast(man->getPassById(PassId::CFGPass))->getReport(); + const CFAGraph* report = dynamic_cast(man->getPassById(PassId::CFAPass))->getReport(); auto dependencies = report->__dependencyRelations; delete pass; ASSERT_EQ(0, dependencies.count(psSeq1)); ASSERT_EQ(1, dependencies.count(psSeq2)); ASSERT_EQ(1, dependencies.count(psIf1)); ASSERT_EQ(1, dependencies.count(psIf2)); for(auto rec: dependencies) { std::cout << rec.first << " " << rec.second << std::endl; } } TEST(CFA, DomReportOneRoot){ std::string program = R"CODE( a = function:: int; entry{ seq {x = 0:: int. x} {x = 1:: int. x}::int } )CODE"; std::unique_ptr man(details::tier2::XreateManager::prepare(move(program))); CFAPass* pass = new CFAPass(man.get()); - man->registerPass(pass, PassId::CFGPass); + man->registerPass(pass, PassId::CFAPass); pass->run(); ScopePacked scope1 = man->transcend->pack(man->root->findFunction("a")->getEntryScope()->getBody().blocks.front()); ScopePacked scope2 = man->transcend->pack(*++man->root->findFunction("a")->getEntryScope()->getBody().blocks.begin()); dominators::DominatorsTreeAnalysisProvider* providerDomAnalysis = new dominators::DominatorsTreeAnalysisProvider(); providerDomAnalysis->run(pass->getReport()); dominators::DominatorsTreeAnalysisProvider::Dominators expectedFDom= { {1, {0, 3}} ,{2, {1, 2}} }; dominators::DominatorsTreeAnalysisProvider::Dominators expectedPostDom= { {2, {0, 3}} ,{1, {1, 2}} }; auto actualFDom = providerDomAnalysis->getForwardDominators(); auto actualPostDom = providerDomAnalysis->getPostDominators(); ASSERT_EQ(expectedFDom, actualFDom); ASSERT_EQ(expectedPostDom, actualPostDom); delete providerDomAnalysis; delete pass; } diff --git a/cpp/tests/communication.cpp b/cpp/tests/effects-communication.cpp similarity index 100% rename from cpp/tests/communication.cpp rename to cpp/tests/effects-communication.cpp diff --git a/cpp/tests/latereasoning.cpp b/cpp/tests/latereasoning.cpp index 1e3f715..7f307c1 100644 --- a/cpp/tests/latereasoning.cpp +++ b/cpp/tests/latereasoning.cpp @@ -1,109 +1,215 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * latereasoning.cpp * * Author: pgess * Created on April 21, 2018, 5:10 PM */ #include "xreatemanager.h" #include "transcendlayer.h" +#include "pass/latereasoningpass.h" +#include "aux/latereasoning.h" +#include "pass/dfapass.h" #include #include "gtest/gtest.h" using namespace xreate; +using namespace xreate::latereasoning; TEST(LateReasoning, test2) { FILE* input = fopen("scripts/latereasoning/test2.xreate", "r"); assert(input != nullptr); std::unique_ptr man(XreateManager::prepare(input)); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(3, result); } /** * Test plan: * - add late annotation(several variants) * - define late bindings * - get late variant wrt defined bindings **/ TEST(LateReasoning, PutAndGetLateAnnotation1) { #define FORMATSYMBOL(s) (formatSymb % s.identifier % s.version % s.scope).str() + typedef LateReasoningTranscendDecorator LRTranscend; - Attachments::init(); + Attachments::init(); Attachments::init(); - std::unique_ptr transcend(new TranscendLayer()); + std::unique_ptr transcend(new LRTranscend()); std::unique_ptr scope(new CodeScope(nullptr)); Symbol symbA = scope->addDefinition(Atom("a"), Expression()); Symbol symbB = scope->addDefinition(Atom("b"), Expression()); Symbol symbC = scope->addDefinition(Atom("c"), Expression()); Symbol symbTarget = scope->addDefinition(Atom("target"), Expression()); SymbolPacked symbpA = transcend->pack(symbA, "a"); SymbolPacked symbpB = transcend->pack(symbB, "b"); SymbolPacked symbpC = transcend->pack(symbC, "c"); SymbolPacked symbpTarget = transcend->pack(symbTarget, "target"); boost::format formatSymb("s(%1%,%2%,%3%)"); boost::format formatLateAnnotation("late(%1%, (%2%, %3%, %4%), (%5%, %6%, %7%), %8%)."); //Add `variant1` variant transcend->addRawScript((formatLateAnnotation % FORMATSYMBOL(symbpTarget) % FORMATSYMBOL(symbpA) % FORMATSYMBOL(symbpB) % FORMATSYMBOL(symbpC) % "guard1" % "guard1" % "guard1" % "result(variant1)" ). str()); //Add `result2` variant transcend->addRawScript((formatLateAnnotation % FORMATSYMBOL(symbpTarget) % FORMATSYMBOL(symbpA) % FORMATSYMBOL(symbpB) % FORMATSYMBOL(symbpC) % "guard2" % "guard2" % "guard2" % "result(variant2)" ). str()); transcend->run(); //Define keys - Attachments::put(symbA, Expression(Operator::CALL, {Atom("guard2")})); - Attachments::put(symbB, Expression(Operator::CALL, {Atom("guard2")})); - Attachments::put(symbC, Expression(Operator::CALL, {Atom("guard2")})); + Attachments::put(symbA, Expression(Operator::CALL, {Atom("guard2")})); + Attachments::put(symbB, Expression(Operator::CALL, {Atom("guard2")})); + Attachments::put(symbC, Expression(Operator::CALL, {Atom("guard2")})); //Fetch late annotation - ReasoningModel model = transcend->queryCompiled(); - StaticModel answer = model.queryLate("result", symbpTarget); + StaticModel answer = transcend->queryLate("result", symbpTarget); ASSERT_EQ(1, answer.size()); std::tuple answerParsed = transcend->parse(answer.begin()->second); ASSERT_STREQ("variant2", std::get<0>(answerParsed).c_str()); } TEST(LateReasoning, Syntax1) { XreateManager* man = XreateManager::prepare(R"Code( test = function:: int { x = 0::int. y1= switch late (x)::int{0}. y2= switch late(x+y1->a::int)::int{1}. y1+y2 } )Code"); CodeScope* scope = man->root->findFunction("test")->getEntryScope(); Expression y1 = scope->getDefinition(scope->getSymbol("y1")); Expression y2 = scope->getDefinition(scope->getSymbol("y2")); ASSERT_EQ(1, y1.bindings.size()); ASSERT_STRCASEEQ("x", y1.bindings.at(0).c_str()); ASSERT_EQ(1, y2.bindings.size()); ASSERT_STRCASEEQ("a", y2.bindings.at(0).c_str()); } + +TEST(LateReasoning, Compilation1){ + XreateManager* man = XreateManager::prepare(R"Code( +Color = type variant{RED, BLUE, GREEN}. + +test = function:: int; entry { + x = RED():: Color. + y1= switch late (x):: int + {0}. + y1 +} +)Code"); + + int (*program)() = (int (*)())man->run(); + int result = program(); + + ASSERT_EQ(0, result); +} + +TEST(LateReasoning, LateVariablesRecognition1){ + typedef LateReasoningTranscendDecorator LRTranscend; + + auto man = details::tier2::XreateManager::prepare(R"Code( +Dom = type slave dom. + +test = function:: int; entry +{ + LateIdent = 0:: Dom. + 0:: int; ann1(LateIdent) +} +)Code"); + + CodeScope* scopeEntry = man->root->findFunction("test")->getEntryScope(); + ScopedSymbol keyS = scopeEntry->getSymbol("LateIdent"); + SymbolPacked keySP = man->transcend->pack(Symbol{keyS, scopeEntry}); + + std::shared_ptr scopeLateEntry(new LateReasoningScope(nullptr)); + scopeLateEntry->addIdentifier("LateIdent", keySP); + + //Pass information to the late scope + typedef LateReasoningDFAPassDecorator LRDFAPass; + LRDFAPass* dfaPass = new LRDFAPass(man); + dfaPass->registerLateScope(scopeEntry, scopeLateEntry.get()); + + //Pass information to the late model + Attachments::init(); + man->transcend->addRawScript("dom(guard1; guard2).\n"); + Attachments::put(Symbol{keyS, scopeEntry}, Expression(Operator::CALL, {Atom("guard1")})); + + man->registerPass(dfaPass, PassId::DFAPass, nullptr); + man->executePasses(); + man->analyse(); + + //Fetch late annotation + LRTranscend* transcend = dynamic_cast(man->transcend); + SymbolPacked targetSymP = transcend->pack(Symbol{ScopedSymbol::RetSymbol, scopeEntry}); + StaticModel solution = transcend->queryLate("ann1", targetSymP); + ASSERT_EQ(1, solution.size()); + + std::tuple solutionParsed = man->transcend->parse(solution.begin()->second); + ASSERT_STREQ("guard1", std::get<0>(solutionParsed).c_str()); +} + +TEST(LateReasoning, Compilation2){ + auto man = details::tier1::XreateManager::prepare(R"Code( + DomLow = type variant {guard1, guard2}. + Dom = type slave dom. + + guard:: guard1 { + compute = function :: int + {0} + } + + guard:: guard2 { + compute = function :: int + {1} + } + + test = function:: int; entry + { + xLate = guard2():: DomLow. + y1= switch late ((xLate::Dom):: Dom; alias(xLate)):: int + { + compute():: int; guardkey(xLate) + }. + y1 + } + )Code"); + + man->transcend->addRawScript(R"RAW( + dom(guard1; guard2). + late(Target, Key, Variant, dfa_callguard(Variant)):- + bind(Target, guardkey(Alias)); + bind(Key, alias(Alias)); + dom(Variant). + )RAW"); + man->analyse(); + int (*program)() = (int (*)())man->run(); + int result = program(); + + ASSERT_EQ(1, result); +} diff --git a/cpp/tests/main.cpp b/cpp/tests/main.cpp index 5ab9a9b..2df18c6 100644 --- a/cpp/tests/main.cpp +++ b/cpp/tests/main.cpp @@ -1,24 +1,24 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * main.cpp * - * Created on: - + * Created on: 00:00 Xreate Epoch * Author: pgess */ #include "utils.h" #include using namespace std; using namespace xreate; int main(int argc, char **argv) { testing::GTEST_FLAG(color) = "yes"; string testsTemplate = Config::get("tests.template"); string testsFilter = Config::get(string("tests.templates.") + testsTemplate); testing::GTEST_FLAG(filter) = testsFilter; testing::InitGoogleTest(&argc, argv); - + return RUN_ALL_TESTS(); } diff --git a/cpp/tests/polymorph.cpp b/cpp/tests/polymorph.cpp index 226218f..9dd13f5 100644 --- a/cpp/tests/polymorph.cpp +++ b/cpp/tests/polymorph.cpp @@ -1,106 +1,108 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * polymorph.cpp * * Author: pgess * Created on October 11, 2017, 8:37 PM */ #include "xreatemanager.h" #include "ast.h" +#include "transcendlayer.h" +#include "aux/latereasoning.h" #include #include "gtest/gtest.h" -#include "transcendlayer.h" -using namespace std; using namespace xreate; +using namespace xreate::latereasoning; using namespace std; + TEST(Polymorphs, ast1) { xreate::XreateManager* man = xreate::XreateManager::prepare( R"CODE( guard:: a { test = function:: int {0} } guard:: b { test = function:: int {1} } main = function:: int; entry { test() } )CODE"); const std::list& specs = man->root->getFunctionSpecializations("test"); ASSERT_EQ(2, specs.size()); auto itSpecs = specs.begin(); ASSERT_EQ("a", (*itSpecs)->guard.getValueString()); itSpecs++; ASSERT_EQ("b", (*itSpecs)->guard.getValueString()); } TEST(Polymorphs, StaticCall1) { xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"CODE( import raw("scripts/dfa/polymorphism.lp"). guard:: a { test = function:: int {0} } guard:: b { test = function:: int {1} } main = function:: int; entry { test()::int; callguard(b);dfa_polym(ret)} )CODE"); man->analyse(); int (*main)() = (int (*)()) man->run(); ASSERT_EQ(1, main()); } TEST(Polymorphs, LateCall1){ - Attachments::init(); + Attachments::init(); xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"CODE( guard:: a { test = function:: int {0} } guard:: b { test = function:: int {1} } main = function:: int; entry{ key = 0:: int; _guard. if (key == 0)::int { test()::int; dfa_polym(late) } else {0} } )CODE"); man->transcend->addRawScript( R"RULE( late(SymbRet, list(SymbGuard), list(a), dfa_callguard(a)):- bind(SymbRet, dfa_polym(late)); bind(SymbGuard, _guard). late(SymbRet, list(SymbGuard), list(b), dfa_callguard(b)):- bind(SymbRet, dfa_polym(late)); bind(SymbGuard, _guard). )RULE"); man->analyse(); CodeScope* scopeMainBody = man->root->findFunction("main")->getEntryScope(); Symbol symbKey = Symbol{scopeMainBody->getSymbol("key"), scopeMainBody}; - Attachments::put(symbKey, Expression(Operator::CALL, {Atom("b")})); + Attachments::put(symbKey, Expression(Operator::CALL, {Atom("b")})); int (*main)() = (int (*)()) man->run(); ASSERT_EQ(1, main()); } diff --git a/cpp/tests/transcend.cpp b/cpp/tests/transcend.cpp new file mode 100644 index 0000000..5ad0ef3 --- /dev/null +++ b/cpp/tests/transcend.cpp @@ -0,0 +1,43 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * Author: pgess + * Created on June 7, 2018, 3:35 PM + * + * \file transcend.cpp + * \brief Transcend's tests + */ + +#include "xreatemanager.h" +#include "transcendlayer.h" +#include + +using namespace xreate; +using namespace std; + +TEST(Transcend, Parse1) { + std::string script = +R"Code( +)Code"; + + std::unique_ptr man(details::tier1::XreateManager::prepare(std::move(script))); + + std::string scriptTranscend = +R"Code( + test1((1)). + test2((1, 2)). +)Code"; + + man->transcend->addRawScript(move(scriptTranscend)); + man->analyse(); + + StaticModel solution = man->transcend->query("test1"); + Gringo::Symbol symbTest1 = solution.begin()->second; + auto answer1 = man->transcend->parse>(symbTest1); + ASSERT_EQ(1, get<0>(answer1).size()); + + solution = man->transcend->query("test2"); + Gringo::Symbol symbTest2 = solution.begin()->second; + auto answer2 = get<0>(man->transcend->parse>(symbTest2)); + ASSERT_EQ(2, answer2.size()); +} \ No newline at end of file diff --git a/git-commit-template b/git-commit-template new file mode 100644 index 0000000..94da945 --- /dev/null +++ b/git-commit-template @@ -0,0 +1,12 @@ + + +Syntax: +Transcend: +Compilation: +Documentation: <...> +: <...> + +Malfunctions: + +Tests: + diff --git a/grammar/xreate.ATG b/grammar/xreate.ATG index 77cf607..4947344 100644 --- a/grammar/xreate.ATG +++ b/grammar/xreate.ATG @@ -1,664 +1,676 @@ //TODO add ListLiteral //TODO ExprTyped: assign default(none) type #include "ast.h" #include "ExternLayer.h" #include #include #define wprintf(format, ...) \ char __buffer[100]; \ wcstombs(__buffer, format, 100); \ fprintf(stderr, __buffer, __VA_ARGS__) using namespace std; COMPILER Xreate details::inconsistent::AST* root = nullptr; // current program unit void ensureInitalizedAST(){ if (root == nullptr) root = new details::inconsistent::AST(); } struct { std::stack scopesOld; CodeScope* scope = nullptr; } context; void pushContextScope(CodeScope* scope){ context.scopesOld.push(context.scope); context.scope = scope; } void popContextScope(){ context.scope = context.scopesOld.top(); context.scopesOld.pop(); } int nextToken() { scanner->ResetPeek(); return scanner->Peek()->kind; } bool checkTokenAfterIdent(int key){ if (la->kind != _ident) return false; return nextToken() == key; } bool checkParametersList() { return la->kind == _ident && nextToken() == _lparen; } bool checkInfix() { return la->kind == _ident && nextToken() == _ident; } bool checkIndex() { return la->kind == _ident && nextToken() == _lbrack; } bool checkFuncDecl() { if (la->kind != _ident) return false; int token2 = nextToken(); int token3 = scanner->Peek()->kind; return token2 == _assign && (token3 == _function || token3 == _pre); } bool checkAssignment() { if (la->kind != _ident) return false; scanner->ResetPeek(); int token2 = scanner->Peek()->kind; if (token2 == _lcurbrack) { scanner->Peek(); int token3 = scanner->Peek()->kind; if (token3 != _rcurbrack) return false; int token4 = scanner->Peek()->kind; return token4 == _assign; } return token2 == _assign; } void recognizeIdentifier(Expression& i){ if (!context.scope->recognizeIdentifier(i)){ root->postponeIdentifier(context.scope, i); } } enum SwitchKind{SWITCH_NORMAL, SWITCH_META}; CHARACTERS letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". any = ANY - '"'. digit = "0123456789". cr = '\r'. lf = '\n'. tab = '\t'. TOKENS ident = (letter | '_') {letter | digit | '_'}. number = (digit | '-' digit) {digit}. string = '"' { any } '"'. function = "function". pre = "pre". + comma = ','. + period = '.'. lparen = '('. rparen = ')'. lbrack = '['. rbrack = ']'. lcurbrack = '{'. rcurbrack = '}'. equal = "==". assign = '='. implic = '-' '>'. colon = ':'. context = "context". tagcolon = "::". lse = "<=". lss = "<". gte = ">=". gtr = ">". ne1 = "!=". ne2= "<>". COMMENTS FROM "/*" TO "*/" NESTED COMMENTS FROM "//" TO lf IGNORE cr + lf + tab PRODUCTIONS Xreate = (. Function* function; ensureInitalizedAST(); .) {( RuleDecl | InterfaceData | Imprt | GuardSection | IF(checkFuncDecl()) FDecl (. root->add(function); .) | TDecl | SkipModulesSection )} (. .) . Ident = ident (. name = t->val; .). VarIdent = ident (. e = Expression(Atom(t->val)); .) [ lcurbrack ( ident (. SemErr(coco_string_create("var version as ident is not implemented yet")); .) | number (. Attachments::put(e, Atom(t->val).get()); .) ) rcurbrack ] . FDecl = (. std::wstring fname; std::wstring argName; TypeAnnotation typIn; TypeAnnotation typOut; bool flagIsPrefunct = false; Expression binding; .) Ident assign [pre (. flagIsPrefunct = true; .)] function (. f = new Function(fname); f->isPrefunction = flagIsPrefunct; CodeScope* entry = f->getEntryScope(); .) -['(' Ident tagcolon ExprAnnotations (. f->addBinding(Atom(argName), move(binding)); .) -{',' Ident tagcolon ExprAnnotations (. f->addBinding(Atom (argName), move(binding));.) -} ')'] +[lparen Ident tagcolon ExprAnnotations (. f->addBinding(Atom(argName), move(binding)); .) +{comma Ident tagcolon ExprAnnotations (. f->addBinding(Atom (argName), move(binding));.) +} rparen] [ tagcolon ( IF(flagIsPrefunct) FnTag | Type ) {';' FnTag }] BDecl (. const_cast(entry->getBody()).bindType(move(typOut));.) . GuardSection<>= (. Expression guard; Function* f; .) "guard" tagcolon MetaSimpExpr lcurbrack { FDecl (. f->guard = guard; root->add(f); .) } rcurbrack. /** * TYPES * */ TypeTerm = (. std::wstring tid; .) ("string" (. typ = TypePrimitive::String;.) | "num" (. typ = TypePrimitive::Num;.) | "int" (. typ = TypePrimitive::Int;.) | "float" (. typ = TypePrimitive::Float;.) | "bool" (. typ = TypePrimitive::Bool; .) | "i8" (. typ = TypePrimitive::I8; .) | "i32" (. typ = TypePrimitive::I32; .) | "i64" (. typ = TypePrimitive::I64; .) ). Type = (. TypeAnnotation typ2; TypePrimitive typ3; std::wstring tid, field; .) ( TList | TStruct | TVariant +| TSlave | TypeTerm (. typ = typ3; .) | IF (checkIndex()) Ident lbrack Ident (. typ = TypeAnnotation(TypeOperator::ACCESS, {}); typ.__valueCustom = Atom(tid).get(); typ.fields.push_back(Atom(field).get()); .) - {',' Ident (. typ.fields.push_back(Atom(field).get()); .) + {comma Ident (. typ.fields.push_back(Atom(field).get()); .) } rbrack | Ident (. typ = TypeAnnotation(TypeOperator::CUSTOM, {}); typ.__valueCustom = Atom(tid).get(); .) - ['(' Type (. typ.__operator = TypeOperator::CALL; typ.__operands.push_back(typ2); .) - {',' Type (. typ.__operands.push_back(typ2); .) - } ')'] + [lparen Type (. typ.__operator = TypeOperator::CALL; typ.__operands.push_back(typ2); .) + {comma Type (. typ.__operands.push_back(typ2); .) + } rparen] ) . TList = (. TypeAnnotation ty; .) - '[' Type ']' (. typ = TypeAnnotation(TypeOperator::LIST, {ty}); .) + lbrack Type rbrack (. typ = TypeAnnotation(TypeOperator::LIST, {ty}); .) . TStruct = (. TypeAnnotation t; std::wstring key; size_t keyCounter=0; .) lcurbrack ( IF(checkTokenAfterIdent(_tagcolon)) Ident tagcolon Type | Type (. key = to_wstring(keyCounter++); .) ) (. typ = TypeAnnotation(TypeOperator::LIST_NAMED, {t}); typ.fields.push_back(Atom(key).get()); .) - {',' ( + {comma ( IF(checkTokenAfterIdent(_tagcolon)) Ident tagcolon Type | Type (. key = to_wstring(keyCounter++); .) ) (. typ.__operands.push_back(t); typ.fields.push_back(Atom(key).get()); .) } rcurbrack. TVariant= (. TypeAnnotation t, typVoid(TypeOperator::LIST_NAMED, {}); std::vector operands; std::vector> keys; std::wstring variant; .) "variant" lcurbrack Ident (. t=typVoid; .) [tagcolon Type] (. keys.push_back(Atom(variant)); operands.push_back(t); .) - {',' Ident (. t=typVoid; .) + {comma Ident (. t=typVoid; .) [tagcolon Type] (. keys.push_back(Atom(variant)); operands.push_back(t); .) } rcurbrack (. typ = TypeAnnotation(TypeOperator::VARIANT, {}); typ.__operands = operands; typ.addFields(std::move(keys)); .) -. +. - TDecl = (. TypeAnnotation t; std::wstring tname, arg; std::vector> args; .) - Ident assign "type" - ['(' Ident (. args.push_back(Atom(arg)); .) - {',' Ident (. args.push_back(Atom(arg)); .) - } ')'] - Type'.' (. t.addBindings(move(args)); root->add(move(t), Atom(tname)); .) - . +TSlave= (. std::wstring identMaster; .) + "slave" Ident (. typ = TypeAnnotation(TypeOperator::SLAVE, {}); typ.__valueCustom = Atom(identMaster).get(); .) +. + +TDecl = (. TypeAnnotation t; std::wstring tname, arg; std::vector> args; .) + Ident assign "type" + [lparen Ident (. args.push_back(Atom(arg)); .) + {comma Ident (. args.push_back(Atom(arg)); .) + } rparen] + Typeperiod (. t.addBindings(move(args)); root->add(move(t), Atom(tname)); .) + . ContextDecl = (. Expression tag; .) context tagcolon MetaSimpExpr (. scope->tags.push_back(tag); .) {';' MetaSimpExpr (. scope->tags.push_back(tag); .) }. VDecl = (. std::wstring vname; Expression var, value;.) VarIdent assign ExprTyped (. Symbol identSymbol = f->addDefinition(move(var), move(value)); Attachments::put(value, identSymbol); .) . BDecl = lcurbrack (. Expression body; pushContextScope(scope); .) - {(IF(checkAssignment()) VDecl '.' + {(IF(checkAssignment()) VDecl period | RuleContextDecl - | ContextDecl'.' + | ContextDeclperiod | ExprTyped (. scope->setBody(body); Attachments::put(body, Symbol{ScopedSymbol::RetSymbol, scope});.) )} rcurbrack (. popContextScope(); .) . IfDecl = (. Expression cond; ManagedScpPtr blockTrue = root->add(new CodeScope(context.scope)); ManagedScpPtr blockFalse = root->add(new CodeScope(context.scope)); .) -"if" '(' Expr ')' (. e = Expression(Operator::IF, {cond}); .) +"if" lparen Expr rparen (. e = Expression(Operator::IF, {cond}); .) tagcolon ExprAnnotations BDecl<&*blockTrue> "else" BDecl<&*blockFalse> (. e.addBlock(blockTrue); e.addBlock(blockFalse); .) . LoopDecl = (. Expression eIn, eAcc, eFilters; std::wstring varEl, varAcc, contextClass; Expression tagsEl; ManagedScpPtr block = root->add(new CodeScope(context.scope)); .) "loop" - ("map" '(' Expr implic Ident (. e = Expression(Operator::MAP, {eIn}); .) - tagcolon ExprAnnotations ')' tagcolon ExprAnnotations + ("map" lparen Expr implic Ident (. e = Expression(Operator::MAP, {eIn}); .) + tagcolon ExprAnnotations rparen tagcolon ExprAnnotations (. e.addBindings({Atom(varEl)}); block->addBinding(Atom(varEl), move(tagsEl)); .) BDecl<&*block> (. e.addBlock(block); .) |"fold" - ("inf" '(' Expr implic Ident ')' + ("inf" lparen Expr implic Ident rparen (. e = Expression(Operator::FOLD_INF, {eAcc}); e.addBindings({Atom(varAcc)}); block->addBinding(Atom(varAcc), Expression()); .) tagcolon ExprAnnotations BDecl<&*block> (. e.addBlock(block); .) - | '(' Expr implic Ident tagcolon ExprAnnotations ['|' Expr ] ',' Expr implic Ident')' + | lparen Expr implic Ident tagcolon ExprAnnotations ['|' Expr ] comma Expr implic Identrparen (. e = Expression(Operator::FOLD, {eIn, eAcc}); e.addBindings({Atom(varEl), Atom(varAcc)}); .) tagcolon ExprAnnotations (. block->addBinding(Atom(varEl), move(tagsEl)); block->addBinding(Atom(varAcc), Expression()); .) BDecl<&*block> (. e.addBlock(block); .) ) ). // Switches SwitchDecl = (. TypeAnnotation typ; eSwitch = Expression(Operator::SWITCH, {}); Expression eCondition; Expression tag;.) "switch" ( SwitchVariantDecl | SwitchLate | lparen ExprTyped rparen tagcolon ExprAnnotations (. eSwitch.operands.push_back(eCondition);.) CaseDecl {CaseDecl} ) . CaseDecl = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); Expression condition; .) "case" ( IF(flagSwitchKind == SWITCH_META) lparen MetaSimpExpr rparen BDecl<&*scope> (. Expression exprCase(Operator::CASE, {}); exprCase.addTags({condition}); exprCase.addBlock(scope); outer.addArg(move(exprCase));.) | "default" BDecl<&*scope> (. Expression exprCase(Operator::CASE_DEFAULT, {}); exprCase.addBlock(scope); outer.operands.insert(++outer.operands.begin(), exprCase); .) | lparen CaseParams<&*scope> rparen (. ManagedScpPtr scopeBody = root->add(new CodeScope(&*scope)); Expression exprCase(Operator::CASE, {}); .) BDecl<&*scopeBody> (. exprCase.addBlock(scope); exprCase.addBlock(scopeBody); outer.addArg(move(exprCase)); .) ). CaseParams = (. Expression condition; Expression guard(Operator::LOGIC_AND, {}); pushContextScope(scope); .) ExprTyped (. guard.addArg(Expression(condition)); .) - {',' ExprTyped (. guard.addArg(Expression(condition)); .) + {comma ExprTyped (. guard.addArg(Expression(condition)); .) } (. scope->setBody(guard); popContextScope(); .) . SwitchLate = (. - std::wstring aliasCondition; Expression exprCondition; + std::wstring aliasCondition; Expression exprCondition, aliasAnns; expr = Expression(Operator::SWITCH_LATE, {}); ManagedScpPtr scope = root->add(new CodeScope(context.scope)); .) - "late" lparen Expr [implic Ident] [tagcolon ExprAnnotations] rparen + "late" lparen Expr [implic Ident] [tagcolon ExprAnnotations] rparen tagcolon ExprAnnotations BDecl<&*scope> (. - expr.addArg(Expression(exprCondition)); + expr.addArg(Expression(exprCondition)); + expr.addBlock(scope); + std::string alias; if(aliasCondition.empty()){ if(exprCondition.__state != Expression::IDENT){ SemErr(coco_string_create("An identifier expected in the short form")); return; } - //Use exprCondition as id - expr.addBindings({Atom(string(exprCondition.getValueString()))}); + //Use exprCondition as identifier + alias = exprCondition.getValueString(); } else { //Use aliasCondition - expr.addBindings({Atom(aliasCondition)}); + alias = Atom(move(aliasCondition)).get(); } + + expr.addBindings({Atom(string(alias))}); + scope->addBinding(Atom(move(alias)), move(aliasAnns)); .) . SwitchVariantDecl = (. Expression varTested; std::wstring varAlias; bool flagAliasFound = false; expr = Expression(Operator::SWITCH_VARIANT, {}); .) "variant" lparen Expr [implic Ident (. flagAliasFound = true; .) ] [tagcolon ExprAnnotations] rparen tagcolon ExprAnnotations (. expr.addArg(std::move(varTested)); if (flagAliasFound) { expr.addBindings({Atom(varAlias)}); } else { if(varTested.__state == Expression::IDENT){ expr.addBindings({Atom(string(varTested.getValueString()))}); } } .) CaseVariantDecl {CaseVariantDecl} . CaseVariantDecl = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); std::wstring key; scope->addBinding(Atom(string(expr.bindings.front())), Expression()); .) "case" lparen Ident rparen (. expr.addArg(root->recognizeVariantConstructor(Atom(std::move(key)))); .) BDecl<&*scope> (. expr.addBlock(scope); .) . IntrinsicDecl= (. std::wstring name; .) "intrinsic" Ident< name> (. outer = Expression(Operator::CALL_INTRINSIC, {}); outer.setValue(Atom(name)); .) lparen [CalleeParams] rparen . SequenceDecl = (. sequence = Expression(); sequence.setOp(Operator::SEQUENCE); ManagedScpPtr scope = root->add(new CodeScope(context.scope)); .) "seq" BDecl<&*scope> (. sequence.blocks.push_back(&*scope); scope = root->add(new CodeScope(&*scope)); .) { (. scope = root->add(new CodeScope(&*scope)); .) BDecl<&*scope> (. sequence.blocks.push_back(&*scope); .) }. /*============================ INTERFACES ===============================*/ Imprt<> = "import" "raw" lparen string (. root->__rawImports.push_back(Atom(t->val).get()); .) -rparen '.'. +rparen period. -InterfaceData<> = "interface" '(' - ( "dfa" ')' InterfaceDFA - | "extern-c" ')' InterfaceExternC - | "cfa" ')' InterfaceCFA +InterfaceData<> = "interface" lparen + ( "dfa" rparen InterfaceDFA + | "extern-c" rparen InterfaceExternC + | "cfa" rparen InterfaceCFA ). InterfaceExternC<> = (. ExternData data; .) - '{' {IncludeExternDecl | LibExternDecl } '}' + lcurbrack {IncludeExternDecl | LibExternDecl } rcurbrack (. root->addExternData(move(data)); .) . LibExternDecl = (. std::wstring pkgname, libname; .) Ident assign "library" tagcolon "pkgconfig" - '(' string (. pkgname = t->val; .) - ')' '.' (. data.addLibrary(Atom(libname), Atom(pkgname)); .) + lparen string (. pkgname = t->val; .) + rparen period (. data.addLibrary(Atom(libname), Atom(pkgname)); .) . IncludeExternDecl = (. Expression inc; .) - "include" StructLiteral '.' (. data.addIncludeDecl(move(inc)); .) + "include" StructLiteral period (. data.addIncludeDecl(move(inc)); .) . -InterfaceDFA<> = '{' { InstructDecl } '}' . +InterfaceDFA<> = lcurbrack { InstructDecl } rcurbrack . InstructDecl = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; tags.push_back(Expression()); /* return value */ .) -"operator" InstructAlias tagcolon '(' (.scheme.setOp(op); .) +"operator" InstructAlias tagcolon lparen (.scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { - ',' MetaSimpExpr (. tags.push_back(tag); .) + comma MetaSimpExpr (. tags.push_back(tag); .) } -] ')' [ implic MetaSimpExpr (. tags[0] = tag; .) +] rparen [ implic MetaSimpExpr (. tags[0] = tag; .) ] (. root->addDFAData(move(scheme)); .) -'.'. +period. InstructAlias = ( "map" (. op = Operator::MAP; .) | "list_range" (. op = Operator::LIST_RANGE; .) | "list" (. op = Operator::LIST; .) | "fold" (. op = Operator::FOLD; .) | "index" (. op = Operator::INDEX; .) ). -InterfaceCFA<> = '{' { InstructCFADecl } '}' . +InterfaceCFA<> = lcurbrack { InstructCFADecl } rcurbrack . InstructCFADecl<> = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; .) "operator" InstructAlias tagcolon (. scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { - ',' MetaSimpExpr (. tags.push_back(tag); .) + comma MetaSimpExpr (. tags.push_back(tag); .) } -] '.' (. root->addInterfaceData(CFA, move(scheme)); .). +] period (. root->addInterfaceData(CFA, move(scheme)); .). /*============================ METAPROGRAMMING ===============================*/ // TagsDecl = (. Expression tag; TagModifier mod = TagModifier::NONE; .) // ':' { MetaSimpExpr (. /*f.addTag(std::move(tag), mod); */ .) // }. FnTag = (. Expression tag; TagModifier mod = TagModifier::NONE; .) MetaSimpExpr ['-' TagMod] (. f->addTag(std::move(tag), mod); .). TagMod = ( "assert" (. mod = TagModifier::ASSERT; .) | "require" (. mod = TagModifier::REQUIRE; .) ). RuleDecl<> = "rule" tagcolon (. RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg; .) -'(' Ident tagcolon Domain (. args.add(arg, typ); .) -{',' Ident tagcolon Domain (. args.add(arg, typ); .) -} ')' -["case" RGuard {',' RGuard}] -'{' RBody '}' . +lparen Ident tagcolon Domain (. args.add(arg, typ); .) +{comma Ident tagcolon Domain (. args.add(arg, typ); .) +} rparen +["case" RGuard {comma RGuard}] +lcurbrack RBody rcurbrack . /* - TODO use RGuard for guards-*/ RuleContextDecl = (.Expression eHead, eGuards, eBody; .) "rule" "context" tagcolon MetaSimpExpr "case" lparen MetaSimpExpr rparen -'{' MetaSimpExpr '}' (.scope->contextRules.push_back(Expression(Operator::CONTEXT_RULE, {eHead, eGuards, eBody})); .). +lcurbrack MetaSimpExpr rcurbrack (.scope->contextRules.push_back(Expression(Operator::CONTEXT_RULE, {eHead, eGuards, eBody})); .). Domain = ( "function" (. dom = DomainAnnotation::FUNCTION; .) | "variable" (. dom = DomainAnnotation::VARIABLE; .) ). RGuard= (. Expression e; .) MetaExpr (. guards.add(std::move(e)); .). MetaExpr= (.Operator op; Expression e2; .) MetaExpr2 [MetaOp MetaExpr2 (. e = Expression(op, {e, e2}); .) ]. MetaExpr2= ( -'(' MetaExpr ')' +lparen MetaExpr rparen | MetaSimpExpr ). MetaSimpExpr= (. std::wstring i1, infix; Expression e2; .) ( '-' MetaSimpExpr (. e = Expression(Operator::NEG, {e2}); .) | IF(checkParametersList()) Ident (. e = Expression(Operator::CALL, {Expression(Atom(i1))}); .) -'(' [ MetaCalleeParams ] ')' +lparen [ MetaCalleeParams ] rparen | IF(checkInfix()) Ident Ident MetaSimpExpr (. e = Expression(Operator::CALL, {Expression(Atom(infix))}); e.addArg(Expression(Atom(i1))); e.addArg(std::move(e2)); .) | Ident (. e = Expression(Operator::CALL, {Atom(i1)}); .) ). MetaCalleeParams = (. Expression e2; .) MetaSimpExpr (. e.addArg(Expression(e2)); .) - {',' MetaSimpExpr (. e.addArg(Expression(e2)); .) + {comma MetaSimpExpr (. e.addArg(Expression(e2)); .) }. RBody = (. Expression e; std::wstring msg; .) "warning" MetaExpr ["message" string (. msg = t->val; .) ] (. root->add(new RuleWarning(RuleArguments(args), RuleGuards(guards), std::move(e), Atom(msg))); .) . MetaOp< Operator& op> = implic (. op = Operator::IMPL; .) . /*============================ Expressions ===============================*/ ExprAnnotations = (. TypeAnnotation typ; std::list tags; Expression tag; e.tags.clear();.) Type (. e.bindType(move(typ)); .) {';' MetaSimpExpr (. tags.push_back(tag); .) } (. e.addTags(tags); .) . ExprTyped = Expr [tagcolon ExprAnnotations]. Expr< Expression& e> (. Operator op; Expression e2; .) = ExprArithmAdd [ RelOp ExprArithmAdd (. e = Expression(op, {e, e2}); .) ]. ExprArithmAdd< Expression& e>= (. Operator op; Expression e2; .) ExprArithmMul< e> [ AddOp< op> ExprArithmAdd< e2> (. e = Expression(op, {e, e2});.) ]. ExprArithmMul< Expression& e> (. Operator op; Expression e2; .) = ExprPostfix< e> [ MulOp< op> ExprArithmMul< e2> (. e = Expression(op, {e, e2}); .) ]. ExprPostfix = Term [ (. e = Expression(Operator::INDEX, {e}); .) {lbrack CalleeParams rbrack } ]. Term< Expression& e> (. std::wstring name; e = Expression(); .) = (IF (checkParametersList()) Ident< name> (. e = Expression(Operator::CALL, {Atom(name)}); root->recognizeVariantConstructor(e); .) - '(' [CalleeParams] ')' + lparen [CalleeParams] rparen | VarIdent (. recognizeIdentifier(e); .) | ListLiteral (. /* tuple */.) | StructLiteral (. /* struct */.) | LoopDecl | IfDecl | SwitchDecl | IntrinsicDecl | SequenceDecl | number (. e = Expression(Atom(t->val)); .) | string (. e = Expression(Atom(t->val)); .) | "true" (. e = Expression(Atom(1)); e.bindType(TypePrimitive::Bool); .) | "false" (. e = Expression(Atom(0)); e.bindType(TypePrimitive::Bool); .) | "undef" (. e = Expression(Operator::UNDEF, {}); .) | '-' Term (. e = Expression(Operator::NEG, {e}); .) - | '(' ExprTyped ')' + | lparen ExprTyped rparen ). StructLiteral = (. std::wstring key; Expression val; std::list> keys; size_t keyCounter=0; .) lcurbrack - (IF(checkTokenAfterIdent(_assign)) Ident '=' Expr + (IF(checkTokenAfterIdent(_assign)) Ident assign Expr | Expr (. key = to_wstring(keyCounter++); .) ) (. keys.push_back(Atom(key)); e = Expression(Operator::LIST_NAMED, {val}); .) - {',' (IF(checkTokenAfterIdent(_assign)) Ident '=' Expr + {comma (IF(checkTokenAfterIdent(_assign)) Ident assign Expr | Expr (. key = to_wstring(keyCounter++); .) ) (. e.addArg(Expression(val)); keys.push_back(Atom(key)); .) } rcurbrack (. e.addBindings(keys.begin(), keys.end()); .) . ListLiteral = (. Expression eFrom, eTo; .) -'[' (. e.setOp(Operator::LIST); .) +lbrack (. e.setOp(Operator::LIST); .) [ Expr (. e.addArg(Expression(eFrom)); .) ( ".." Expr (. e.addArg(Expression(eTo)); e.setOp(Operator::LIST_RANGE); .) - |{',' Expr (. e.addArg(Expression(eFrom)); .) + |{comma Expr (. e.addArg(Expression(eFrom)); .) } ) ] -']'. +rbrack. CalleeParams = (. Expression e2; .) ExprTyped (. e.addArg(Expression(e2)); .) - {',' ExprTyped (. e.addArg(Expression(e2)); .) + {comma ExprTyped (. e.addArg(Expression(e2)); .) }. AddOp< Operator& op> = (. op = Operator::ADD; .) ( '+' | '-' (. op = Operator::SUB; .) ). MulOp< Operator& op> = (. op = Operator::MUL; .) ( '*' | '/' (. op = Operator::DIV; .) ). RelOp< Operator& op> = (. op = Operator::EQU; .) ( equal | (ne1 | ne2) (. op = Operator::NE; .) | lse (. op = Operator::LSE; .) | lss (. op = Operator::LSS; .) | gte (. op = Operator::GTE; .) | gtr (. op = Operator::GTR; .) ). -SkipModulesSection = "module" '{' {ANY} '}'. +SkipModulesSection = "module" lcurbrack {ANY} rcurbrack. END Xreate.