diff --git a/config/default.json b/config/default.json index 1fda882..04ec9d5 100644 --- a/config/default.json +++ b/config/default.json @@ -1,70 +1,69 @@ { "containers": { "id": { "implementations": "impl_fulfill_cluster", "clusters": "var_cluster", "prototypes": "proto_cluster", "linkedlist": "linkedlist" }, "impl": { "solid": "solid", "onthefly": "on_the_fly" } }, "logging": { "id": "logging" }, "function-entry": "entry", "clasp": { "bindings" : { "variable": "bind", "function": "bind_func", "scope": "bind_scope", "function_demand" : "bind_function_demand", "scope_decision": "bind_scope_decision" }, "context" : { "decisions":{ "dependent": "resolution_dependency" }, }, "nonevalue": "nonevalue", "ret": { "symbol": "retv", "tag": "ret" } }, "tests": { "template": "default", "templates": { "default": "*-", - + "ast": "AST.*", "adhocs": "Adhoc.*", "effects": "Effects.*", "basic": "Attachments.*", - "ast": "AST.*", + "context": "Context.*", + "compilation": "Compilation.*", "cfa": "CFA.*", + "containers": "Containers.*", "dfa": "DFA.*", - "compilation": "Compilation.*", "diagnostic": "Diagnostic.*", + "dsl": "Interpretation.*:InterpretationExamples.*", "ExpressionSerializer": "ExpressionSerializer.*", "externc": "InterfaceExternC.*", + "loops": "Loop.*", + "modules": "Modules.*", "types": "Types.*-", "vendorsAPI/clang": "ClangAPI.*", - "vendorsAPI/xml2": "libxml2*", - "dsl": "Interpretation.*:InterpretationExamples.*", - "context": "Context.*", - "containers": "Containers.*", - "loops": "Loop.*", - "modules": "Modules.*" + "vendorsAPI/xml2": "libxml2*" } } } diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index de1b0c3..9f4c71a 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -1,229 +1,229 @@ cmake_minimum_required(VERSION 2.8.11) project(xreate) cmake_policy(SET CMP0022 NEW) message("MODULES" ${CMAKE_MODULE_PATH}) # LLVM #====================== FIND_PACKAGE (LLVM REQUIRED) set(LLVM_VERSION ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message("LLVM LIB PATH:" ${LLVM_LIBRARY_DIRS}) message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") INCLUDE_DIRECTORIES(${LLVM_INCLUDE_DIRS}) message(STATUS "INCLUDE DIR: ${LLVM_INCLUDE_DIRS}") add_definitions(${LLVM_DEFINITIONS}) message("LLVM DEFS: " ${LLVM_DEFINITIONS}) llvm_map_components_to_libnames(LLVM_LIBS core nativecodegen native executionengine mcjit support option) message("LLVM LIBS: " ${LLVM_LIBS}) # CLANG #====================== set(CLANG_LIBS clangCodeGen clangASTMatchers clangQuery clangTooling clangFrontend clangSerialization clangDriver clangParse clangSema clangAnalysis clangAST clangEdit clangLex clangBasic ) # POTASSCO #====================== set(POTASSCO_PATH "/opt/potassco/clingo" CACHE PATH "Path to potassco sources") set(POTASSCO_INCLUDE_PATH ${POTASSCO_PATH}/libgringo ${POTASSCO_PATH}/libclasp ${POTASSCO_PATH}/libclingo ${POTASSCO_PATH}/libprogram_opts ${POTASSCO_PATH}/liblp ) INCLUDE_DIRECTORIES(${POTASSCO_INCLUDE_PATH}) set(LIBCLASP_LIBS clingo clasp gringo program_opts reify lp ) message("CLASP LIBS: " ${LIBCLASP_LIBS}) # OTHER DEPENDENCIES #=========================== set(JEAYESON_INCLUDE_PATH ${CMAKE_HOME_DIRECTORY}/../vendors/jeayeson/include/ ) INCLUDE_DIRECTORIES(${JEAYESON_INCLUDE_PATH}) # COCO #=========================== set(COCO_EXECUTABLE "" CACHE PATH "Path to coco executable") set(COCO_FRAMES_PATH "" CACHE PATH "Path to coco frames") set(COCO_GRAMMAR_PATH ${CMAKE_HOME_DIRECTORY}/../grammar/) set(COCO_SOURCE_FILES_MAIN ${COCO_GRAMMAR_PATH}/main/Parser.cpp ${COCO_GRAMMAR_PATH}/main/Scanner.cpp ) set(COCO_SOURCE_FILES_MODULES ${COCO_GRAMMAR_PATH}/modules/Parser.cpp ${COCO_GRAMMAR_PATH}/modules/Scanner.cpp ) set(COCO_SOURCE_FILES ${COCO_SOURCE_FILES_MODULES} ${COCO_SOURCE_FILES_MAIN}) INCLUDE_DIRECTORIES(${COCO_GRAMMAR_PATH}) add_custom_command(OUTPUT ${COCO_SOURCE_FILES_MAIN} COMMAND ${COCO_GRAMMAR_PATH}/gen-grammar main ${COCO_EXECUTABLE} ${COCO_FRAMES_PATH} WORKING_DIRECTORY ${COCO_GRAMMAR_PATH} MAIN_DEPENDENCY ${COCO_GRAMMAR_PATH}/xreate.ATG ) add_custom_command(OUTPUT ${COCO_SOURCE_FILES_MODULES} COMMAND ${COCO_GRAMMAR_PATH}/gen-grammar modules ${COCO_EXECUTABLE} ${COCO_FRAMES_PATH} WORKING_DIRECTORY ${COCO_GRAMMAR_PATH} MAIN_DEPENDENCY ${COCO_GRAMMAR_PATH}/modules.ATG ) message(STATUS "COCO GRAMMAR BUILD STATUS:" ${COCO_OUTPUT}) # XREATE #====================== set(SOURCE_FILES modules.cpp ast.cpp xreatemanager.cpp analysis/typeinference.cpp - misc/xreatemanager-decorators.cpp + aux/xreatemanager-decorators.cpp compilation/operators.cpp compilation/transformations.cpp compilation/transformersaturation.cpp pass/compilepass.cpp pass/dfapass.cpp analysis/dfagraph.cpp pass/versionspass.cpp compilation/targetinterpretation.cpp attachments.cpp ExternLayer.cpp analysis/cfagraph.cpp analysis/aux.cpp compilation/containers.cpp compilation/advanced.cpp clasplayer.cpp compilation/latecontextcompiler2.cpp query/context.cpp llvmlayer.cpp utils.cpp pass/abstractpass.cpp pass/cfapass.cpp pass/adhocpass.cpp contextrule.cpp query/containers.cpp pass/interpretationpass.cpp analysis/DominatorsTreeAnalysisProvider.cpp - misc/serialization/expressionserializer.cpp + aux/serialization/expressionserializer.cpp ) set(XREATE_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/ ) INCLUDE_DIRECTORIES(${XREATE_INCLUDE_DIRS}) set(XREATE_PRIVATE_INCLUDE_DIRS ${XREATE_INCLUDE_DIRS} ${COCO_GRAMMAR_PATH} ${JEAYESON_INCLUDE_PATH} ${LLVM_INCLUDE_DIRS} ${POTASSCO_INCLUDE_PATH} ) -add_library(${PROJECT_NAME} SHARED ${COCO_SOURCE_FILES} ${SOURCE_FILES}) +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${COCO_SOURCE_FILES}) target_link_libraries(${PROJECT_NAME}) target_include_directories(${PROJECT_NAME} INTERFACE ${XREATE_INCLUDE_DIRS} ${COCO_GRAMMAR_PATH} ${JEAYESON_INCLUDE_PATH} ${LLVM_INCLUDE_DIRS} ${POTASSCO_INCLUDE_PATH} ) get_directory_property(DEFINITIONS_ALL DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_DEFINITIONS) message("definitions all: " ${DEFINITIONS_ALL}) target_compile_definitions(${PROJECT_NAME} INTERFACE ${DEFINITIONS_ALL}) get_directory_property(COMPILATION_OPTIONS_ALL DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_OPTIONS) message("compilations all: " ${COMPILATION_OPTIONS_ALL}) target_compile_options(${PROJECT_NAME} INTERFACE ${COMPILATION_OPTIONS_ALL}) SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY INTERFACE_LINK_LIBRARIES ${LIBCLASP_LIBS} ${CLANG_LIBS} ${LLVM_LIBS} tbb 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/aux.cpp b/cpp/src/analysis/aux.cpp index 7ac53fc..505231f 100644 --- a/cpp/src/analysis/aux.cpp +++ b/cpp/src/analysis/aux.cpp @@ -1,136 +1,141 @@ #include "aux.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::NONE: { 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; } //TODO Null ad hoc ClaspLayer implementation // if (e.isNone()){ // result.push_back(e.__valueS); // } 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; } boost::format formatSymbol(const SymbolPacked& s){ boost::format formatSymbNamed("(%1%, %2%, %3%)"); boost::format formatSymbAnonymous("anonym(%1%, %2%)"); if (!s.categoryTransient){ return formatSymbNamed % s.identifier % s.version % s.scope; } else { return formatSymbAnonymous % s.identifier % s.scope; } } }} \ No newline at end of file diff --git a/cpp/src/analysis/typeinference.cpp b/cpp/src/analysis/typeinference.cpp index 53888e3..50d0efb 100644 --- a/cpp/src/analysis/typeinference.cpp +++ b/cpp/src/analysis/typeinference.cpp @@ -1,55 +1,60 @@ /* * typeinference.cpp * * Author: pgess * Created on April 16, 2017, 10:13 AM */ #include "typeinference.h" #include "llvmlayer.h" #include "llvm/IR/Function.h" #include "llvm/IR/DerivedTypes.h" 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::getDeclaration(s), ast); } assert(false && "Type can't be determined for an expression"); } } } //end of namespace xreate::typeinference \ No newline at end of file diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp index 01b0842..cee486b 100644 --- a/cpp/src/ast.cpp +++ b/cpp/src/ast.cpp @@ -1,926 +1,928 @@ #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)); } 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: case Expression::VARIANT: return false; case Expression::COMPOUND: { switch (e.op) { case Operator::CALL: return true; default: return false; } } } return false; } static bool isDoubleValueValid(const Expression& e) { switch (e.__state) { case Expression::NUMBER: case Expression::VARIANT: return true; case Expression::INVALID: assert(false); case Expression::IDENT: case Expression::STRING: case Expression::COMPOUND: case Expression::BINDING: return false; } return false; } }; class TypesResolver { private: const AST* ast; std::map 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::ARRAY: { assert(t.__operands.size() == 1); Expanded elTy = expandType(t.__operands.at(0)); return ExpandedType(TypeAnnotation(tag_array, elTy, 0)); } case TypeOperator::STRUCT: { assert(t.__operands.size()); std::vector&& packOperands = expandOperands(t.__operands); auto typNew = TypeAnnotation(TypeOperator::STRUCT, 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: { std::string alias = t.__valueCustom; /* if (signatures.count(alias)) { return ExpandedType(TypeAnnotation(TypeOperator::LINK, {t})); } signatures[alias].emplace(t); */ //find in local scope: if (scope.count(alias)) { return expandType(scope.at(alias)); } // find in general scope: if (ast->__indexTypeAliases.count(alias)) { return expandType(ast->__indexTypeAliases.at(t.__valueCustom)); } //if type is unknown keep it as is. return ExpandedType(TypeAnnotation(t)); }; case TypeOperator::ACCESS: { std::string alias = t.__valueCustom; ExpandedType tyAlias = ExpandedType(TypeAnnotation()); //find in local scope: if (scope.count(alias)) { tyAlias = expandType(scope.at(alias)); //find in global scope: } else if ((ast->__indexTypeAliases.count(alias))) { tyAlias = expandType(ast->__indexTypeAliases.at(alias)); } else { assert(false && "Undefined or external type"); } assert(tyAlias->__operator == TypeOperator::STRUCT); for (const string& field : t.fields) { auto fieldIt = std::find(tyAlias->fields.begin(), tyAlias->fields.end(), field); assert(fieldIt != tyAlias->fields.end() && "unknown field"); int fieldId = fieldIt - tyAlias->fields.begin(); tyAlias = expandType(tyAlias->__operands.at(fieldId)); } return tyAlias; } case TypeOperator::VARIANT: { return ExpandedType(TypeAnnotation(t)); } case TypeOperator::NONE: { return ExpandedType(TypeAnnotation(t)); } default: assert(false); } assert(false); return ExpandedType(TypeAnnotation()); } }; TypeAnnotation::TypeAnnotation() : __operator(TypeOperator::NONE), __value(TypePrimitive::Invalid) {} TypeAnnotation::TypeAnnotation(TypePrimitive typ) : __value(typ) { } TypeAnnotation::TypeAnnotation(TypeOperator op, std::initializer_list 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::ARRAY,{typ}) { __size = size; } bool TypeAnnotation::isValid() const{ return !(__value == TypePrimitive::Invalid && __operator == TypeOperator::NONE); } bool TypeAnnotation::operator<(const TypeAnnotation& t) const { if (__operator != t.__operator) return __operator < t.__operator; if (__operator == TypeOperator::NONE) return __value < t.__value; if (__operator == TypeOperator::CALL || __operator == TypeOperator::CUSTOM || __operator == TypeOperator::ACCESS) { if (__valueCustom != t.__valueCustom) return __valueCustom < t.__valueCustom; } return __operands < t.__operands; } /* TypeAnnotation (struct_tag, std::initializer_list) {} */ 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::NONE; __valueD=number.get(); } Expression::Expression(const Atom& a) : Expression(){ __state=STRING; op=Operator::NONE; __valueS=a.get(); } Expression::Expression(const Atom &ident) : Expression() { __state=IDENT; op=Operator::NONE; __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::NONE: __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); } Expression::Expression() : __state(INVALID), op(Operator::NONE), id(nextVacantId++) { } namespace details { namespace incomplete { AST::AST() { - 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::getFunctionVariants(const std::string& name) const { auto functions = __indexFunctions.equal_range(name); 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); } bool AST::recognizeVariantIdentifier(Expression& identifier) { assert(identifier.__state == Expression::IDENT); std::string variant = identifier.getValueString(); if (!__dictVariants.count(variant)) { return false; } auto record = __dictVariants.at(variant); const TypeAnnotation& typ = record.first; identifier.__state = Expression::VARIANT; identifier.setValueDouble(record.second); identifier.type = typ; return true; } 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) { - VariableVersion version = Attachments::get(identifier, VERSION_NONE); + 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{ - VariableVersion version = Attachments::get(identifier, VERSION_NONE); + 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, VERSION_NONE}; + 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); } void CodeScope::addDeclaration(Expression&& var, Expression&& body) { ScopedSymbol s = registerIdentifier(var); __declarations[s] = move(body); } CodeScope::CodeScope(CodeScope* parent) : __parent(parent) { } CodeScope::~CodeScope() { } void CodeScope::setBody(const Expression &body) { __declarations[ScopedSymbol::RetSymbol] = body; } Expression& CodeScope::getBody() { return __declarations[ScopedSymbol::RetSymbol]; } const Expression& CodeScope::getDeclaration(const Symbol& symbol) { CodeScope* self = symbol.scope; return self->getDeclaration(symbol.identifier); } const Expression& CodeScope::getDeclaration(const ScopedSymbol& symbol){ assert(__declarations.count(symbol) && "Symbol's declaration not found"); return __declarations.at(symbol); } void RuleArguments::add(const Atom &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(ClaspLayer& layer) { //TODO restore addRuleWarning //layer.addRuleWarning(*this); } bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2) { return (s1.id < s2.id) || (s1.id==s2.id && s1.version < s2.version); } bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2) { return (s1.id == s2.id) && (s1.version == s2.version); } bool operator<(const Symbol& s1, const Symbol& s2) { return (s1.scope < s2.scope) || (s1.scope == s2.scope && s1.identifier < s2.identifier); } bool operator==(const Symbol& s1, const Symbol& s2) { return (s1.scope == s2.scope) && (s1.identifier == s2.identifier); } bool operator<(const Expression&a, const Expression&b) { if (a.__state != b.__state) return a.__state < b.__state; assert(a.__state != Expression::INVALID); switch (a.__state) { case Expression::IDENT: case Expression::STRING: case Expression::VARIANT: return a.getValueString() < b.getValueString(); case Expression::NUMBER: return a.getValueDouble() < b.getValueDouble(); case Expression::COMPOUND: { assert(a.blocks.size() == 0); assert(b.blocks.size() == 0); if (a.op != b.op){ return a.op < b.op; } bool flagAValid = ExpressionHints::isStringValueValid(a); bool flagBValid = ExpressionHints::isStringValueValid(b); if (flagAValid != flagBValid) { return flagAValid < flagBValid; } if (flagAValid){ if (a.getValueString() != b.getValueString()) { return a.getValueString() < b.getValueString(); } } flagAValid = ExpressionHints::isDoubleValueValid(a); flagBValid = ExpressionHints::isDoubleValueValid(b); if (flagAValid != flagBValid) { return flagAValid < flagBValid; } if (flagAValid){ if (a.getValueDouble() != b.getValueDouble()) { return a.getValueDouble() < b.getValueDouble(); } } if (a.operands.size() != b.operands.size()) { return (a.operands.size() < b.operands.size()); } for (size_t i = 0; i < a.operands.size(); ++i) { bool result = a.operands[i] < b.operands[i]; if (result) return true; } return false; } case Expression::BINDING: case Expression::INVALID: assert(false); } return false; } bool Expression::operator==(const Expression& other) const { if (this->__state != other.__state) return false; if (ExpressionHints::isStringValueValid(*this)) { if (this->__valueS != other.__valueS) return false; } if (ExpressionHints::isDoubleValueValid(*this)) { if (this->__valueD != other.__valueD) return false; } if (this->__state != Expression::COMPOUND) { return true; } if (this->op != other.op) { return false; } if (this->operands.size() != other.operands.size()) { return false; } for (size_t i = 0; 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, VERSION_NONE}; +ScopedSymbol::RetSymbol = ScopedSymbol{0, versions::VERSION_NONE}; } diff --git a/cpp/src/ast.h b/cpp/src/ast.h index fe90e83..f7cbb79 100644 --- a/cpp/src/ast.h +++ b/cpp/src/ast.h @@ -1,575 +1,577 @@ #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 hold for all atoms/identifiers Parser::Token data, like line:col position 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); const std::string& get() const; private: std::string __value; }; enum class TypePrimitive { Invalid, Bool, I8, I32, I64, Num, Int, Float, String }; enum class TypeOperator { NONE, CALL, CUSTOM, VARIANT, ARRAY, STRUCT, ACCESS, LINK }; struct llvm_array_tag { }; struct struct_tag { }; const llvm_array_tag tag_array = llvm_array_tag(); const struct_tag tag_struct = struct_tag(); class TypeAnnotation { public: TypeAnnotation(); TypeAnnotation(const Atom& 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 { ADD, SUB, MUL, DIV, EQU, NE, NEG, LSS, LSE, GTR, GTE, LIST, LIST_RANGE, LIST_NAMED, CALL, CALL_INTRINSIC, NONE, IMPL/* implication */, MAP, FOLD, FOLD_INF, LOOP_CONTEXT, INDEX, IF, SWITCH, SWITCH_ADHOC, CASE, CASE_DEFAULT, LOGIC_AND, ADHOC, CONTEXT_RULE }; class Function; class AST; class CodeScope; class MetaRuleAbstract; template struct ManagedPtr { static ManagedPtr Invalid() { return ManagedPtr(); } ManagedPtr() : __storage(0) { } ManagedPtr(unsigned int id, const std::vector* storage) : __id(id), __storage(storage) { } Target& operator*() const { assert(isValid() && "Invalid Ptr"); return *__storage->at(__id); } void operator=(const ManagedPtr& other) { __id = other.__id; __storage = other.__storage; } bool operator==(const ManagedPtr& other) { return isValid() && (__id == other.__id); } Target* operator->() const noexcept { assert(isValid() && "Invalid Ptr"); return __storage->at(__id); } inline bool isValid() const { return (__storage) && (0 <= __id) && (__id < __storage->size()); } inline operator bool() const { return isValid(); } ManagedPtr& operator++() { ++__id; return *this; } inline unsigned int id() const { return __id; } private: unsigned int __id = 0; const std::vector * __storage = 0; }; typedef ManagedPtr ManagedFnPtr; typedef ManagedPtr ManagedScpPtr; typedef ManagedPtr ManagedRulePtr; const ManagedScpPtr NO_SCOPE = ManagedScpPtr(UINT_MAX, 0); //To update ExpressionHints in case of any changes struct Expression { friend class CodeScope; friend class ClaspLayer; friend class CFAPass; friend class ExpressionHints; Expression(const Operator &oprt, std::initializer_list 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; enum { INVALID, COMPOUND, IDENT, NUMBER, STRING, VARIANT, BINDING } __state = INVALID; Operator op; unsigned int id; std::vector bindings; std::map __indexBindings; std::vector operands; TypeAnnotation type; mutable std::map tags; 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 ClaspLayer; class LLVMLayer; class MetaRuleAbstract { public: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards); virtual ~MetaRuleAbstract(); virtual void compile(ClaspLayer& layer) = 0; protected: RuleArguments __args; RuleGuards __guards; }; class RuleWarning : public MetaRuleAbstract { friend class ClaspLayer; public: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message); virtual void compile(ClaspLayer& layer); ~RuleWarning(); private: std::string __message; Expression __condition; }; typedef unsigned int VNameId; -typedef int VariableVersion; -const VariableVersion VERSION_NONE = -2; -const VariableVersion VERSION_INIT = 0; +namespace versions { + typedef int VariableVersion; + const VariableVersion VERSION_NONE = -2; + const VariableVersion VERSION_INIT = 0; +} template<> -struct AttachmentsDict +struct AttachmentsDict { - typedef VariableVersion Data; + typedef versions::VariableVersion Data; static const unsigned int key = 6; }; struct ScopedSymbol{ VNameId id; - VariableVersion version; + versions::VariableVersion version; static const ScopedSymbol RetSymbol; }; struct Symbol { ScopedSymbol identifier; CodeScope * scope; }; template<> struct AttachmentsDict { typedef Symbol Data; static const unsigned int key = 7; }; 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); class CodeScope { friend class Function; friend class PassManager; public: CodeScope(CodeScope* parent = 0); void setBody(const Expression& body); Expression& getBody(); void addDeclaration(Expression&& var, Expression&& body); void addBinding(Expression&& var, Expression&& argument); static const Expression& getDeclaration(const Symbol& symbol); const Expression& getDeclaration(const ScopedSymbol& symbol); ~CodeScope(); std::vector __bindings; std::map __identifiers; CodeScope* __parent; //TODO move __definitions to SymbolsAttachments data //NOTE: definition of return type has zero(0) variable index 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); }; class Function { friend class Expression; friend class CodeScope; friend class AST; public: Function(const Atom& name); void addBinding(Atom && name, Expression&& argument); 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 guardContext; private: std::map __tags; }; class ExternData; struct ExternEntry { std::string package; std::vector headers; }; typedef Expanded ExpandedType; 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); } }; namespace details { namespace incomplete { class AST { public: AST(); //TASK extern and DFA interfaces move into addInterfaceData /** * DFA Interface */ void addDFAData(Expression&& data); /** * Extern Interface */ void addExternData(ExternData&& data); void addInterfaceData(const ASTInterface& interface, Expression&& data); void add(Function* f); void add(MetaRuleAbstract* r); ManagedScpPtr add(CodeScope* scope); std::string getModuleName(); ManagedPtr findFunction(const std::string& name); typedef std::multimap FUNCTIONS_REGISTRY; std::list getAllFunctions() const; std::list getFunctionVariants(const std::string& name) const; template ManagedPtr begin(); 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; // ***** TYPES SECTION ***** public: std::map __indexTypeAliases; ExpandedType getType(const Expression& expression); void add(TypeAnnotation t, Atom alias); // ***** SYMBOL RECOGNITION ***** //TODO revisit enums/variants, move to codescope bool recognizeVariantIdentifier(Expression& identifier); private: std::map> __dictVariants; public: std::set> bucketUnrecognizedIdentifiers; public: void postponeIdentifier(CodeScope* scope, const Expression& id); void recognizePostponedIdentifiers(); xreate::AST* finalize(); }; template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); } } // namespace details::incomplete class AST: public details::incomplete::AST{ public: AST(): details::incomplete::AST() {} ExpandedType expandType(const TypeAnnotation &t) const; ExpandedType findType(const std::string& name); ExpandedType getType(const Expression& expression); }; } #endif // AST_H diff --git a/cpp/src/attachments.h b/cpp/src/attachments.h index 5964ebe..9d7463a 100644 --- a/cpp/src/attachments.h +++ b/cpp/src/attachments.h @@ -1,163 +1,170 @@ // // Created by pgess on 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 (current unreserved - 9); + //reserved attachments: +// 1 containers::Implementation +// 3 interpretation::InterpretationData +// 5 interpretation::FunctionInterpretationData +// 6 VariableVersion +// 7 Symbol +// 8 versions::VersionImposedDependency }; 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; 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); } 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); } 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 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_ \ No newline at end of file diff --git a/cpp/src/misc/serialization/expressionserializer.cpp b/cpp/src/aux/serialization/expressionserializer.cpp similarity index 99% rename from cpp/src/misc/serialization/expressionserializer.cpp rename to cpp/src/aux/serialization/expressionserializer.cpp index d62a1cc..bf62ba2 100644 --- a/cpp/src/misc/serialization/expressionserializer.cpp +++ b/cpp/src/aux/serialization/expressionserializer.cpp @@ -1,318 +1,318 @@ /* * expressionserializer.cpp * * Created on: Jan 4, 2016 * Author: pgess */ -#include "misc/serialization/expressionserializer.h" +#include "aux/serialization/expressionserializer.h" #include #include #include using namespace std; //using namespace boost::bimaps; namespace xreate { struct Index { string name; size_t degree; //count of parameters unsigned char level; //level in expression tree (depth of tree layer) bool operator< (const Index other) const{ if (name != other.name) return name < other.name; if (degree != other.degree) return degree < other.degree; if (name != other.name) return level < other.level; return false; } }; class ExpressionSerializerPrivate { //boost::bimap> __registry; struct { map left; } __registry; map __range; public: void pack(const Expression& e, unsigned char level, OptionalPackedExpression& target){ if (!target) return; switch (e.op){ case Operator::NONE: { switch (e.__state) { case Expression::NUMBER: case Expression::STRING: case Expression::IDENT : { Index index; if ((e.__state == Expression::NUMBER)) index = {std::to_string(e.getValueDouble()), 0, level}; else index = {e.getValueString(), 0, level}; if (!__registry.left.count(index)){ target = boost::none; return; } size_t id = __registry.left.at(index); size_t range = __range[level]; (*target) << make_pair(id, range); return; } default: break; } break; } case Operator::CALL: { Index index{e.getValueString(), e.operands.size(), level}; if(!__registry.left.count(index)){ target = boost::none; return; } size_t id = __registry.left.at(index); size_t range = __range[level]; (*target) << make_pair(id, range); for (const Expression& operand: e.operands){ pack(operand, level+1, target); } return; } default: break; } assert(false && "Expression too complicate for serialization"); } void registerExpression(const Expression&e, unsigned char level){ switch (e.op){ case Operator::CALL: { Index index{e.getValueString(), e.operands.size(), level}; if (__registry.left.insert(make_pair(index, __range[level])).second){ __range[level]++; } for (const Expression& operand: e.operands){ registerExpression(operand, level+1); } return; } case Operator::NONE: { Index index; switch (e.__state) { case Expression::STRING: case Expression::IDENT: { index = {e.getValueString(), 0, level}; if (__registry.left.insert(make_pair(index, __range[level])).second){ __range[level]++; } return; } case Expression::NUMBER: { index = {std::to_string(e.getValueDouble()), 0, level}; if (__registry.left.insert(make_pair(index, __range[level])).second){ __range[level]++; } return; } default: break; } break; } default: break; } assert(false && "Expression too complicate for serialization"); } }; ExpressionSerializer::ExpressionSerializer() : strategy(new ExpressionSerializerPrivate()){ } ExpressionSerializer::~ExpressionSerializer() { delete strategy; } void ExpressionSerializer::registerExpression(const Expression&e){ if (e.isValid()) strategy->registerExpression(e, 0); } PackedExpression ExpressionSerializer::getId(const Expression& e){ OptionalPackedExpression result(boost::in_place()); //move(PackedExpression()) strategy->pack(e, 0, result); assert(result); return move(*result); } OptionalPackedExpression ExpressionSerializer::getIdOptional(const Expression& e) const{ OptionalPackedExpression result(boost::in_place()); //move(PackedExpression()) strategy->pack(e, 0, result); return result; } ExpressionSerializerIntegral::ExpressionSerializerIntegral():serializer(*this){} ExpressionSerializerIntegral::ExpressionSerializerIntegral(const std::vector&& expressions) : std::vector(move(expressions)), serializer(*this){ size_t id =0; for (const Expression& e: expressions){ __registry.emplace(serializer.getId(e), id++); } } size_t ExpressionSerializerIntegral::size() const{ return PARENT::size(); } size_t ExpressionSerializerIntegral::count(const Expression& e) const { return (getIdOptional(e)? 1: 0); } ExpressionSerializerIntegral::const_iterator ExpressionSerializerIntegral::begin() const { return PARENT::begin(); } ExpressionSerializerIntegral::const_iterator ExpressionSerializerIntegral::end() const { return PARENT::end(); } size_t ExpressionSerializerIntegral::getId(const Expression& e) const{ const OptionalPackedExpression exprPacked = serializer.getIdOptional(e); assert(exprPacked); return __registry.at(*exprPacked); } boost::optional ExpressionSerializerIntegral::getIdOptional(const Expression& e) const{ const OptionalPackedExpression exprPacked = serializer.getIdOptional(e); if (!exprPacked){ return boost::none; } return __registry.at(*exprPacked); } const Expression& ExpressionSerializerIntegral::get(size_t id) const{ return at(id); } void PackedExpression::operator<< (const std::pair& value){ static const size_t sizeSizeT = sizeof(size_t); const size_t& id = value.first; const size_t& range = value.second; int countSufficientBits = range <=1? 0 : ceil(log2(range)); if (0 < countRemainedBits && countRemainedBits < countSufficientBits) { size_t* tail = reinterpret_cast(__storage + size- sizeSizeT); (*tail) += id >> (countSufficientBits - countRemainedBits); countSufficientBits-=countRemainedBits; countRemainedBits = 0; } if (countRemainedBits == 0) { if (countSufficientBits == 0) return; char* __storageNew = new char[size+sizeSizeT]; std::memcpy (__storageNew, __storage, size); std::memset(__storageNew + size, 0, sizeSizeT); delete[] __storage; __storage = __storageNew; size += sizeSizeT; countRemainedBits = 8 * sizeSizeT; } if (countRemainedBits >= countSufficientBits) { size_t* tail = reinterpret_cast(__storage + size- sizeSizeT); (*tail) += id << (countRemainedBits - countSufficientBits); countRemainedBits -= countSufficientBits; return; } assert("Unreachable block"); } #if BOOST_VERSION <= 105500 PackedExpression::PackedExpression(const PackedExpression& other){ __storage = other.__storage; size = other.size; countRemainedBits = other.countRemainedBits; } #endif PackedExpression::PackedExpression(PackedExpression&& other){ __storage = other.__storage; size = other.size; countRemainedBits = other.countRemainedBits; other.__storage = nullptr; } bool PackedExpression::operator==(const PackedExpression& other) const{ if (size == other.size && countRemainedBits == other.countRemainedBits){ return std::memcmp(__storage, other.__storage, size) == 0 ; } return false; } bool PackedExpression::operator<(const PackedExpression& other) const{ if (size < other.size) { return true; } if (countRemainedBits < other.countRemainedBits) return true; if (size == other.size && countRemainedBits == other.countRemainedBits){ return std::memcmp(__storage, other.__storage, size) < 0 ; } return false; } bool PackedExpression::operator!=(const PackedExpression& other) const{ return ! ((*this) == other); } PackedExpression::~PackedExpression() { delete[] __storage; } //PackedExpression::PackedExpression (const PackedExpression& other) // : size(other.size), countRemainedBits(other.countRemainedBits) //{ // __storage = new char[size]; // std::memcpy (__storage, other.__storage, size); //} -} /* namespace xreate */ \ No newline at end of file +} /* namespace xreate */ diff --git a/cpp/src/misc/serialization/expressionserializer.h b/cpp/src/aux/serialization/expressionserializer.h similarity index 100% rename from cpp/src/misc/serialization/expressionserializer.h rename to cpp/src/aux/serialization/expressionserializer.h diff --git a/cpp/src/misc/xreatemanager-decorators.cpp b/cpp/src/aux/xreatemanager-decorators.cpp similarity index 92% rename from cpp/src/misc/xreatemanager-decorators.cpp rename to cpp/src/aux/xreatemanager-decorators.cpp index 7f414ac..ff3dc9c 100644 --- a/cpp/src/misc/xreatemanager-decorators.cpp +++ b/cpp/src/aux/xreatemanager-decorators.cpp @@ -1,67 +1,67 @@ /* * xreatemanager-decorators.cpp * * Author: pgess * Created on July 16, 2017, 4:40 PM */ -#include "misc/xreatemanager-decorators.h" +#include "aux/xreatemanager-decorators.h" #include "main/Parser.h" #include "pass/compilepass.h" #include "pass/adhocpass.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(clasp); clasp->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); this->registerPass(new adhoc::AdhocPass(this), PassId::AdhocPass); this->registerPass(new interpretation::InterpretationPass(this), PassId::InterpretationPass); this->registerPass(new versions::VersionsPass(this), PassId::VersionsPass); } void* XreateManagerDecoratorFull::run() { - std::unique_ptr compiler(new CompilePass(this)); + 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/misc/xreatemanager-decorators.h b/cpp/src/aux/xreatemanager-decorators.h similarity index 100% rename from cpp/src/misc/xreatemanager-decorators.h rename to cpp/src/aux/xreatemanager-decorators.h diff --git a/cpp/src/misc/xreatemanager-modules.h b/cpp/src/aux/xreatemanager-modules.h similarity index 100% rename from cpp/src/misc/xreatemanager-modules.h rename to cpp/src/aux/xreatemanager-modules.h diff --git a/cpp/src/clasplayer.h b/cpp/src/clasplayer.h index 525868d..2a1a617 100644 --- a/cpp/src/clasplayer.h +++ b/cpp/src/clasplayer.h @@ -1,236 +1,245 @@ #ifndef CLASPLAYER_H #define CLASPLAYER_H #include "ast.h" #include "contextrule.h" #include #include #include #include #include #include #include #include namespace xreate { typedef unsigned int ScopePacked; struct SymbolPacked { VNameId identifier; - VariableVersion version; + versions::VariableVersion version; ScopePacked scope; bool categoryTransient; SymbolPacked(): categoryTransient(false){} SymbolPacked(ScopedSymbol i, ScopePacked s, bool isTransient = false): identifier(i.id), version(i.version), scope(s), categoryTransient(isTransient){} - SymbolPacked(VNameId symbolId, VariableVersion symbolVersion, ScopePacked symbolScope, bool isTransient = false) + SymbolPacked(VNameId symbolId, versions::VariableVersion symbolVersion, ScopePacked symbolScope, bool isTransient = false) : identifier(symbolId), version(symbolVersion), scope(symbolScope), categoryTransient(isTransient){} }; bool operator==(const SymbolPacked& s1, const SymbolPacked& s2); bool operator<(const SymbolPacked& s1, const SymbolPacked& s2); enum class DFGConnection { STRONG, WEAK, PROTOTYPE }; class IAnalysisData { public: void print(std::ostringstream& output) const; virtual ~IAnalysisData(){}; }; class IQuery { public: virtual void init(ClaspLayer* clasp) = 0; virtual ~IQuery() {} }; enum class QueryId { ContainersQuery, ContextQuery, PtrvalidQuery }; namespace dfa{ class DFAGraph; } namespace cfa { class CFAGraph; } class ClaspLayer { friend class ContextRule; //PROVIDERS: public: boost::scoped_ptr dataDFA; void setDFAData(xreate::dfa::DFAGraph* graph); boost::scoped_ptr dataCFA; void setCFAData(xreate::cfa::CFAGraph* graph); void addRawScript(std::string&& script); private: void involveImports(); //QUERIES public: IQuery* registerQuery(IQuery* query, const QueryId& id); IQuery* getQuery(const QueryId& id); template static std::tuple parse(const Gringo::Symbol& atom); typedef std::multimap::const_iterator ModelIterator; typedef boost::optional> ModelFragment; ModelFragment query(const std::string& atom); size_t getScopesCount() const; SymbolPacked pack(const Symbol& symbol, std::string hintSymbolName = ""); ScopePacked pack(CodeScope * const scope); Symbol unpack(const SymbolPacked& symbol); std::string getHintForPackedSymbol(const SymbolPacked& symbol); private: std::map __queries; std::multimap __model; std::map __indexSymbolNameHints; std::unordered_map __indexScopes; std::vector __registryScopes; //WARNINGS //TODO move to separate provider/query public: void addRuleWarning(const RuleWarning &rule); unsigned int registerWarning(std::string &&message); private: std::map __warnings; void printWarnings(std::ostream& out); //DEFAULT public: AST *ast; ClaspLayer(); void run(); private: 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 std::string get(const Gringo::Symbol& atom) { switch (atom.type()) { case Gringo::SymbolType::Str: return atom.string().c_str(); case Gringo::SymbolType::Fun: return atom.name().c_str(); default: break; } assert(false && "Inappropriate symbol type"); } }; - + template<> struct ParseImplAtom { static SymbolPacked get(const Gringo::Symbol& atom) { auto result = ClaspLayer::parse(atom); return SymbolPacked(std::get<0>(result), std::get<1>(result), std::get<2>(result)); } }; template<> struct ParseImplAtom { static Gringo::Symbol get(const Gringo::Symbol& atom) { return atom; } }; + + template<> + struct ParseImplAtom>{ + static std::list get(const Gringo::Symbol& atom) { + assert (atom.type() == Gringo::SymbolType::Fun); + std::list 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) { switch (atom.type()) { case Gringo::SymbolType::Num: return Expression(atom.num()); case Gringo::SymbolType::Str: return Expression(std::string(atom.string().c_str())); case Gringo::SymbolType::Fun: - { - //ID - if (!atom.args().size){ - return Expression(std::string(atom.name().c_str())); - } - + { //FUNC Expression result(Operator::CALL,{Expression(std::string(atom.name().c_str()))}); for (const Gringo::Symbol& arg : atom.args()) { result.addArg(ParseImplAtom::get(arg)); } return result; } default: { assert(false); } } } }; 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 ClaspLayer::parse(const Gringo::Symbol& atom) { typedef std::tuple < Types...> Tuple; Tuple tup; Parse_Impl::value>::parse(tup, atom.args().first); return tup; } } #endif \ No newline at end of file diff --git a/cpp/src/compilation/advanced.cpp b/cpp/src/compilation/advanced.cpp index f5c489b..f4c64d2 100644 --- a/cpp/src/compilation/advanced.cpp +++ b/cpp/src/compilation/advanced.cpp @@ -1,399 +1,399 @@ /* * File: InstructionsAdvanced.cpp * Author: pgess * * Created on June 26, 2016, 6:00 PM */ //#include #include "compilation/advanced.h" #include "compilation/containers.h" #include "compilation/transformersaturation.h" #include "query/context.h" #include "query/containers.h" #include "llvmlayer.h" #include "ast.h" using namespace std; using namespace llvm; using namespace xreate; using namespace xreate::containers; using namespace xreate::compilation; #define NAME(x) (hintRetVar.empty()? x : hintRetVar) #define UNUSED(x) (void)(x) #define EXPAND_CONTEXT \ LLVMLayer* llvm = context.pass->man->llvm; \ - compilation::AbstractCodeScopeUnit* scope = context.scope; \ - compilation::FunctionUnit* function = context.function; + compilation::ICodeScopeUnit* scope = context.scope; \ + compilation::IFunctionUnit* function = context.function; Advanced::Advanced(compilation::Context ctx) : context(ctx), tyNum(static_cast (ctx.pass->man->llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::Num))))) { } llvm::Value* Advanced::compileMapSolidOutput(const Expression &expr, const std::string hintRetVar) { EXPAND_CONTEXT //initialization Symbol symbolIn = Attachments::get(expr.getOperands()[0]); ImplementationRec implIn = containers::Query::queryImplementation(symbolIn).extract(); // impl of input list size_t size = implIn.size; CodeScope* scopeLoop = expr.blocks.front(); std::string varEl = scopeLoop->__bindings[0]; Iterator* it = Iterator::create(context, symbolIn); llvm::Value *rangeFrom = it->begin(); llvm::Value *rangeTo = it->end(); //definitions ArrayType* tyNumArray = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::Num, size)))); llvm::IRBuilder<> &builder = llvm->builder; llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "loop", function->raw); llvm::BasicBlock *blockBeforeLoop = builder.GetInsertBlock(); llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "postloop", function->raw); Value* dataOut = llvm->builder.CreateAlloca(tyNumArray, ConstantInt::get(tyNum, size), NAME("map")); // * initial check Value* condBefore = builder.CreateICmpSLE(rangeFrom, rangeTo); builder.CreateCondBr(condBefore, blockLoop, blockAfterLoop); // create PHI: builder.SetInsertPoint(blockLoop); llvm::PHINode *stateLoop = builder.CreatePHI(tyNum, 2, "mapIt"); stateLoop->addIncoming(rangeFrom, blockBeforeLoop); // loop body: Value* elIn = it->get(stateLoop, varEl); - compilation::AbstractCodeScopeUnit* scopeLoopUnit = function->getScopeUnit(scopeLoop); + compilation::ICodeScopeUnit* scopeLoopUnit = function->getScopeUnit(scopeLoop); scopeLoopUnit->bindArg(elIn, move(varEl)); Value* elOut = scopeLoopUnit->compile(); Value *pElOut = builder.CreateGEP(dataOut, ArrayRef(std::vector{ConstantInt::get(tyNum, 0), stateLoop})); builder.CreateStore(elOut, pElOut); //next iteration preparing Value *stateLoopNext = builder.CreateAdd(stateLoop, llvm::ConstantInt::get(tyNum, 1)); stateLoop->addIncoming(stateLoopNext, builder.GetInsertBlock()); //next iteration checks: Value* condAfter = builder.CreateICmpSLE(stateLoopNext, rangeTo); builder.CreateCondBr(condAfter, blockLoop, blockAfterLoop); //finalization: builder.SetInsertPoint(blockAfterLoop); return dataOut; } Value* Advanced::compileArrayIndex(llvm::Value* aggregate, std::vector indexes, std::string hintRetVar) { EXPAND_CONTEXT UNUSED(function); indexes.insert(indexes.begin(), llvm::ConstantInt::get(tyNum, 0)); llvm::Value *pEl = llvm->builder.CreateGEP(aggregate, llvm::ArrayRef(indexes)); return llvm->builder.CreateLoad(pEl, NAME("el")); } Value* Advanced::compileStructIndex(llvm::Value* aggregate, const ExpandedType& t, const std::string& idx) { EXPAND_CONTEXT UNUSED(scope); TypeUtils types(llvm); std::vector&& fields = types.getStructFields(t); for (unsigned i = 0, size = fields.size(); i < size; ++i) { if (fields.at(i) == idx) { //TODO DISABLEDFEATURE validptr // TODO review safety check: validPtr for `aggregate` // SECTIONTAG validptr exception // std::vector refs; // llvm::BasicBlock *blockSafe = llvm::BasicBlock::Create(llvm::getGlobalContext(), "safe", function->raw); // PointerType* tyAggr = dyn_cast(aggregate->getType()); // llvm::Value* null = llvm::ConstantPointerNull::get(tyAggr); // Value* condNull = llvm->builder.CreateICmpNE(aggregate, null); // // llvm::BasicBlock *blockException = llvm::BasicBlock::Create(llvm::getGlobalContext(), "exception", function->raw); // llvm->builder.CreateCondBr(condNull, blockSafe, blockException); // llvm->initExceptionBlock(blockException); // // llvm->builder.SetInsertPoint(blockSafe); //dereference pointer if (types.isPointer(t)) { llvm::Value* addr = llvm->builder.CreateConstGEP2_32(nullptr, aggregate, 0, i); return llvm->builder.CreateLoad(addr); } aggregate->getType()->dump(); return llvm->builder.CreateExtractValue(aggregate, llvm::ArrayRef{i}); } } assert(false && "not found required struct field"); return nullptr; } llvm::Value* Advanced::compileFold(const Expression& fold, const std::string& hintRetVar) { EXPAND_CONTEXT assert(fold.op == Operator::FOLD); //initialization: Symbol varInSymbol = Attachments::get(fold.getOperands()[0]); Implementation info = Query::queryImplementation(varInSymbol); Iterator* it = Iterator::create(context, varInSymbol); llvm::Value* rangeBegin = it->begin(); llvm::Value* rangeEnd = it->end(); llvm::Value* accumInit = scope->process(fold.getOperands()[1]); std::string varIn = fold.getOperands()[0].getValueString(); std::string varAccum = fold.bindings[1]; std::string varEl = fold.bindings[0]; llvm::BasicBlock *blockBeforeLoop = llvm->builder.GetInsertBlock(); std::unique_ptr transformerSaturation(new TransformerSaturation(blockBeforeLoop, context.pass->managerTransformations)); llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold", function->raw); llvm::BasicBlock *blockLoopBody = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold_body", function->raw); llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold_after", function->raw); llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold_next", function->raw); llvm->builder.CreateBr(blockLoop); // * create phi llvm->builder.SetInsertPoint(blockLoop); llvm::PHINode *accum = llvm->builder.CreatePHI(accumInit->getType(), 2, varAccum); accum->addIncoming(accumInit, blockBeforeLoop); llvm::PHINode *itLoop = llvm->builder.CreatePHI(rangeBegin->getType(), 2, "foldIt"); itLoop->addIncoming(rangeBegin, blockBeforeLoop); // * loop checks Value* condRange = llvm->builder.CreateICmpNE(itLoop, rangeEnd); llvm->builder.CreateCondBr(condRange, blockLoopBody, blockAfterLoop); // * loop body llvm->builder.SetInsertPoint(blockLoopBody); CodeScope* scopeLoop = fold.blocks.front(); - compilation::AbstractCodeScopeUnit* loopUnit = function->getScopeUnit(scopeLoop); + compilation::ICodeScopeUnit* loopUnit = function->getScopeUnit(scopeLoop); Value* elIn = it->get(itLoop); loopUnit->bindArg(accum, move(varAccum)); loopUnit->bindArg(elIn, move(varEl)); Value* accumNext = loopUnit->compile(); // * Loop saturation checks bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockNext, blockAfterLoop, context); llvm::BasicBlock* blockSaturation = llvm->builder.GetInsertBlock(); if (!flagSaturationTriggered){ llvm->builder.CreateBr(blockNext); } // * computing next iteration state llvm->builder.SetInsertPoint(blockNext); Value *itLoopNext = it->advance(itLoop); accum->addIncoming(accumNext, llvm->builder.GetInsertBlock()); itLoop->addIncoming(itLoopNext, llvm->builder.GetInsertBlock()); llvm->builder.CreateBr(blockLoop); // * finalization: llvm->builder.SetInsertPoint(blockAfterLoop); if (!flagSaturationTriggered){ return accum; } llvm::PHINode* result = llvm->builder.CreatePHI(accumInit->getType(), 2); result->addIncoming(accum, blockLoop); result->addIncoming(accumNext, blockSaturation); return result; } llvm::Value* Advanced::compileFoldInf(const Expression& fold, const std::string& hintRetVar) { EXPAND_CONTEXT assert(fold.op == Operator::FOLD_INF); std::string accumName = fold.bindings[0]; llvm::Value* accumInit = scope->process(fold.getOperands()[0]); llvm::BasicBlock *blockBeforeLoop = llvm->builder.GetInsertBlock(); llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "foldinf", function->raw); llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm::getGlobalContext(), "foldinf_next", function->raw); llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "foldinf_post", function->raw); std::unique_ptr transformerSaturation(new TransformerSaturation(blockBeforeLoop, context.pass->managerTransformations)); llvm->builder.CreateBr(blockLoop); // * create phi llvm->builder.SetInsertPoint(blockLoop); llvm::PHINode *accum = llvm->builder.CreatePHI(accumInit->getType(), 2, accumName); accum->addIncoming(accumInit, blockBeforeLoop); // * loop body CodeScope* scopeLoop = fold.blocks.front(); - compilation::AbstractCodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); + compilation::ICodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); unitLoop->bindArg(accum, move(accumName)); Value* accumNext = unitLoop->compile(); // * Loop saturation checks bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockNext, blockAfterLoop, context); assert(flagSaturationTriggered); // * computing next iteration state llvm->builder.SetInsertPoint(blockNext); accum->addIncoming(accumNext, llvm->builder.GetInsertBlock()); llvm->builder.CreateBr(blockLoop); // finalization: llvm->builder.SetInsertPoint(blockAfterLoop); return accumNext; } llvm::Value* Advanced::compileIf(const Expression& exprIf, const std::string& hintRetVar) { EXPAND_CONTEXT //initialization: const Expression& condExpr = exprIf.getOperands()[0]; llvm::IRBuilder<>& builder = llvm->builder; //llvm::Type* tyResultType = llvm->toLLVMType(llvm->ast->expandType(exprIf.type)); llvm::BasicBlock *blockAfter = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifAfter", function->raw); llvm::BasicBlock *blockTrue = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifTrue", function->raw); llvm::BasicBlock *blockFalse = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifFalse", function->raw); llvm::Value* cond = scope->process(condExpr); llvm->builder.CreateCondBr(cond, blockTrue, blockFalse); builder.SetInsertPoint(blockTrue); CodeScope* scopeTrue = exprIf.blocks.front(); llvm::Value* resultTrue = function->getScopeUnit(scopeTrue)->compile(); blockTrue = builder.GetInsertBlock(); builder.CreateBr(blockAfter); builder.SetInsertPoint(blockFalse); CodeScope* scopeFalse = exprIf.blocks.back(); llvm::Value* resultFalse = function->getScopeUnit(scopeFalse)->compile(); blockFalse = builder.GetInsertBlock(); builder.CreateBr(blockAfter); builder.SetInsertPoint(blockAfter); llvm::PHINode *ret = builder.CreatePHI(resultTrue->getType(), 2, NAME("if")); ret->addIncoming(resultTrue, blockTrue); ret->addIncoming(resultFalse, blockFalse); return ret; } //TODO Switch: default variant no needed when all possible conditions are considered llvm::Value* Advanced::compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar) { EXPAND_CONTEXT AST* root = context.pass->man->root; UNUSED(function); assert(exprSwitch.operands.size() >= 2); assert(exprSwitch.operands[1].op == Operator::CASE_DEFAULT && "No default case in Switch Statement"); int countCases = exprSwitch.operands.size() - 1; llvm::IRBuilder<>& builder = llvm->builder; llvm::BasicBlock* blockProlog = builder.GetInsertBlock(); llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "switchAfter", function->raw); builder.SetInsertPoint(blockEpilog); llvm::Type* exprSwitchType = llvm->toLLVMType(root->getType(exprSwitch)); llvm::PHINode *ret = builder.CreatePHI(exprSwitchType, countCases, NAME("switch")); builder.SetInsertPoint(blockProlog); llvm::Value * conditionSwitch = scope->process(exprSwitch.operands[0]); llvm::BasicBlock *blockDefault = llvm::BasicBlock::Create(llvm::getGlobalContext(), "caseDefault", function->raw); llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(conditionSwitch, blockDefault, countCases); for (int size = exprSwitch.operands.size(), i = 2; i < size; ++i) { llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm::getGlobalContext(), "case" + std::to_string(i), function->raw); llvm::Value* condCase = function->getScopeUnit(exprSwitch.operands[i].blocks.front())->compile(); builder.SetInsertPoint(blockCase); llvm::Value* resultCase = function->getScopeUnit(exprSwitch.operands[i].blocks.back())->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultCase, builder.GetInsertBlock()); builder.SetInsertPoint(blockProlog); instructionSwitch->addCase(dyn_cast(condCase), blockCase); } //compile default block: builder.SetInsertPoint(blockDefault); CodeScope* scopeDefault = exprSwitch.operands[1].blocks.front(); llvm::Value* resultDefault = function->getScopeUnit(scopeDefault)->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultDefault, builder.GetInsertBlock()); builder.SetInsertPoint(blockEpilog); return ret; } //TODO recognize cases to make const arrays/stored in global mem/stack alloced. llvm::Value* Advanced::compileListAsSolidArray(const Expression &expr, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(scope); UNUSED(function); AST* root = context.pass->man->root; const size_t& length = expr.getOperands().size(); const Expression& expression = expr; llvm::Value* zero = ConstantInt::get(tyNum, 0); llvm::Value* one = ConstantInt::get(tyNum, 1); ExpandedType typAggrExpanded = root->getType(expression); assert(typAggrExpanded->__operator == TypeOperator::ARRAY); llvm::Type* typEl = llvm->toLLVMType(ExpandedType(typAggrExpanded->__operands[0])); ArrayType* typAggr = (ArrayType*) llvm::ArrayType::get(typEl, length); llvm::Value* list = llvm->builder.CreateAlloca(typAggr, ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), length, false), hintRetVar); const std::vector& operands = expression.getOperands(); llvm::Value* addrOperand = llvm->builder.CreateGEP(typAggr, list, ArrayRef(std::vector{zero, zero})); llvm->builder.CreateStore(scope->process(operands.front()), addrOperand) ; for (auto i=++operands.begin(); i!=operands.end(); ++i){ addrOperand = llvm->builder.CreateGEP(typEl, addrOperand, ArrayRef(std::vector{one})); llvm->builder.CreateStore(scope->process(*i), addrOperand) ; } return list; // Value* listDest = l.builder.CreateAlloca(typList, ConstantInt::get(typI32, __size), *hintRetVar); // l.buil1der.CreateMemCpy(listDest, listSource, __size, 16); } llvm::Value* Advanced::compileConstantStringAsPChar(const string& data, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(function); UNUSED(scope); Type* typPchar = PointerType::getUnqual(Type::getInt8Ty(llvm::getGlobalContext())); //ArrayType* typStr = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::I8, size+1)))); /* std::vector chars; chars.reserve(size+1); for (size_t i=0; i< size; ++i){ chars[i] = ConstantInt::get(typI8, (unsigned char) data[i]); } chars[size] = ConstantInt::get(typI8, 0); */ Value* rawData = ConstantDataArray::getString(llvm::getGlobalContext(), data); Value* rawPtrData = llvm->builder.CreateAlloca(rawData->getType(), ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), 1, false)); llvm->builder.CreateStore(rawData, rawPtrData); return llvm->builder.CreateCast(llvm::Instruction::BitCast, rawPtrData, typPchar, hintRetVar); } diff --git a/cpp/src/compilation/containers.cpp b/cpp/src/compilation/containers.cpp index c86d08d..b1d8c49 100644 --- a/cpp/src/compilation/containers.cpp +++ b/cpp/src/compilation/containers.cpp @@ -1,195 +1,195 @@ #include "compilation/containers.h" using namespace std; using namespace llvm; using namespace xreate; using namespace xreate::containers; Iterator* Iterator::create(xreate::compilation::Context context, const xreate::Symbol& var){ const Implementation& data = Query::queryImplementation(var); switch(data.impl){ case ON_THE_FLY: return new IteratorForward(context, var, data.extract()); case SOLID: return new IteratorForward(context, var, data.extract()); default: assert(true); } assert(false && "Unknown declaration"); return nullptr; } llvm::Value* IteratorForward::begin() { switch(sourceDecl.op) { case xreate::Operator::LIST: { sourceRawType = llvm::Type::getInt32Ty(llvm::getGlobalContext()); return llvm::ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), 0); }; case xreate::Operator::LIST_RANGE:{ assert(sourceDecl.operands.size()==2); llvm::Value* result = sourceUnit->process(sourceDecl.operands.at(0)); sourceRawType = result->getType(); return result; }; default: break; } if (linkedlist){ llvm::Value* result = sourceUnit->process(sourceDecl); sourceRawType = result->getType(); return result; } assert(false); } llvm::Value* IteratorForward::end(){ switch(sourceDecl.op) { case xreate::Operator::LIST: { size_t idLast = sourceDecl.operands.size() - 1; return ConstantInt::get(sourceRawType, idLast); } case xreate::Operator::LIST_RANGE: { assert(sourceDecl.operands.size() == 2); llvm::Value* valueEndOfRange = sourceUnit->process(sourceDecl.operands.at(1)); llvm::Value* valueConstOne = llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 1); return llvm->builder.CreateAdd(valueEndOfRange, valueConstOne); }; default: break; } //return null pointer if (linkedlist){ return ConstantPointerNull::getNullValue(sourceRawType); } assert(false && "Unknown declaration"); return nullptr; } llvm::Value* IteratorForward::get(Value* index,const std::string& hintRetVar){ const Expression& currentDecl = CodeScope::getDeclaration(current); switch (currentDecl.op) { case xreate::Operator::LIST: { //TODO re check is it right scope(source) to compile currentDecl. Provide unittests. llvm::Value* currentValue = sourceUnit->processSymbol(current); return xreate::compilation::Advanced(context).compileArrayIndex(currentValue, std::vector{index}); }; case xreate::Operator::LIST_RANGE: { return index; }; case xreate::Operator::MAP: { assert(currentDecl.getOperands().size()==1); assert(currentDecl.bindings.size()); assert(currentDecl.blocks.size()); CodeScope* scopeLoop = currentDecl.blocks.front(); std::string varEl = currentDecl.bindings[0]; const Symbol& symbIn = Attachments::get(currentDecl.getOperands()[0]); auto it = std::unique_ptr(Iterator::create(context, symbIn)); Value* elIn = it->get(index, varEl); - compilation::AbstractCodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); + compilation::ICodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); unitLoop->bindArg(elIn, std::move(varEl)); return unitLoop->compile(); } case xreate::Operator::NONE: { //TODO review iterator determination strategy for case of Expression::BINDING assert(currentDecl.__state==Expression::IDENT); const Symbol& symbIn = Attachments::get(currentDecl); auto it = std::unique_ptr(Iterator::create(context, symbIn)); return it->get(index); }; default: break; } if (linkedlist){ return index; } assert(false && "Unknown declaration"); return nullptr; } llvm::Value* IteratorForward::advance(Value* index, const std::string& hintRetVar){ switch(sourceDecl.op) { case xreate::Operator::LIST: case xreate::Operator::LIST_RANGE: return llvm->builder.CreateAdd(index, llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 1), hintRetVar); default: break; } if (linkedlist){ ExpandedType tySource = llvm->ast->getType(CodeScope::getDeclaration(source)); assert(tySource->__operator == TypeOperator::ARRAY && "Linked list implementation has to have ARRAY type"); assert(tySource->__operands.size()); return xreate::compilation::Advanced(context).compileStructIndex(index, ExpandedType(TypeAnnotation(tySource->__operands.at(0))), linkedlist.fieldPointer); } assert(false && "Unknown declaration"); return nullptr; } //const ImplementationRec& implementation IteratorForward::IteratorForward(const compilation::Context& ctx, const xreate::Symbol& symbolContainer, const ImplementationRec& implementation) : Iterator(), __length(implementation.size), llvm(ctx.pass->man->llvm) { __container = ctx.function->getScopeUnit(symbolContainer.scope)->processSymbol(symbolContainer); } llvm::Value* IteratorForward::begin(){ //0 return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 0); } llvm::Value* IteratorForward::end(){ //length return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), __length); } llvm::Value* IteratorForward::get(llvm::Value* index,const std::string& hintRetVar){ //GEP[index]] llvm::Type* tyNum = llvm::Type::getInt32Ty(llvm::getGlobalContext()); llvm::Value* pResult = llvm->builder.CreateGEP(__container, ArrayRef(std::vector{ConstantInt::get(tyNum, 0), index})); return llvm->builder.CreateLoad(pResult, hintRetVar); } llvm::Value* IteratorForward::advance(llvm::Value* index, const std::string& hintRetVar){ //index + 1 llvm::Type* tyNum = llvm::Type::getInt32Ty(llvm::getGlobalContext()); return llvm->builder.CreateAdd(index, llvm::ConstantInt::get(tyNum, 1), hintRetVar); } diff --git a/cpp/src/compilation/containers.h b/cpp/src/compilation/containers.h index 71815a7..89969b8 100644 --- a/cpp/src/compilation/containers.h +++ b/cpp/src/compilation/containers.h @@ -1,80 +1,80 @@ #ifndef CODEINSTRUCTIONS_H #define CODEINSTRUCTIONS_H #include "ast.h" #include "llvmlayer.h" #include "pass/compilepass.h" #include "compilation/advanced.h" #include "query/context.h" #include "query/containers.h" namespace xreate { namespace containers { using namespace llvm; class Iterator{ public : virtual llvm::Value* begin() =0; virtual llvm::Value* end() = 0; virtual llvm::Value* get(llvm::Value* index,const std::string& hintRetVar="") = 0; virtual llvm::Value* advance(llvm::Value* index, const std::string& hintRetVar="")=0; virtual ~Iterator(){}; static Iterator* create(xreate::compilation::Context context, const xreate::Symbol& var); }; template class IteratorForward; template<> class IteratorForward : public Iterator { private: LLVMLayer* llvm; const xreate::Symbol current; const Symbol source; const ImplementationLinkedList linkedlist; CodeScope* const sourceScope; //TODO initialize and mark as const (three fields) - compilation::AbstractCodeScopeUnit* sourceUnit; - compilation::FunctionUnit* function; //TODO is used somewhere? + compilation::ICodeScopeUnit* sourceUnit; + compilation::IFunctionUnit* function; //TODO is used somewhere? const Expression& sourceDecl; compilation::Context context; llvm::Type* sourceRawType =nullptr; public: IteratorForward(const compilation::Context& ctx, const xreate::Symbol& s, const ImplementationRec& implementation) : llvm(ctx.pass->man->llvm), current(s), source(implementation.source), linkedlist(source), sourceScope(source.scope), sourceUnit(ctx.function->getScopeUnit(source.scope)), sourceDecl(CodeScope::getDeclaration(source)), context(ctx) {} llvm::Value* begin() override; llvm::Value* end() override; llvm::Value* get(llvm::Value* index,const std::string& hintRetVar="") override; llvm::Value* advance(llvm::Value* index, const std::string& hintRetVar="") override; }; template<> class IteratorForward: public Iterator{ size_t __length; llvm::Value* __container; LLVMLayer* llvm; public: IteratorForward(const compilation::Context& ctx, const xreate::Symbol& symbolContainer, const ImplementationRec& implementation); llvm::Value* begin() override; llvm::Value* end() override; llvm::Value* get(llvm::Value* index,const std::string& hintRetVar="") override; llvm::Value* advance(llvm::Value* index, const std::string& hintRetVar="") override; }; }} #endif //CODEINSTRUCTIONS_H diff --git a/cpp/src/compilation/latecontextcompiler2.cpp b/cpp/src/compilation/latecontextcompiler2.cpp index 93bdb9d..02f3cf4 100644 --- a/cpp/src/compilation/latecontextcompiler2.cpp +++ b/cpp/src/compilation/latecontextcompiler2.cpp @@ -1,193 +1,195 @@ /* * LateContextCompiler2.cpp * * Created on: 10 февр. 2016 * Author: pgess */ //TOTEST default variants - do not enable specialization context in order to check default variant invocation #include "latecontextcompiler2.h" #include "llvmlayer.h" #include "pass/compilepass.h" #include "query/context.h" #include using namespace std; namespace xreate {namespace context{ const string topicSpecializationAtom = "specialization"; const string topicDependencyAtom = "dependency"; typedef ExpressionSerialization::Code DomainId; typedef ExpressionSerialization::Serializer Domain; //TODO implement variantDefault; llvm::Value* compileDecisionSelector(llvm::IRBuilder<>& builder, llvm::Value* selector, std::vector vectorVariants, llvm::Value* variantDefault=nullptr){ assert(vectorVariants.size()>0); llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); llvm::Type* tyElement = vectorVariants[0]->getType(); llvm::Type* tyVariants = llvm::VectorType::get(tyElement, vectorVariants.size()); llvm::Value* vectorRaw = llvm::ConstantVector::getNullValue(tyVariants); for(DomainId i=0; iqueryContext; __sizeOfDemand = context->getFunctionDemand(function->function->getName()).size(); } llvm::Value* LateContextCompiler2::findFunction(const std::string& calleeName, llvm::Function* specializationDefault, ScopePacked scopeCaller){ const string& functionName = function->function->getName(); ContextQuery* context = pass->queryContext; llvm::IRBuilder<>& builder = pass->man->llvm->builder; const FunctionDemand& demand = context->getFunctionDemand(functionName); const std::list& specializations = pass->man->root->getFunctionVariants(calleeName); //independent decision: - Expression topic(Operator::CALL, {(Atom(string(topicSpecializationAtom))), (Atom(string(calleeName))), (Atom(scopeCaller))}); + Expression topic(Operator::CALL, {(Atom(string(topicSpecializationAtom))), + Expression(Operator::CALL, {Atom(string(calleeName))}), + Atom(scopeCaller)}); assert(demand.right.count(topic) && "Can't determine specialization for the function"); size_t topicId = demand.right.at(topic); llvm::Value* topicDecisionRaw = builder.CreateExtractValue(this->rawContextArgument, llvm::ArrayRef{(unsigned) topicId}); const Domain& specializationsDomain= context->getTopicDomain(topic); std::vector vectorVariants; vectorVariants.reserve(specializationsDomain.size()); for (const ManagedFnPtr& f: specializations){ if (!f->guardContext.isValid()) continue; const auto& variantId = specializationsDomain.getIdOptional(f->guardContext); if (variantId){ if (vectorVariants.size() < *variantId + 1) { vectorVariants.resize(*variantId + 1); } vectorVariants[*variantId] = pass->getFunctionUnit(f)->compile(); } } return compileDecisionSelectorAsSwitch(topicDecisionRaw, vectorVariants, specializationDefault); } llvm::Value* LateContextCompiler2::compileContextArgument(const std::string& callee, ScopePacked scopeCaller){ const std::string& atomDependentDecision = Config::get("clasp.context.decisions.dependent"); llvm::IRBuilder<>& builder = pass->man->llvm->builder; ContextQuery* context = pass->queryContext; const string& functionName = function->function->getName(); const Decisions& dictStaticDecisions = context->getFinalDecisions(scopeCaller); const FunctionDemand& demandCallee = context->getFunctionDemand(callee); const FunctionDemand& demandSelf = context->getFunctionDemand(functionName); llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); llvm::Type* tyDemand = llvm::ArrayType::get(ty32, demandCallee.size()); //builder.CreateAlloca(tyDemand, llvm::ConstantInt::get(ty32, 1)); llvm::Value* res = llvm::ConstantArray::getNullValue(tyDemand); for (size_t i=0, size = demandCallee.size(); irawContextArgument, llvm::ArrayRef{(unsigned) topicId}); } else if (dictStaticDecisions.count(topic)){ //static final decision: const Expression& decision = dictStaticDecisions.at(topic); const Domain& domainOfTopic = context->getTopicDomain(topic); const DomainId& decisionCode = domainOfTopic.getId(decision); decisionRaw = llvm::ConstantInt::get(ty32, decisionCode); } else { //dependent decision decisionRaw = compileDependentDecision(topic, scopeCaller); } res = builder.CreateInsertValue(res, decisionRaw, llvm::ArrayRef{(unsigned) i}); } return res; } llvm::Value* LateContextCompiler2::compileDependentDecision(const Expression& topic, ScopePacked scopeCaller){ const string& functionName = function->function->getName(); ContextQuery* context = pass->queryContext; llvm::IRBuilder<>& builder = pass->man->llvm->builder; llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); const FunctionDemand& demandSelf = context->getFunctionDemand(functionName); const Expression topicDependency = Expression(Operator::CALL, {Atom(string(topicDependencyAtom)), topic, Atom(scopeCaller)}); const Domain& demandOfTopic = context->getTopicDomain(topic); const Domain& domainOfTopicDependency = context->getTopicDomain(topicDependency); //dependent decision vector vectorDecisions(domainOfTopicDependency.size(), llvm::UndefValue::get(ty32)); for (const std::pair& entry: context->getDependentDecision(scopeCaller,topic)){ vectorDecisions[domainOfTopicDependency.getId(entry.first)]= llvm::ConstantInt::get(ty32, demandOfTopic.getId(entry.second)); } size_t topicDependencyId = demandSelf.right.at(topicDependency); llvm::Value* decisionRaw = builder.CreateExtractValue(this->rawContextArgument, llvm::ArrayRef{(unsigned) topicDependencyId}); auto result = compileDecisionSelector(pass->man->llvm->builder, decisionRaw, vectorDecisions); return result; } llvm::Value* LateContextCompiler2::compileDecisionSelectorAsSwitch(llvm::Value* selector, std::vector vectorVariants, llvm::Function* variantDefault){ llvm::IRBuilder<>& builder = pass->man->llvm->builder; llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); llvm::BasicBlock* blockDefault = llvm::BasicBlock::Create(llvm::getGlobalContext(), "caseDefault", this->function->raw); llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "VariantDeterminationEnd", this->function->raw); llvm::SwitchInst* instrSwitch = builder.CreateSwitch(selector, blockDefault, vectorVariants.size()); builder.SetInsertPoint(blockEpilog); llvm::PHINode *result = builder.CreatePHI(variantDefault->getType(), vectorVariants.size(), "callee"); for (size_t i=0; ifunction->raw); builder.SetInsertPoint(blockCase); builder.CreateBr(blockEpilog); result->addIncoming(vectorVariants[i], blockCase); instrSwitch->addCase(llvm::ConstantInt::get(ty32, i), blockCase); } builder.SetInsertPoint(blockDefault); builder.CreateBr(blockEpilog); result->addIncoming(variantDefault, blockDefault); builder.SetInsertPoint(blockEpilog); return result; } size_t LateContextCompiler2::getFunctionDemandSize() const { return __sizeOfDemand; } }} /* namespace xreate::context */ diff --git a/cpp/src/compilation/latecontextcompiler2.h b/cpp/src/compilation/latecontextcompiler2.h index 8d8234d..f4d91ab 100644 --- a/cpp/src/compilation/latecontextcompiler2.h +++ b/cpp/src/compilation/latecontextcompiler2.h @@ -1,51 +1,51 @@ /* * LateContextCompiler2.h * * Created on: 10 февр. 2016 * Author: pgess */ //TOTEST compile several context arguments #ifndef LATECONTEXTCOMPILER2_H_ #define LATECONTEXTCOMPILER2_H_ #include "serialization.h" namespace llvm { class Value; class Function; } namespace xreate { class CompilePass; namespace compilation { - class FunctionUnit; + class IFunctionUnit; }} namespace xreate {namespace context{ typedef unsigned int ScopePacked; class LateContextCompiler2 { public: llvm::Value* rawContextArgument = nullptr; - LateContextCompiler2(compilation::FunctionUnit* f, CompilePass* p); + LateContextCompiler2(compilation::IFunctionUnit* f, CompilePass* p); llvm::Value* findFunction(const std::string& calleeName, llvm::Function* specializationDefault, ScopePacked scopeCaller); llvm::Value* compileContextArgument(const std::string& callee, ScopePacked scopeCaller); size_t getFunctionDemandSize() const; private: //boost::bimap __decisions; //std::vector __scheme; - compilation::FunctionUnit* function; + compilation::IFunctionUnit* function; CompilePass* pass; size_t __sizeOfDemand; llvm::Value* compileDependentDecision(const Expression& topic, ScopePacked scopeCaller); llvm::Value* compileDecisionSelectorAsSwitch(llvm::Value* selector, std::vector vectorVariants, llvm::Function* variantDefault); }; }} /* namespace xreate::context */ #endif /* LATECONTEXTCOMPILER2_H_ */ \ No newline at end of file diff --git a/cpp/src/compilation/scopedecorators.h b/cpp/src/compilation/scopedecorators.h index 0c6aa78..8c3146f 100644 --- a/cpp/src/compilation/scopedecorators.h +++ b/cpp/src/compilation/scopedecorators.h @@ -1,129 +1,129 @@ /* * File: scopedecorators.h * Author: pgess * * Created on February 24, 2017, 11:35 AM */ #ifndef SCOPEDECORATORS_H #define SCOPEDECORATORS_H #include "ast.h" #include "compilation/targetinterpretation.h" #include "compilation/versions.h" #include "compilation/transformations.h" namespace xreate { class CompilePass; namespace compilation { -class AbstractCodeScopeUnit; -class FunctionUnit; +class ICodeScopeUnit; +class IFunctionUnit; template class CachedScopeDecorator: public Parent{ typedef CachedScopeDecorator SELF; public: - CachedScopeDecorator(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} + CachedScopeDecorator(CodeScope* codeScope, IFunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} void bindArg(llvm::Value* value, std::string&& alias) { //ensure existence of an alias assert(Parent::scope->__identifiers.count(alias)); //memorize new value for an alias - ScopedSymbol id{Parent::scope->__identifiers.at(alias), VERSION_NONE}; + ScopedSymbol id{Parent::scope->__identifiers.at(alias), versions::VERSION_NONE}; __rawVars[id] = value; } void bindArg(llvm::Value* value, const ScopedSymbol& s) { __rawVars[s] = value; } llvm::Value* compile(const std::string& hintBlockDecl="") override{ if (__rawVars.count(ScopedSymbol::RetSymbol)){ return __rawVars[ScopedSymbol::RetSymbol]; } return Parent::compile(hintBlockDecl); } llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar) override{ CodeScope* scope = s.scope; SELF* self = dynamic_cast(Parent::function->getScopeUnit(scope)); if (self->__rawVars.count(s.identifier)){ return self->__rawVars[s.identifier]; } //Declaration could be overriden Expression declaration = CodeScope::getDeclaration(s); if (!declaration.isDefined()){ if (self->__declarationsOverriden.count(s.identifier)){ declaration = self->__declarationsOverriden[s.identifier]; } else { assert(false); //in case of binding there should be raws provided. } } return self->__rawVars[s.identifier] = Parent::processSymbol(s, hintRetVar); } void overrideDeclaration(const Symbol binding, Expression&& declaration){ SELF* self = dynamic_cast(Parent::function->getScopeUnit(binding.scope)); self->__declarationsOverriden.emplace(binding.identifier, std::move(declaration)); } - void registerChildScope(std::shared_ptr scope){ + void registerChildScope(std::shared_ptr scope){ __childScopes.push_back(scope); } void reset(){ __rawVars.clear(); __declarationsOverriden.clear(); __childScopes.clear(); } private: std::unordered_map __declarationsOverriden; std::unordered_map __rawVars; - std::list> __childScopes; + std::list> __childScopes; }; typedef CachedScopeDecorator< compilation::TransformationsScopeDecorator< interpretation::InterpretationScopeDecorator< versions::VersionsScopeDecorator>>> - DefaultScopeUnit; + DefaultCodeScopeUnit; } //end of compilation namespace struct CachedScopeDecoratorTag; struct VersionsScopeDecoratorTag; template<> struct DecoratorsDict{ typedef compilation::CachedScopeDecorator< compilation::TransformationsScopeDecorator< interpretation::InterpretationScopeDecorator< versions::VersionsScopeDecorator>>> result; }; template<> struct DecoratorsDict{ typedef versions::VersionsScopeDecorator< compilation::BasicCodeScopeUnit> result; }; } //end of xreate #endif /* SCOPEDECORATORS_H */ diff --git a/cpp/src/compilation/targetinterpretation.cpp b/cpp/src/compilation/targetinterpretation.cpp index 3c79321..513a3a2 100644 --- a/cpp/src/compilation/targetinterpretation.cpp +++ b/cpp/src/compilation/targetinterpretation.cpp @@ -1,442 +1,442 @@ /* * File: targetinterpretation.cpp * Author: pgess * * Created on June 29, 2016, 6:45 PM */ #include "compilation/targetinterpretation.h" #include "pass/interpretationpass.h" #include "llvmlayer.h" #include "compilation/scopedecorators.h" #include #include #include using namespace std; using namespace xreate::compilation; namespace xreate{ namespace interpretation{ const Expression EXPRESSION_FALSE = Expression(Atom(0)); const Expression EXPRESSION_TRUE = Expression(Atom(1)); //Expression //InterpretationScope::compile(const Expression& expression){} CodeScope* InterpretationScope::processOperatorIf(const Expression& expression){ const Expression& exprCondition = process(expression.getOperands()[0]); if (exprCondition == EXPRESSION_TRUE){ return expression.blocks.front(); } return expression.blocks.back(); } CodeScope* InterpretationScope::processOperatorSwitch(const Expression& expression) { const Expression& exprCondition = process(expression.operands[0]); bool flagHasDefault = expression.operands[1].op == Operator::CASE_DEFAULT; //TODO check that one and only one case variant is appropriate for (size_t size = expression.operands.size(), i= flagHasDefault? 2: 1; igetScope(exprCase.blocks.front())->processScope() == exprCondition){ return exprCase.blocks.back(); } } if (flagHasDefault){ const Expression& exprCaseDefault = expression.operands[1]; return exprCaseDefault.blocks.front(); } assert(false && "Switch has no appropriate variant"); return nullptr; } llvm::Value* InterpretationScope::compileHybrid(const InterpretationOperator& op, const Expression& expression, const Context& context){ switch(op){ case IF_INTERPRET_CONDITION: { CodeScope* scopeResult = processOperatorIf(expression); llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); return result; } case SWITCH_INTERPRET_CONDITION:{ CodeScope* scopeResult = processOperatorSwitch(expression); llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); return result; } case FOLD_INTERPRET_INPUT: { //initialization const Expression& exprInput = process(expression.getOperands()[0]); assert(exprInput.op == Operator::LIST); CodeScope* scopeBody = expression.blocks.front(); const string& nameEl = expression.bindings[0]; - Symbol symbEl{ScopedSymbol{scopeBody->__identifiers.at(nameEl), VERSION_NONE}, scopeBody}; + Symbol symbEl{ScopedSymbol{scopeBody->__identifiers.at(nameEl), versions::VERSION_NONE}, scopeBody}; const std::string& idAccum = expression.bindings[1]; llvm::Value* rawAccum = context.scope->process(expression.getOperands()[1]); InterpretationScope* intrBody = function->getScope(scopeBody); auto unitBody = Decorators::getInterface(context.function->getScopeUnit(scopeBody)); const std::vector elementsInput= exprInput.getOperands(); for (size_t i=0; ireset(); unitBody->reset(); Expression exprElement = elementsInput[i]; intrBody->overrideBinding(exprElement, nameEl); unitBody->overrideDeclaration(symbEl, move(exprElement)); unitBody->bindArg(rawAccum, string(idAccum)); rawAccum = unitBody->compile(); } return rawAccum; } /* case FOLD_INF_INTERPRET_INOUT{ } */ case CALL_INTERPRET_PARTIAL: { const std::string &calleeName = expression.getValueString(); - AbstractCodeScopeUnit* scopeUnitSelf = context.scope; + ICodeScopeUnit* scopeUnitSelf = context.scope; ManagedFnPtr callee = this->function->man->ast->findFunction(calleeName); const FunctionInterpretationData& calleeData = FunctionInterpretationHelper::getSignature(callee); std::vector argsActual; PIFSignature sig; sig.declaration = callee; for(size_t no=0, size = expression.operands.size(); no < size; ++no){ const Expression& op = expression.operands[no]; if (calleeData.signature.at(no) == INTR_ONLY){ sig.bindings.push_back(process(op)); continue; } argsActual.push_back(scopeUnitSelf->process(op)); } TargetInterpretation* man = dynamic_cast(this->function->man); PIFunction* pifunction = man->getFunction(move(sig)); llvm::Function* raw = pifunction->compile(); boost::scoped_ptr statement(new CallStatementRaw(raw, man->pass->man->llvm)); return (*statement)(move(argsActual)); } default: break; } assert(false&& "Unknown hybrid operator"); return nullptr; } llvm::Value* InterpretationScope::compile(const Expression& expression, const Context& context){ const InterpretationData& data = Attachments::get(expression); if (data.op != InterpretationOperator::NONE){ return compileHybrid(data.op, expression, context); } Expression result = process(expression); return context.scope->process(result); } Expression InterpretationScope::process(const Expression& expression){ switch (expression.__state){ case Expression::INVALID: assert(false); case Expression::VARIANT: case Expression::NUMBER: case Expression::STRING: return expression; case Expression::IDENT:{ Symbol s = Attachments::get(expression); return Parent::processSymbol(s); } case Expression::COMPOUND: break; default: assert(false); } switch (expression.op) { case Operator::EQU: { const Expression& left = process(expression.operands[0]); const Expression& right = process(expression.operands[1]); if (left == right) return EXPRESSION_TRUE; return EXPRESSION_FALSE; } case Operator::NE: { const Expression& left = process(expression.operands[0]); const Expression& right = process(expression.operands[1]); if (left == right) return EXPRESSION_FALSE; return EXPRESSION_TRUE; } case Operator::LOGIC_AND: { assert(expression.operands.size() == 1); return process (expression.operands[0]); } // case Operator::LOGIC_OR: case Operator::CALL: { const std::string &fnName = expression.getValueString(); ManagedFnPtr fnAst = this->function->man->ast->findFunction(fnName); InterpretationFunction* fnUnit = this->function->man->getFunction(fnAst); vector args; args.reserve(expression.getOperands().size()); for(size_t i=0, size = expression.getOperands().size(); iprocess(args); } case Operator::IF:{ CodeScope* scopeResult = processOperatorIf(expression); return function->getScope(scopeResult)->processScope(); } case Operator::SWITCH: { CodeScope* scopeResult = processOperatorSwitch(expression); return function->getScope(scopeResult)->processScope(); } case Operator::INDEX: { const Expression& exprKey = process(expression.operands[1]); const Expression& exprData = process(expression.operands[0]); if (exprKey.__state == Expression::STRING){ const string& key = exprKey.getValueString(); assert(exprData.__indexBindings.count(key)); return exprData.operands[exprData.__indexBindings.at(key)]; } if (exprKey.__state == Expression::NUMBER){ int key = exprKey.getValueDouble(); return exprData.operands[key]; } assert(false); } case Operator::FOLD: { const Expression& exprInput = process(expression.getOperands()[0]); const Expression& exprInit = process(expression.getOperands()[1]); const std::string& argEl = expression.bindings[0]; const std::string& argAccum = expression.bindings[1]; InterpretationScope* body = function->getScope(expression.blocks.front()); Expression accum = exprInit; for(size_t size=exprInput.getOperands().size(), i=0; ioverrideBinding(exprInput.getOperands()[i], argEl); body->overrideBinding(accum, argAccum); accum = body->processScope(); } return accum; } // case Operator::MAP: { // break; // } default: break; } return expression; } InterpretationFunction* -TargetInterpretation::getFunction(FunctionUnit* unit){ +TargetInterpretation::getFunction(IFunctionUnit* unit){ if (__dictFunctionsByUnit.count(unit)) { return __dictFunctionsByUnit.at(unit); } InterpretationFunction* f = new InterpretationFunction(unit->function, this); __dictFunctionsByUnit.emplace(unit, f); assert(__functions.emplace(unit->function.id(), f).second); return f; } PIFunction* TargetInterpretation::getFunction(PIFSignature&& sig){ auto f = __pifunctions.find(sig); if (f != __pifunctions.end()){ return f->second; } PIFunction* result = new PIFunction(PIFSignature(sig), __pifunctions.size(), this); __pifunctions.emplace(move(sig), result); assert(__dictFunctionsByUnit.emplace(result->functionUnit, result).second); return result; } InterpretationScope* TargetInterpretation::transformContext(const Context& c){ return this->getFunction(c.function)->getScope(c.scope->scope); } llvm::Value* TargetInterpretation::compile(const Expression& expression, const Context& ctx){ return transformContext(ctx)->compile(expression, ctx); } InterpretationFunction::InterpretationFunction(const ManagedFnPtr& function, Target* target) : Function(function, target) {} Expression InterpretationFunction::process(const std::vector& args){ InterpretationScope* body = getScope(__function->__entry); for(size_t i=0, size = args.size(); ioverrideBinding(args.at(i), string(body->scope->__bindings.at(i))); } return body->processScope(); } // Partial function interpretation -typedef BasicFunctionDecorator PIFunctionUnitParent; +typedef BasicFunctionUnit PIFunctionUnitParent; class PIFunctionUnit: public PIFunctionUnitParent{ public: PIFunctionUnit(ManagedFnPtr f, std::set&& arguments, size_t id, CompilePass* p) : PIFunctionUnitParent(f, p), argumentsActual(move(arguments)), __id(id) {} protected: std::vector prepareArguments(){ LLVMLayer* llvm = PIFunctionUnitParent::pass->man->llvm; AST* ast = PIFunctionUnitParent::pass->man->root; CodeScope* entry = PIFunctionUnitParent::function->__entry; std::vector signature; for(size_t no: argumentsActual){ VNameId argId = entry->__identifiers.at(entry->__bindings.at(no)); - ScopedSymbol arg{argId, VERSION_NONE}; + ScopedSymbol arg{argId, versions::VERSION_NONE}; signature.push_back(llvm->toLLVMType(ast->expandType(entry->__declarations.at(arg).type))); } return signature; } llvm::Function::arg_iterator prepareBindings(){ CodeScope* entry = PIFunctionUnitParent::function->__entry; - AbstractCodeScopeUnit* entryCompilation = PIFunctionUnitParent::getScopeUnit(entry); + ICodeScopeUnit* entryCompilation = PIFunctionUnitParent::getScopeUnit(entry); llvm::Function::arg_iterator fargsI = PIFunctionUnitParent::raw->arg_begin(); for(size_t no: argumentsActual){ - ScopedSymbol arg{entry->__identifiers.at(entry->__bindings.at(no)), VERSION_NONE}; + ScopedSymbol arg{entry->__identifiers.at(entry->__bindings.at(no)), versions::VERSION_NONE}; entryCompilation->bindArg(&*fargsI, arg); fargsI->setName(entry->__bindings.at(no)); ++fargsI; } return fargsI; } virtual std::string prepareName(){ return PIFunctionUnitParent::prepareName() + "_" + std::to_string(__id); } private: std::set argumentsActual; size_t __id; }; PIFunction::PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target) : InterpretationFunction(sig.declaration, target), signatureInstance(move(sig)) { const FunctionInterpretationData& functionData = FunctionInterpretationHelper::getSignature(signatureInstance.declaration); std::set argumentsActual; for (size_t no=0, size=functionData.signature.size(); no < size; ++no){ if (functionData.signature.at(no) != INTR_ONLY){ argumentsActual.insert(no); } } functionUnit = new PIFunctionUnit(signatureInstance.declaration, move(argumentsActual), id, target->pass); CodeScope* entry = signatureInstance.declaration->__entry; auto entryUnit = Decorators::getInterface<>(functionUnit->getEntry()); InterpretationScope* entryIntrp = InterpretationFunction::getScope(entry); for(size_t no=0, sigNo=0, size = entry->__bindings.size(); no < size; ++no){ if (functionData.signature.at(no) == INTR_ONLY){ entryIntrp->overrideBinding(signatureInstance.bindings[sigNo], entry->__bindings[no]); VNameId argId = entry->__identifiers.at(entry->__bindings[no]); - Symbol argSymbol{ScopedSymbol{argId, VERSION_NONE}, entry}; + Symbol argSymbol{ScopedSymbol{argId, versions::VERSION_NONE}, entry}; entryUnit->overrideDeclaration(argSymbol, Expression(signatureInstance.bindings[sigNo])); ++sigNo; } } } llvm::Function* PIFunction::compile(){ llvm::Function* raw = functionUnit->compile(); return raw; } bool operator<(const PIFSignature& lhs, const PIFSignature& rhs){ if (lhs.declaration.id() != rhs.declaration.id()) { return lhs.declaration.id() < rhs.declaration.id(); } return lhs.bindings < rhs.bindings; } bool operator<(const PIFSignature& lhs, PIFunction* const rhs){ return lhs < rhs->signatureInstance; } bool operator<(PIFunction* const lhs, const PIFSignature& rhs){ return lhs->signatureInstance < rhs; } }} diff --git a/cpp/src/compilation/targetinterpretation.h b/cpp/src/compilation/targetinterpretation.h index a36b08a..3a47bdd 100644 --- a/cpp/src/compilation/targetinterpretation.h +++ b/cpp/src/compilation/targetinterpretation.h @@ -1,130 +1,130 @@ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * 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" 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{ class InterpretationScope: public compilation::Scope{ typedef Scope Parent; public: InterpretationScope(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); }; class InterpretationFunction: public compilation::Function{ public: InterpretationFunction(const ManagedFnPtr& function, compilation::Target* target); Expression process(const std::vector& args); }; /* * Partially interpreted function signature */ struct PIFSignature{ ManagedFnPtr declaration; std::vector bindings; }; class PIFunctionUnit; 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); class TargetInterpretation: public compilation::Target{ public: TargetInterpretation(AST* root, CompilePass* passCompilation): Target(root), pass(passCompilation){} //target: public: - InterpretationFunction* getFunction(compilation::FunctionUnit* unit); + InterpretationFunction* getFunction(compilation::IFunctionUnit* unit); PIFunction* getFunction(PIFSignature&& sig); private: std::map __pifunctions; - std::map __dictFunctionsByUnit; + std::map __dictFunctionsByUnit; //self: public: CompilePass* pass; llvm::Value* compile(const Expression& expression, const compilation::Context& ctx); private: InterpretationScope* transformContext(const compilation::Context& c); }; template class InterpretationScopeDecorator: public Parent{ public: - InterpretationScopeDecorator(CodeScope* codeScope, compilation::FunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} + InterpretationScopeDecorator(CodeScope* 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); } }; }} //end of xreate:: interpretation #endif /* TARGETSTATIC_H */ //transformers: // template<> // struct TransformerInfo { // static const int id = 1; // }; \ No newline at end of file diff --git a/cpp/src/compilation/targets.h b/cpp/src/compilation/targets.h index 6b891c7..b7247cd 100644 --- a/cpp/src/compilation/targets.h +++ b/cpp/src/compilation/targets.h @@ -1,191 +1,191 @@ /* * File: targetabstract.h * Author: pgess * * Created on July 2, 2016, 1:25 PM */ #ifndef TARGETABSTRACT_H #define TARGETABSTRACT_H #include "ast.h" #include #include namespace xreate{ namespace compilation { template struct TargetInfo{ //typedef Result //typedef Function //typedef Scope }; template class Function; template class Target; template class Scope{ typedef typename TargetInfo::Scope Self; public: CodeScope* scope; typename TargetInfo::Result processSymbol(const Symbol& s){ CodeScope* scope = s.scope; Self* self = function->getScope(scope); if (self->__bindings.count(s.identifier)) { return self->__bindings[s.identifier]; } const Expression& declaration = CodeScope::getDeclaration(s); if (!declaration.isDefined()){ assert(false); //for bindings there should be result already } return self->__bindings[s.identifier] = self->process(declaration); } typename TargetInfo::Result processScope() { if (raw) return *raw; raw = process(scope->getBody()); return *raw; } // typename TargetInfo::Result // processFunction(typename TargetInfo::Function* fnRemote, const std::vector::Result>& args){ // Scope scopeRemote = fnRemote->getScope(fnRemote->__function->__entry); // // if (scopeRemote->raw){ // return scopeRemote->raw; // } // // return fnRemote->process(args); // } virtual typename TargetInfo::Result process(const Expression& expression)=0; Scope(CodeScope* codeScope, Function* f) : scope(codeScope), function(f) {} virtual ~Scope(){} void overrideBinding(typename TargetInfo::Result arg, const std::string& name){ assert(scope->__identifiers.count(name)); - ScopedSymbol id{scope->__identifiers.at(name), VERSION_NONE}; + ScopedSymbol id{scope->__identifiers.at(name), versions::VERSION_NONE}; __bindings[id] = arg; //reset the result if any: raw.reset(); } void registerChildScope(std::shared_ptr scope){ __childScopes.push_back(scope); } void reset(){ __bindings.clear(); __childScopes.clear(); raw.reset(); } protected: Function* function=0; std::map::Result> __bindings; std::list> __childScopes; typename boost::optional::Result> raw; }; template class Function{ typedef typename TargetInfo::Result Result; typedef typename TargetInfo::Scope ConcreteScope; public: Function(const ManagedFnPtr& function, Target* target) : man(target), __function(function) {} virtual ~Function(){}; ConcreteScope* getScope(CodeScope* scope){ if (__scopes.count(scope)) { auto result = __scopes.at(scope).lock(); if (result){ return result.get(); } } std::shared_ptr unit(new ConcreteScope(scope, this)); if (scope->__parent != nullptr){ getScope(scope->__parent)->registerChildScope(unit); } else { assert(!__entryScope); __entryScope = unit; } if (!__scopes.emplace(scope, unit).second){ __scopes[scope] = unit; } return unit.get(); } virtual Result process(const std::vector& args)=0; Target* man=0; ManagedFnPtr __function; protected: std::map> __scopes; std::shared_ptr __entryScope; }; template class Target { typedef typename TargetInfo::Function ConcreteFunction; public: Target(AST* root): ast(root){} ConcreteFunction* getFunction(const ManagedFnPtr& function){ unsigned int id = function.id(); if (!__functions.count(id)){ ConcreteFunction* unit = new ConcreteFunction(function, this); __functions.emplace(id, unit); return unit; } return __functions.at(id); } AST* ast; virtual ~Target(){ for (const auto& entry: __functions){ delete entry.second; } } protected: std::map __functions; }; }} #endif /* TARGETABSTRACT_H */ diff --git a/cpp/src/compilation/transformations.h b/cpp/src/compilation/transformations.h index d2ac123..5455411 100644 --- a/cpp/src/compilation/transformations.h +++ b/cpp/src/compilation/transformations.h @@ -1,110 +1,110 @@ /* * File: transformations.h * Author: pgess * * Created on March 25, 2017, 9:04 PM */ #ifndef TRANSFORMATIONS_H #define TRANSFORMATIONS_H #include "pass/compilepass.h" namespace xreate { namespace compilation { template struct TransformerInfo { //static const unsigned int id = 1; (current vacant id) }; class Transformer{ public: virtual llvm::Value* transform(const Expression& expression, llvm::Value* raw, const Context& ctx)=0; virtual ~Transformer(){}; }; class TransformationsManager { public: std::list getRelevantTransformers(const Expression& expression); template void registerTransformer(const std::string& annotation, TransformerType* t){ const int id = TransformerInfo::id; assert(!__transformers.count(id)); __transformers[id] = t; __subscriptions.emplace(annotation, id); } template void unregisterTransformer(const std::string& annotation, TransformerType* t){ const unsigned int id = TransformerInfo::id; auto range = __subscriptions.equal_range(annotation); const auto entry = make_pair(annotation, id); __subscriptions.erase(std::find_if(range.first, range.second, [id](const auto& el){return el.second == id;})); __transformers.erase(id); } template TransformerType* update(TransformerType* newInstance){ const int id = TransformerInfo::id; Transformer* oldInstance = __transformers[id]; __transformers[id] = newInstance; return static_cast(oldInstance); } template bool exists(){ const int id = TransformerInfo::id; return __transformers.count(id); } template TransformerType* get(){ const int id = TransformerInfo::id; return static_cast(__transformers.at(id)); } private: std::map __transformers; std::multimap __subscriptions; }; template class TransformationsScopeDecorator: public Transformer, public Parent { // SCOPE DECORATOR PART public: - TransformationsScopeDecorator(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass) + TransformationsScopeDecorator(CodeScope* codeScope, IFunctionUnit* f, CompilePass* compilePass) : Parent(codeScope, f, compilePass){} virtual llvm::Value* process(const Expression& expr, const std::string& hintVarDecl=""){ llvm::Value* result = Parent::process(expr, hintVarDecl); return transform(expr, result, Context{this, Parent::function, Parent::pass}); } // TRANSFORMER PART public: virtual llvm::Value* transform(const Expression& expression, llvm::Value* raw, const Context& ctx) { llvm::Value* result = raw; TransformationsManager* man = Parent::pass->managerTransformations; if (expression.tags.size()) for (Transformer* handler: man->getRelevantTransformers(expression)){ result = handler->transform(expression, result, ctx); } return result; } }; } } #endif /* TRANSFORMATIONS_H */ diff --git a/cpp/src/compilation/versions.h b/cpp/src/compilation/versions.h index bc958e6..82ca3fc 100644 --- a/cpp/src/compilation/versions.h +++ b/cpp/src/compilation/versions.h @@ -1,125 +1,126 @@ /* * versions.cpp * * Author: pgess * Created on January 21, 2017, 1:24 PM */ #include "pass/versionspass.h" #include "pass/compilepass.h" +#include "llvmlayer.h" namespace xreate { class CompilePass; namespace compilation { - class AbstractCodeScopeUnit; - class FunctionUnit; + class ICodeScopeUnit; + class IFunctionUnit; } namespace versions{ template class VersionsScopeDecorator: public Parent{ typedef VersionsScopeDecorator SELF; public: - VersionsScopeDecorator(CodeScope* codeScope, compilation::FunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} + VersionsScopeDecorator(CodeScope* codeScope, compilation::IFunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} virtual llvm::Value* processSymbol(const Symbol& s, std::string hintSymbol=""){ if (Attachments::exists(s)){ const std::list dependencies = Attachments::get(s); for(const Symbol& symbolDependent: dependencies){ processSymbol(symbolDependent); } } llvm::Value* result = Parent::processSymbol(s, hintSymbol); if (s.identifier.version == VERSION_INIT){ llvm::Value* storage = SELF::processIntrinsicInit(result->getType(), hintSymbol); setSymbolStorage(s, storage); processIntrinsicCopy(result, storage); - return compilation::AbstractCodeScopeUnit::pass->man->llvm->builder.CreateLoad(storage); + return compilation::ICodeScopeUnit::pass->man->llvm->builder.CreateLoad(storage); } else if (s.identifier.version != VERSION_NONE){ Symbol symbolInitVersion = getSymbolInitVersion(s); llvm::Value* storage = getSymbolStorage(symbolInitVersion); processIntrinsicCopy(result, storage); - return compilation::AbstractCodeScopeUnit::pass->man->llvm->builder.CreateLoad(storage); + return compilation::ICodeScopeUnit::pass->man->llvm->builder.CreateLoad(storage); } return result; } llvm::Value* processIntrinsicInit(llvm::Type* typeStorage, const std::string& hintVarDecl=""){ llvm::IntegerType* tyInt = llvm::Type::getInt32Ty(llvm::getGlobalContext()); llvm::ConstantInt* constOne = llvm::ConstantInt::get(tyInt, 1, false); - return compilation::AbstractCodeScopeUnit::pass->man->llvm->builder.CreateAlloca(typeStorage, constOne, hintVarDecl); + return compilation::ICodeScopeUnit::pass->man->llvm->builder.CreateAlloca(typeStorage, constOne, hintVarDecl); } void processIntrinsicCopy(llvm::Value* value, llvm::Value* storage){ - compilation::AbstractCodeScopeUnit::pass->man->llvm->builder.CreateStore(value, storage); + compilation::ICodeScopeUnit::pass->man->llvm->builder.CreateStore(value, storage); } private: std::map __symbolStorage; static Symbol getSymbolInitVersion(const Symbol& s){ return Symbol{ScopedSymbol{s.identifier.id, VERSION_INIT}, s.scope}; } llvm::Value* getSymbolStorage(const Symbol& s){ return __symbolStorage.at(s); } void setSymbolStorage(const Symbol& s, llvm::Value* storage){ __symbolStorage[s] = storage; } }; } } //end of namespace xreate::versions // llvm::Value* // processIntrinsicInitAndCopy(){ // // } //llvm::Value* //process(const Expression& expr, const std::string& hintVarDecl){ // case Operator::CALL_INTRINSIC: { // enum INRINSIC{INIT, COPY}; // // const ExpandedType& typSymbol = pass->man->root->expandType(expr.type); // // INTRINSIC op = (INTRINSIC) expr.getValueDouble(); // // switch (op){ // case INIT: { // llvm::Type* typSymbolRaw = l.toLLVMType(typSymbol); // // // return storage; // } // // case COPY: { // llvm::Type* typSymbolRaw = l.toLLVMType(typSymbol); // llvm::value* valueOriginal = process(expr.getOperands()[0], hintVarDecl); // llvm::Value* storage = l.builder.CreateAlloca(typSymbolRaw, constOne, hintVarDecl); // llvm::Value* valueCopy = l.builder.CreateStore(valueOriginal, storage); // // return valueCopy; // } // } // return; // } //} //}; \ No newline at end of file diff --git a/cpp/src/pass/adhocpass.cpp b/cpp/src/pass/adhocpass.cpp index b7bdd7e..411efa3 100644 --- a/cpp/src/pass/adhocpass.cpp +++ b/cpp/src/pass/adhocpass.cpp @@ -1,95 +1,95 @@ /* * adhoc.cpp * * Created on: Nov 28, 2015 * Author: pgess */ #include "pass/adhocpass.h" #include "query/context.h" namespace xreate { namespace adhoc { AdhocExpression::AdhocExpression(): Expression(Operator::ADHOC, {}) {} AdhocExpression::AdhocExpression(const Expression& base): Expression(base) {} void AdhocExpression::setCommand(const Expression& comm){ this->addTags({Expression(Operator::CALL, {Atom("adhoc"), comm})}); } Expression AdhocExpression::getCommand() const{ assert(this->tags.count("adhoc")); return this->tags.at("adhoc").getOperands().at(0); } AdhocScheme* AdhocPass::findAssotiatedScheme(CodeScope* entry){ const ScopePacked scopeId = man->clasp->pack(entry); const context::Domain& domain = queryContext->getContext(scopeId); AdhocScheme* scheme = nullptr; for (const Expression& context: domain){ - if (context.__state != Expression::IDENT) continue; + if (!(context.__state == Expression::COMPOUND && context.op == Operator::CALL)) continue; - if (__schemes.count(context.getValueString())){ - assert(!scheme && "Can't determine relevant scheme, ambiguous context"); - scheme = __schemes.at(context.getValueString()); - } + if (__schemes.count(context.getValueString())){ + assert(!scheme && "Can't determine relevant scheme, ambiguous context"); + scheme = __schemes.at(context.getValueString()); + } } assert(scheme && "Context doesn't define any ad hoc scheme"); return scheme; } const TypeAnnotation& AdhocScheme::getResultType(){ return __resultType; } CodeScope* AdhocScheme::getCommandImplementation(const Expression& comm) { - assert(comm.__state == Expression::IDENT); + assert(comm.__state == Expression::COMPOUND && comm.op == Operator::CALL && comm.operands.size() == 0); const std::string commSerialized = comm.getValueString(); assert(__commands.count(commSerialized) && "Command isn't defined for a selected scheme"); return __commands.at(commSerialized); } AdhocScheme::AdhocScheme(const Expression& scheme): __resultType(scheme.type), __name(scheme.getValueString()) { Expression exprCasesList = scheme.getOperands()[0]; for (const Expression& exprSingleCase: exprCasesList.getOperands()){ std::string command = exprSingleCase.tags.begin()->second.getValueString(); CodeScope* blockImpl = *(exprSingleCase.blocks.begin()); __commands.emplace(command, blockImpl); } } const std::string& AdhocScheme::getName(){ return __name; } void AdhocPass::run(){ queryContext = reinterpret_cast(man->clasp->registerQuery(new context::ContextQuery(), QueryId::ContextQuery)); auto range = man->root->__interfacesData.equal_range(ASTInterface::Adhoc); for (auto i=range.first; i!= range.second; ++i){ AdhocScheme* scheme = new AdhocScheme(i->second); __schemes.emplace(scheme->getName(), scheme); } } }} //end of namespace xreate::adhoc diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp index c1655de..8d094fa 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,769 +1,788 @@ #include "compilepass.h" #include "clasplayer.h" #include #include "llvmlayer.h" #include "query/containers.h" #include "query/context.h" #include "compilation/containers.h" #include "compilation/latecontextcompiler2.h" #include "ExternLayer.h" #include "pass/adhocpass.h" #include "compilation/targetinterpretation.h" #include "pass/versionspass.h" #include "compilation/scopedecorators.h" #include "compilation/adhocfunctiondecorator.h" #include "compilation/operators.h" #include "analysis/typeinference.h" #include #include #include using namespace std; using namespace llvm; //TODO use Scope -//SECTIONTAG types/convert implementation -//TODO type conversion: -//a) automatically expand types int -> bigger int; int -> floating -//b) detect exact type of `num` based on max used numeral / function type -//c) warning if need to truncate (allow/dissalow based on annotations) + //SECTIONTAG late-context FunctionDecorator -namespace xreate { +namespace xreate{namespace context{ +template +class LateContextFunctionDecorator : public Parent { +public: + LateContextFunctionDecorator(ManagedFnPtr f, CompilePass* p) + : Parent(f, p), contextCompiler(this, p) { + } + +protected: + std::vector prepareArguments() { + std::vector&& arguments = Parent::prepareArguments(); + + size_t sizeLateContextDemand = contextCompiler.getFunctionDemandSize(); + if (sizeLateContextDemand) { + llvm::Type* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); + llvm::Type* tyDemand = llvm::ArrayType::get(ty32, sizeLateContextDemand); + + arguments.push_back(tyDemand); + } + + return arguments; + } + + llvm::Function::arg_iterator prepareBindings() { + llvm::Function::arg_iterator fargsI = Parent::prepareBindings(); + + size_t sizeLateContextDemand = contextCompiler.getFunctionDemandSize(); + if (sizeLateContextDemand) { + fargsI->setName("latecontext"); + contextCompiler.rawContextArgument = &*fargsI; + ++fargsI; + } + + return fargsI; + } + +public: + context::LateContextCompiler2 contextCompiler; +}; + +}} //end of namespace xreate::context + +namespace xreate { namespace compilation{ std::string -BasicFunctionDecorator::prepareName(){ - AST* ast = FunctionUnit::pass->man->root; +BasicFunctionUnit::prepareName(){ + AST* ast = IFunctionUnit::pass->man->root; - string name = ast->getFunctionVariants(FunctionUnit::function->__name).size() > 1? - FunctionUnit::function->__name + std::to_string(FunctionUnit::function.id()) : - FunctionUnit::function->__name; + string name = ast->getFunctionVariants(IFunctionUnit::function->__name).size() > 1 ? + IFunctionUnit::function->__name + std::to_string(IFunctionUnit::function.id()) : + IFunctionUnit::function->__name; return name; } std::vector -BasicFunctionDecorator::prepareArguments(){ - LLVMLayer* llvm = FunctionUnit::pass->man->llvm; - AST* ast = FunctionUnit::pass->man->root; - CodeScope* entry = FunctionUnit::function->__entry; +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* { + [llvm, ast, entry](const std::string & arg)->llvm::Type* { assert(entry->__identifiers.count(arg)); - ScopedSymbol argid{entry->__identifiers.at(arg), VERSION_NONE}; + ScopedSymbol argid{entry->__identifiers.at(arg), versions::VERSION_NONE}; return llvm->toLLVMType(ast->expandType(entry->__declarations.at(argid).type)); - }); + }); return signature; } llvm::Type* -BasicFunctionDecorator::prepareResult(){ - LLVMLayer* llvm = FunctionUnit::pass->man->llvm; - AST* ast = FunctionUnit::pass->man->root; - CodeScope* entry = FunctionUnit::function->__entry; +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 -BasicFunctionDecorator::prepareBindings(){ - CodeScope* entry = FunctionUnit::function->__entry; - AbstractCodeScopeUnit* entryCompilation = FunctionUnit::getScopeUnit(entry); - llvm::Function::arg_iterator fargsI = FunctionUnit::raw->arg_begin(); +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], VERSION_NONE}; + ScopedSymbol argid{entry->__identifiers[arg], versions::VERSION_NONE}; entryCompilation->bindArg(&*fargsI, argid); fargsI->setName(arg); ++fargsI; } return fargsI; } -//SECTIONTAG late-context FunctionDecorator -template -class LateContextFunctionDecorator: public Parent{ -public: - LateContextFunctionDecorator(ManagedFnPtr f, CompilePass* p) - : Parent(f, p), contextCompiler(this, p) - {} - -protected: - std::vector prepareArguments(){ - std::vector&& arguments = Parent::prepareArguments(); - - size_t sizeLateContextDemand = contextCompiler.getFunctionDemandSize(); - if (sizeLateContextDemand) { - llvm::Type* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); - llvm::Type* tyDemand = llvm::ArrayType::get(ty32, sizeLateContextDemand); - - arguments.push_back(tyDemand); - } - - return arguments; - } - - llvm::Function::arg_iterator prepareBindings(){ - llvm::Function::arg_iterator fargsI = Parent::prepareBindings(); - - size_t sizeLateContextDemand = contextCompiler.getFunctionDemandSize(); - if (sizeLateContextDemand){ - fargsI->setName("latecontext"); - contextCompiler.rawContextArgument = &*fargsI; - ++fargsI; - } - - return fargsI; - } - -public: - context::LateContextCompiler2 contextCompiler; - -}; - -//DEBT compiler rigidly depends on exact definition of DefaultFunctionUnit -typedef LateContextFunctionDecorator< + //DEBT compiler rigidly depends on exact definition of DefaultFunctionUnit +typedef context::LateContextFunctionDecorator< adhoc::AdhocFunctionDecorator< - BasicFunctionDecorator>> DefaultFunctionUnit; - - -AbstractCodeScopeUnit::AbstractCodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass) - : pass(compilePass), function(f), scope(codeScope) -{} + BasicFunctionUnit>> DefaultFunctionUnit; +ICodeScopeUnit::ICodeScopeUnit(CodeScope* codeScope, IFunctionUnit* f, CompilePass* compilePass) +: pass(compilePass), function(f), scope(codeScope) { +} llvm::Value* -CallStatementRaw::operator() (std::vector&& args, const std::string& hintDecl) { +CallStatementRaw::operator()(std::vector&& args, const std::string& hintDecl) { llvm::Function* calleeInfo = dyn_cast(__callee); - if (calleeInfo){ + if (calleeInfo) { auto argsFormal = calleeInfo->args(); - int pos=0; + int pos = 0; //SECTIONTAG types/convert function ret value - for (auto argFormal = argsFormal.begin(); argFormal!=argsFormal.end(); ++argFormal, ++pos){ + for (auto argFormal = argsFormal.begin(); argFormal != argsFormal.end(); ++argFormal, ++pos) { args[pos] = typeinference::doAutomaticTypeConversion(args[pos], argFormal->getType(), llvm->builder); } } return llvm->builder.CreateCall(__calleeTy, __callee, args, hintDecl); } -//DESABLEDFEATURE implement inlining -class CallStatementInline: public CallStatement{ + //DESABLEDFEATURE implement inlining +class CallStatementInline : public CallStatement { public: - CallStatementInline(FunctionUnit* caller, FunctionUnit* callee, LLVMLayer* l) - : __caller(caller), __callee(callee), llvm(l) {} - - llvm::Value* operator() (std::vector&& 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(); + CallStatementInline(IFunctionUnit* caller, IFunctionUnit* callee, LLVMLayer* l) + : __caller(caller), __callee(callee), llvm(l) { + } - return nullptr; - } + 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: - FunctionUnit* __caller; - FunctionUnit* __callee; - LLVMLayer* llvm; - - bool isInline(){ - // Symbol ret = Symbol{0, function->__entry}; - // bool flagOnTheFly = SymbolAttachments::get(ret, false); - //TODO consider inlining - return false; - } + 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(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass) - : AbstractCodeScopeUnit(codeScope, f, compilePass) -{} +BasicCodeScopeUnit::BasicCodeScopeUnit(CodeScope* codeScope, IFunctionUnit* f, CompilePass* compilePass) +: ICodeScopeUnit(codeScope, f, compilePass) { +} llvm::Value* -BasicCodeScopeUnit::processSymbol(const Symbol& s, std::string hintRetVar){ +BasicCodeScopeUnit::processSymbol(const Symbol& s, std::string hintRetVar) { Expression declaration = CodeScope::getDeclaration(s); CodeScope* scope = s.scope; - AbstractCodeScopeUnit* self = AbstractCodeScopeUnit::function->getScopeUnit(scope); + ICodeScopeUnit* self = ICodeScopeUnit::function->getScopeUnit(scope); return self->process(declaration, hintRetVar); } - //SECTIONTAG late-context find callee function //TOTEST static late context decisions //TOTEST dynamic late context decisions CallStatement* -BasicCodeScopeUnit::findFunction(const std::string& calleeName){ +BasicCodeScopeUnit::findFunction(const std::string& calleeName) { LLVMLayer* llvm = pass->man->llvm; ClaspLayer* clasp = pass->man->clasp; - DefaultFunctionUnit* function = dynamic_cast(this->function); + DefaultFunctionUnit* function = dynamic_cast (this->function); context::ContextQuery* queryContext = pass->queryContext; const std::list& specializations = pass->man->root->getFunctionVariants(calleeName); //if no specializations registered - check external function - if (specializations.size()==0){ + if (specializations.size() == 0) { llvm::Function* external = llvm->layerExtern->lookupFunction(calleeName); llvm::outs() << "Debug/External function: " << calleeName; external->getType()->print(llvm::outs(), true); llvm::outs() << "\n"; return new CallStatementRaw(external, llvm); } //no decisions required - if (specializations.size()==1){ + if (specializations.size() == 1) { if (!specializations.front()->guardContext.isValid()) { - return new CallStatementRaw( pass->getFunctionUnit(specializations.front())->compile(), llvm); + return new CallStatementRaw(pass->getFunctionUnit(specializations.front())->compile(), llvm); } } //TODO move dictSpecialization over to a separate function in order to perform cache, etc. //prepare specializations dictionary std::map dictSpecializations; boost::optional variantDefault; boost::optional variant; - for(const ManagedFnPtr& f: specializations){ + for (const ManagedFnPtr& f : specializations) { const Expression& guard = f->guardContext; //default case: - if (!guard.isValid()){ - variantDefault = f; - continue; + if (!guard.isValid()) { + variantDefault = f; + continue; } assert(dictSpecializations.emplace(guard, f).second && "Found several identical specializations"); } //check static context ScopePacked scopeCaller = clasp->pack(this->scope); const string atomSpecialization = "specialization"; - const Expression topicSpecialization(Operator::CALL, {(Atom(string(atomSpecialization))), (Atom(string(calleeName))), (Atom(scopeCaller))}); + const Expression topicSpecialization(Operator::CALL,{(Atom(string(atomSpecialization))), + Expression(Operator::CALL, + {Atom(string(calleeName))}), + Atom(scopeCaller)}); const context::Decisions& decisions = queryContext->getFinalDecisions(scopeCaller); - if (decisions.count(topicSpecialization)){ - variant = dictSpecializations.at(decisions.at(topicSpecialization)); + if (decisions.count(topicSpecialization)) { + variant = dictSpecializations.at(decisions.at(topicSpecialization)); } //TODO check only demand for this particular topic. size_t sizeDemand = function->contextCompiler.getFunctionDemandSize(); //decision made if static context found or no late context exists(and there is default variant) - bool flagHasStaticDecision = variant || (variantDefault && !sizeDemand); + bool flagHasStaticDecision = variant || (variantDefault && !sizeDemand); //if no late context exists if (flagHasStaticDecision) { - FunctionUnit* calleeUnit = pass->getFunctionUnit(variant? *variant: *variantDefault); + IFunctionUnit* calleeUnit = pass->getFunctionUnit(variant ? *variant : *variantDefault); - //inlining possible based on static decision only -// if (calleeUnit->isInline()) { -// return new CallStatementInline(function, calleeUnit); -// } + //inlining possible based on static decision only + // if (calleeUnit->isInline()) { + // return new CallStatementInline(function, calleeUnit); + // } return new CallStatementRaw(calleeUnit->compile(), llvm); } //require default variant if no static decision made assert(variantDefault); llvm::Function* functionVariantDefault = this->pass->getFunctionUnit(*variantDefault)->compile(); llvm::Value* resultFn = function->contextCompiler.findFunction(calleeName, functionVariantDefault, scopeCaller); llvm::PointerType *resultPTy = cast(resultFn->getType()); llvm::FunctionType *resultFTy = cast(resultPTy->getElementType()); return new CallStatementRaw(resultFn, resultFTy, llvm); } //DISABLEDFEATURE transformations // if (pass->transformations->isAcceptable(expr)){ // return pass->transformations->transform(expr, result, ctx); // } llvm::Value* -BasicCodeScopeUnit::process(const Expression& expr, const std::string& hintVarDecl){ +BasicCodeScopeUnit::process(const Expression& expr, const std::string& hintVarDecl) { #define DEFAULT(x) (hintVarDecl.empty()? x: hintVarDecl) - llvm::Value *left; llvm::Value *right; + llvm::Value *left; + llvm::Value *right; LLVMLayer& l = *pass->man->llvm; xreate::compilation::Advanced instructions = xreate::compilation::Advanced({this, function, pass}); switch (expr.op) { case Operator::SUB: case Operator::MUL: case Operator::DIV: case Operator::EQU: case Operator::LSS: - case Operator::GTR: case Operator::NE: case Operator::LSE: + 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); + right = typeinference::doAutomaticTypeConversion(right, left->getType(), l.builder); break; default:; } switch (expr.op) { - case Operator::ADD:{ + 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;} + 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: { + case Operator::CALL: + { assert(expr.__state == Expression::COMPOUND); std::string nameCallee = expr.getValueString(); shared_ptr callee(findFunction(nameCallee)); //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); - } + [this](const Expression & operand) { + return process(operand); + } ); ScopePacked outerScopeId = pass->man->clasp->pack(this->scope); //TASK a) refactor CALL/ADHOC/find function //SECTIONTAG late-context propagation arg size_t calleeDemandSize = pass->queryContext->getFunctionDemand(nameCallee).size(); - if (calleeDemandSize){ - DefaultFunctionUnit* function = dynamic_cast(this->function); - llvm::Value* argLateContext = function->contextCompiler.compileContextArgument(nameCallee, outerScopeId); - args.push_back(argLateContext); + if (calleeDemandSize) { + DefaultFunctionUnit* function = dynamic_cast (this->function); + llvm::Value* argLateContext = function->contextCompiler.compileContextArgument(nameCallee, outerScopeId); + args.push_back(argLateContext); } - return (*callee)(move(args), DEFAULT("res_"+nameCallee)); + return (*callee)(move(args), DEFAULT("res_" + nameCallee)); } case Operator::IF: { - return instructions.compileIf(expr, DEFAULT("tmp_if")); + return instructions.compileIf(expr, DEFAULT("tmp_if")); } case Operator::SWITCH: { - return instructions.compileSwitch(expr, DEFAULT("tmp_switch")); + return instructions.compileSwitch(expr, DEFAULT("tmp_switch")); } case Operator::LOOP_CONTEXT: { assert(false); return nullptr; //return instructions.compileLoopContext(expr, DEFAULT("tmp_loop")); } - case Operator::LOGIC_AND: { - assert(expr.operands.size() == 1); - return process (expr.operands[0]); + case Operator::LOGIC_AND: + { + assert(expr.operands.size() == 1); + return process(expr.operands[0]); } case Operator::LIST: { - return instructions.compileListAsSolidArray(expr, DEFAULT("tmp_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); + // 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; + 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(l.toLLVMType(tyStructLiteral)); llvm::Value* record = llvm::UndefValue::get(tyLiteralRaw); - for (size_t i=0; igetElementType(fieldId); -// result = llvm::UndefValue::get(tyNullField); -// -// } else { - result = process(operand); -// } + //TODO Null ad hoc llvm implementation (related code: operators/StructUpdate/add) + // if (operand.isNone()){ + // llvm::Type* tyNullField = tyRecord->getElementType(fieldId); + // result = llvm::UndefValue::get(tyNullField); + // + // } else { + result = process(operand); + // } - assert (result); + 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: { - //TODO allow multiindex - assert(expr.operands.size()==2); + //TODO allow multiindex + assert(expr.operands.size() == 2); assert(expr.operands[0].__state == Expression::IDENT); - const std::string& hintIdent= expr.operands[0].getValueString(); + 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); + llvm::Value* aggr = processSymbol(s, hintIdent); - switch (t2.get().__operator) - { + switch (t2.get().__operator) { case TypeOperator::STRUCT: case TypeOperator::CUSTOM: { std::string idxField; const Expression& idx = expr.operands.at(1); switch (idx.__state) { //named struct field - case Expression::STRING: + case Expression::STRING: idxField = idx.getValueString(); break; //anonymous struct field case Expression::NUMBER: - idxField = to_string((int)idx.getValueDouble()); + idxField = to_string((int) idx.getValueDouble()); break; default: - assert(false&& "Wrong index for a struct"); + assert(false && "Wrong index for a struct"); } return instructions.compileStructIndex(aggr, t2, idxField); }; - case TypeOperator::ARRAY: { + case TypeOperator::ARRAY: + { std::vector indexes; std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()), - [this] (const Expression& op){ - return process(op); - } + [this] (const Expression & op) { + return process(op); + } ); return instructions.compileArrayIndex(aggr, indexes, DEFAULT(string("el_") + hintIdent)); }; default: assert(false); } }; - //SECTIONTAG adhoc actual compilation - //TODO a) make sure that it's correct: function->adhocImplementation built for Entry scope and used in another scope - case Operator::ADHOC: { - DefaultFunctionUnit* function = dynamic_cast(this->function); + //SECTIONTAG adhoc actual compilation + //TODO a) make sure that it's correct: function->adhocImplementation built for Entry scope and used in another scope + case Operator::ADHOC: + { + DefaultFunctionUnit* function = dynamic_cast (this->function); assert(function->adhocImplementation && "Adhoc implementation not found"); const Expression& comm = adhoc::AdhocExpression(expr).getCommand(); CodeScope* scope = function->adhocImplementation->getCommandImplementation(comm); - AbstractCodeScopeUnit* unitScope = function->getScopeUnit(scope); + ICodeScopeUnit* unitScope = function->getScopeUnit(scope); //SECTIONTAG types/convert ADHOC ret convertation - llvm::Type* resultTy = l.toLLVMType( pass->man->root->expandType(function->adhocImplementation->getResultType())); + llvm::Type* resultTy = l.toLLVMType(pass->man->root->expandType(function->adhocImplementation->getResultType())); return typeinference::doAutomaticTypeConversion(unitScope->compile(), resultTy, l.builder); }; - case Operator::CALL_INTRINSIC:{ + 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::NONE: assert(expr.__state != Expression::COMPOUND); switch (expr.__state) { - case Expression::IDENT: { + case Expression::IDENT: + { Symbol s = Attachments::get(expr); return processSymbol(s, expr.getValueString()); } - case Expression::NUMBER: { + case Expression::NUMBER: + { llvm::Type* typConst; - if (expr.type.isValid()){ + if (expr.type.isValid()) { typConst = l.toLLVMType(pass->man->root->getType(expr)); } else { typConst = llvm::Type::getInt32Ty(llvm::getGlobalContext()); } int literal = expr.getValueDouble(); return llvm::ConstantInt::get(typConst, literal); } - case Expression::STRING: { + case Expression::STRING: + { return instructions.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str")); }; - case Expression::VARIANT: { - const ExpandedType& typVariant = pass->man->root->getType(expr); - llvm::Type* typRaw = l.toLLVMType(typVariant); - int value = expr.getValueDouble(); + case Expression::VARIANT: + { + const ExpandedType& typVariant = pass->man->root->getType(expr); + llvm::Type* typRaw = l.toLLVMType(typVariant); + int value = expr.getValueDouble(); return llvm::ConstantInt::get(typRaw, value); } - default: { + default: + { break; } }; break; default: break; } - assert(false); + assert(false && "Can't compile expression"); return 0; } llvm::Value* -BasicCodeScopeUnit::compile(const std::string& hintBlockDecl){ +BasicCodeScopeUnit::compile(const std::string& hintBlockDecl) { if (!hintBlockDecl.empty()) { llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm::getGlobalContext(), hintBlockDecl, function->raw); pass->man->llvm->builder.SetInsertPoint(block); } Symbol symbScope = Symbol{ScopedSymbol::RetSymbol, scope}; return processSymbol(symbScope); } -AbstractCodeScopeUnit::~AbstractCodeScopeUnit() -{} +ICodeScopeUnit::~ICodeScopeUnit() { +} -FunctionUnit::~FunctionUnit() -{} +IFunctionUnit::~IFunctionUnit() { +} llvm::Function* -FunctionUnit::compile(){ +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"; + const std::string&blockName = "entry"; llvm::BasicBlock* blockCurrent = builder.GetInsertBlock(); - llvm::Value* result =getScopeUnit(function->__entry)->compile(blockName); + 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); + if (blockCurrent) { + builder.SetInsertPoint(blockCurrent); } llvm->moveToGarbage(ft); return raw; } -AbstractCodeScopeUnit* -FunctionUnit::getScopeUnit(CodeScope* scope){ +ICodeScopeUnit* +IFunctionUnit::getScopeUnit(CodeScope* scope) { if (__scopes.count(scope)) { auto result = __scopes.at(scope).lock(); - if (result){ + if (result) { return result.get(); } } - std::shared_ptr unit(new DefaultScopeUnit(scope, this, pass)); + std::shared_ptr unit(pass->buildCodeScopeUnit(scope, this)); - if (scope->__parent != nullptr){ + 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){ + if (!__scopes.emplace(scope, unit).second) { __scopes[scope] = unit; } return unit.get(); } -AbstractCodeScopeUnit* -FunctionUnit::getScopeUnit(ManagedScpPtr scope){ +ICodeScopeUnit* +IFunctionUnit::getScopeUnit(ManagedScpPtr scope) { return getScopeUnit(&*scope); } -AbstractCodeScopeUnit* -FunctionUnit::getEntry(){ - return getScopeUnit(function->getEntryScope()); +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(CodeScope* scope, IFunctionUnit* function){ + return new DefaultCodeScopeUnit(scope, function, this); +} +} // emf of compilation -FunctionUnit* -CompilePass::getFunctionUnit(const ManagedFnPtr& function){ - unsigned int id = function.id(); +IFunctionUnit* +CompilePass::getFunctionUnit(const ManagedFnPtr& function) { + unsigned int id = function.id(); - if (!functions.count(id)){ - FunctionUnit* unit = new DefaultFunctionUnit(function, this); + if (!functions.count(id)) { + IFunctionUnit* unit = buildFunctionUnit(function); functions.emplace(id, unit); return unit; } return functions.at(id); } void -CompilePass::run(){ +CompilePass::run() { managerTransformations = new TransformationsManager(); targetInterpretation = new interpretation::TargetInterpretation(this->man->root, this); queryContext = reinterpret_cast (man->clasp->getQuery(QueryId::ContextQuery)); //Find out main function; ClaspLayer::ModelFragment model = man->clasp->query(Config::get("function-entry")); assert(model && "Error: No entry function found"); assert(model->first != model->second && "Error: Ambiguous entry function"); string nameMain = std::get<0>(ClaspLayer::parse(model->first->second)); - FunctionUnit* unitMain = getFunctionUnit(man->root->findFunction(nameMain)); + IFunctionUnit* unitMain = getFunctionUnit(man->root->findFunction(nameMain)); entry = unitMain->compile(); } llvm::Function* -CompilePass::getEntryFunction(){ - assert(entry); - return entry; +CompilePass::getEntryFunction() { + assert(entry); + return entry; } void -CompilePass::prepareQueries(ClaspLayer* clasp){ - clasp->registerQuery(new containers::Query(), QueryId::ContainersQuery); - clasp->registerQuery(new context::ContextQuery(), QueryId::ContextQuery); +CompilePass::prepareQueries(ClaspLayer* clasp) { + clasp->registerQuery(new containers::Query(), QueryId::ContainersQuery); + clasp->registerQuery(new context::ContextQuery(), QueryId::ContextQuery); } - } //end of namespace xreate diff --git a/cpp/src/pass/compilepass.h b/cpp/src/pass/compilepass.h index 38209d0..0649df6 100644 --- a/cpp/src/pass/compilepass.h +++ b/cpp/src/pass/compilepass.h @@ -1,166 +1,183 @@ #ifndef COMPILEPASS_H #define COMPILEPASS_H #include "abstractpass.h" #include "llvm/IR/Function.h" namespace xreate { class ClaspLayer; class CompilePass; class LLVMLayer; namespace adhoc{ class AdhocScheme; } namespace context{ class ContextQuery; class LateContextCompiler2; } namespace interpretation{ class TargetInterpretation; } } namespace xreate { namespace compilation { -class AbstractCodeScopeUnit; -class FunctionUnit; +class ICodeScopeUnit; +class IFunctionUnit; class TransformationsManager; struct Context{ - AbstractCodeScopeUnit* scope; - FunctionUnit* function; + ICodeScopeUnit* scope; + IFunctionUnit* function; CompilePass* pass; }; class CallStatement { public: virtual llvm::Value* operator() (std::vector&& args, const std::string& hintDecl="") = 0; }; class CallStatementRaw: public CallStatement{ public: CallStatementRaw(llvm::Function* callee, LLVMLayer* l) : __callee(callee), __calleeTy(callee->getFunctionType()), llvm(l) {} CallStatementRaw(llvm::Value* callee, llvm::FunctionType* ty, LLVMLayer* l) : __callee(callee), __calleeTy(ty), llvm(l) {} llvm::Value* operator() (std::vector&& args, const std::string& hintDecl=""); private: llvm::Value* __callee; llvm::FunctionType* __calleeTy; LLVMLayer* llvm; }; -class AbstractCodeScopeUnit{ +class ICodeScopeUnit{ public: CompilePass* const pass; - FunctionUnit* const function; + IFunctionUnit* const function; CodeScope* const scope; - AbstractCodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass); - virtual ~AbstractCodeScopeUnit(); + ICodeScopeUnit(CodeScope* codeScope, IFunctionUnit* f, CompilePass* compilePass); + virtual ~ICodeScopeUnit(); virtual llvm::Value* compile(const std::string& hintBlockDecl="")=0; virtual llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar="")=0; virtual llvm::Value* process(const Expression& expr, const std::string& hintVarDecl="")=0; virtual void bindArg(llvm::Value* value, std::string&& alias)=0; virtual void bindArg(llvm::Value* value, const ScopedSymbol& s)=0; protected: virtual CallStatement* findFunction(const std::string& callee)=0; }; -class BasicCodeScopeUnit: public AbstractCodeScopeUnit{ +class BasicCodeScopeUnit: public ICodeScopeUnit{ public: - BasicCodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass); + BasicCodeScopeUnit(CodeScope* codeScope, IFunctionUnit* f, CompilePass* compilePass); - llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar=""); - llvm::Value* process(const Expression& expr, const std::string& hintVarDecl=""); - llvm::Value* compile(const std::string& hintBlockDecl=""); + llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar="") override; + llvm::Value* process(const Expression& expr, const std::string& hintVarDecl="") override; + llvm::Value* compile(const std::string& hintBlockDecl="") override; protected: - CallStatement* findFunction(const std::string& callee); + CallStatement* findFunction(const std::string& callee) override; }; - - -class IFunctionDecorator { -protected: - virtual std::string prepareName() = 0; - virtual std::vector prepareArguments() = 0; - virtual llvm::Type* prepareResult() = 0; - virtual llvm::Function::arg_iterator prepareBindings() = 0; - virtual ~IFunctionDecorator(){} -}; - -class FunctionUnit: public IFunctionDecorator{ +class IFunctionUnit{ public: - FunctionUnit(ManagedFnPtr f, CompilePass* p) - : function(f), pass(p) {} - ~FunctionUnit(); + IFunctionUnit(ManagedFnPtr f, CompilePass* p): function(f), pass(p) {} + virtual ~IFunctionUnit(); llvm::Function* compile(); - AbstractCodeScopeUnit* getEntry(); - AbstractCodeScopeUnit* getScopeUnit(CodeScope* scope); - AbstractCodeScopeUnit* getScopeUnit(ManagedScpPtr scope); + ICodeScopeUnit* getEntry(); + ICodeScopeUnit* getScopeUnit(CodeScope* scope); + ICodeScopeUnit* getScopeUnit(ManagedScpPtr scope); ManagedFnPtr function; llvm::Function* raw = nullptr; protected: CompilePass* pass=nullptr; + virtual std::string prepareName() = 0; + virtual std::vector prepareArguments() = 0; + virtual llvm::Type* prepareResult() = 0; + virtual llvm::Function::arg_iterator prepareBindings() = 0; + private: - std::map> __scopes; - std::list> __orphanedScopes; + std::map> __scopes; + std::list> __orphanedScopes; }; -class BasicFunctionDecorator: public FunctionUnit{ +class BasicFunctionUnit: public IFunctionUnit{ public: - BasicFunctionDecorator(ManagedFnPtr f, CompilePass* p) - : FunctionUnit(f, p) {} + BasicFunctionUnit(ManagedFnPtr f, CompilePass* p) + : IFunctionUnit(f, p) {} protected: - std::string prepareName(); - virtual std::vector prepareArguments(); - virtual llvm::Type* prepareResult(); - virtual llvm::Function::arg_iterator prepareBindings(); + std::string prepareName() override; + virtual std::vector prepareArguments() override; + virtual llvm::Type* prepareResult() override; + virtual llvm::Function::arg_iterator prepareBindings() override; }; - -} // end of namespace `xreate::compilation` +} // end of namespace compilation class CompilePass : public AbstractPass { friend class context::LateContextCompiler2; friend class compilation::BasicCodeScopeUnit; - friend class compilation::FunctionUnit; + friend class compilation::IFunctionUnit; public: compilation::TransformationsManager* managerTransformations; interpretation::TargetInterpretation* targetInterpretation; CompilePass(PassManager* manager): AbstractPass(manager) {} - compilation::FunctionUnit* getFunctionUnit(const ManagedFnPtr& function); + compilation::IFunctionUnit* getFunctionUnit(const ManagedFnPtr& function); void run() override; llvm::Function* getEntryFunction(); static void prepareQueries(ClaspLayer* clasp); +public: + virtual compilation::IFunctionUnit* buildFunctionUnit(const ManagedFnPtr& function)=0; + virtual compilation::ICodeScopeUnit* buildCodeScopeUnit(CodeScope* scope, compilation::IFunctionUnit* function)=0; private: //TODO free `functions` in destructor - std::map functions; + std::map functions; llvm::Function* entry = 0; - context::ContextQuery* queryContext; + context::ContextQuery* queryContext; +}; + +namespace compilation{ +template +class CompilePassCustomDecorators: public ::xreate::CompilePass{ +public: + CompilePassCustomDecorators(PassManager* manager): ::xreate::CompilePass(manager) {} + + virtual compilation::IFunctionUnit* buildFunctionUnit(const ManagedFnPtr& function) override{ + return new FUNCTION_DECORATOR(function, this); + } + virtual compilation::ICodeScopeUnit* buildCodeScopeUnit(CodeScope* scope, IFunctionUnit* function) override{ + return new SCOPE_DECORATOR(scope, function, this); + } }; -} +template<> +compilation::IFunctionUnit* +CompilePassCustomDecorators::buildFunctionUnit(const ManagedFnPtr& function); + +template<> +compilation::ICodeScopeUnit* +CompilePassCustomDecorators::buildCodeScopeUnit(CodeScope* scope, IFunctionUnit* function); + +}} //end of namespace xreate::compilation #endif // COMPILEPASS_H diff --git a/cpp/src/pass/dfapass.cpp b/cpp/src/pass/dfapass.cpp index e64eeff..47f2ec0 100644 --- a/cpp/src/pass/dfapass.cpp +++ b/cpp/src/pass/dfapass.cpp @@ -1,262 +1,262 @@ #include "pass/dfapass.h" #include "analysis/dfagraph.h" #include "xreatemanager.h" #include "clasplayer.h" #include using namespace std; namespace xreate { namespace dfa { class DfaExpressionProcessor { std::vector operands; std::vector blocks; const Expression expression; SymbolNode result; DFAPass * const pass; const PassContext context; public: DfaExpressionProcessor(const Expression& expr, SymbolNode resInitial, DFAPass * const p, const PassContext c) : expression(expr), result(resInitial), pass(p), context(c) { operands.reserve(expression.getOperands().size()); for (const Expression &op : expression.getOperands()) { SymbolAnonymous symbOp(op.id); operands.push_back(DfaExpressionProcessor(op, symbOp, pass, context).process()); } blocks.reserve(expression.blocks.size()); for (CodeScope* scope : expression.blocks) { blocks.push_back(pass->process(scope, context)); } } SymbolNode process() { if (expression.__state == Expression::COMPOUND) { processCompoundOp(); } else { processElementaryOp(); } applySignatureAnnotations(); applyInPlaceAnnotations(); return result; } private: void processElementaryOp() { switch (expression.__state) { case Expression::IDENT: { SymbolPacked symbFrom = pass->processSymbol(Attachments::get(expression), context, expression.getValueString()); SymbolPacked* symbTo = boost::get(&result); if (symbTo) { pass->__context.graph->addConnection(*symbTo, SymbolNode(symbFrom), DFGConnection::STRONG); } else { result = SymbolNode(symbFrom); } break; } default: break; } } void processCompoundOp() { switch (expression.op) { //DEBT provide CALL processing // case Operator::CALL: { // const string &nameCalleeFunction = expression.getValueString(); // // //TODO implement processFnCall/Uncertain // list variantsCalleeFunction = man->root->getFunctionVariants(nameCalleeFunction); // if (variantsCalleeFunction.size()!=1) return; // ManagedFnPtr function= variantsCalleeFunction.front(); // // // set calling relations: // CodeScope *scopeRemote = function->getEntryScope(); // std::vector::iterator nodeActual = cache.operands.begin(); // for (const std::string &identFormal: scopeRemote->__bindings){ - // const ScopedSymbol symbolFormal{scopeRemote->__identifiers.at(identFormal), VERSION_NONE}; + // const ScopedSymbol symbolFormal{scopeRemote->__identifiers.at(identFormal), versions::VERSION_NONE}; // // __context.graph->addConnection(clasp->pack(Symbol{symbolFormal, scopeRemote}, nameCalleeFunction + ":" + identFormal), *nodeActual, DFGConnection::WEAK); // ++nodeActual; // } // // //TODO add RET connection // break; // } //MAP processing: apply PROTOTYPE relation case Operator::MAP: { SymbolNode nodeFrom = operands.front(); SymbolPacked* nodeTo = boost::get(&result); assert(nodeTo); pass->__context.graph->addConnection(*nodeTo, nodeFrom, DFGConnection::PROTOTYPE); break; } default: break; } } void applySignatureAnnotations() { if (pass->__signatures.count(expression.op)) { const Expression &scheme = pass->__signatures.at(expression.op); std::vector::iterator arg = operands.begin(); std::vector::const_iterator tag = scheme.getOperands().begin(); //Assign scheme RET annotation Expression retTag = *scheme.getOperands().begin(); if (retTag.__state != Expression::INVALID) { pass->__context.graph->addAnnotation(result, move(retTag)); } ++tag; while (tag != scheme.getOperands().end()) { if (tag->__state != Expression::INVALID) { pass->__context.graph->addAnnotation(*arg, Expression(*tag)); } ++arg; ++tag; } // TODO add possibility to have specific signature for a particular function // if (expression.op == Operator::CALL || expression.op == Operator::INDEX){ // string caption = expression.getValueString(); // operands.push_back(process(Expression(move(caption)), context, "")); // } } } void applyInPlaceAnnotations() { // write down in-place expression tags: for (pair tag : expression.tags) { pass->__context.graph->addAnnotation(result, Expression(tag.second)); } } }; DFAPass::DFAPass(PassManager* manager) : AbstractPass(manager) , __context{new DFAGraph(manager->clasp)} , clasp(manager->clasp) {} SymbolPacked DFAPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl) { const SymbolPacked& symbRet = AbstractPass::process(scope, context, hintBlockDecl); return symbRet; } SymbolPacked DFAPass::processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol) { const Expression& declaration = CodeScope::getDeclaration(symbol); const SymbolPacked& symbPacked = clasp->pack(symbol, hintSymbol); DfaExpressionProcessor(declaration, symbPacked, this, context).process(); return symbPacked; } void DFAPass::run() { init(); return AbstractPass::run(); } void DFAPass::init() { for (const Expression& scheme : man->root->__dfadata) { __signatures.emplace(scheme.op, scheme); } } void DFAPass::finish() { clasp->setDFAData(move(__context.graph)); } } //end of namespace dfa template<> SymbolPacked defaultValue(){ assert(false); } } //xreate namespace //DEBT represent VersionaPass in declarative form using applyDependencies // applyDependencies(expression, context, cache, decl); //DEBT prepare static annotations and represent InterpretationPass in declarative form // applyStaticAnnotations(expression, context, cache, decl); //TODO Null ad hoc DFG implementation/None symbol //DISABLEDFEATURE None value // if (expression.isNone()){ // return SymbolTransient{{Atom(Config::get("clasp.nonevalue"))}}; // } // non initialized(SymbolInvalid) value //void //DFAPass::applyDependencies(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl){ // for (SymbolNode &op: cache.operands) { // __context.graph->addDependencyConnection(cache.result, op); // } // // for (SymbolNode &block: cache.blocks) { // __context.graph->addDependencyConnection(cache.result, block); // } // // switch(expression.__state) { // case Expression::IDENT: { // SymbolNode identSymbol = clasp->pack(Attachments::get(expression), context.function->getName() + ":" + expression.getValueString()); // __context.graph->addDependencyConnection(cache.result, identSymbol); // } // // default: break; // } //} //void //DFAPass::applyStaticAnnotations(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl){ // // switch(expression.__state) { // case Expression::NUMBER: // case Expression::STRING: // __context.graph->addAnnotation(cache.result, Expression(Atom("static"))); // break; // // default: break; // } //} diff --git a/cpp/src/pass/interpretationpass.cpp b/cpp/src/pass/interpretationpass.cpp index 2387463..69bb3b1 100644 --- a/cpp/src/pass/interpretationpass.cpp +++ b/cpp/src/pass/interpretationpass.cpp @@ -1,414 +1,414 @@ /* * File: interpretationpass.cpp * Author: pgess * * Created on July 5, 2016, 5:21 PM */ #include "pass/interpretationpass.h" //#include "compilation/transformations.h" #include #include "ast.h" //DEBT implement InterpretationPass purely in clasp //DEBT represent InterpretationPass as general type inference using namespace std; namespace xreate{ template<> interpretation::InterpretationResolution defaultValue(){ return interpretation::CMPL_ONLY; } namespace interpretation{ enum InterpretationQuery{QUERY_INTR_ONLY, QUERY_CMPL_ONLY}; namespace details { template bool checkConstraints(InterpretationResolution flag) { return ( (flag==INTR_ONLY && FLAG_REQUIRED == QUERY_INTR_ONLY) || (flag==CMPL_ONLY && FLAG_REQUIRED == QUERY_CMPL_ONLY)); } InterpretationResolution recognizeTags(const map& tags){ auto i = tags.find("interpretation"); if (i== tags.end()){ return ANY; } assert(i->second.op == Operator::CALL); const string& cmd = i->second.operands.at(0).getValueString(); //TODO make consistent names of annotation and resolution if (cmd == "force"){ return INTR_ONLY; } else if (cmd == "suppress"){ return CMPL_ONLY; } return ANY; } } InterpretationResolution unify(InterpretationResolution flag) { return flag; } template InterpretationResolution unify(FLAG_A flagA, FLAG_B flagB, FLAGS... flags) { if (flagA== ANY){ return unify(flagB, flags...); } if (flagB == ANY) { return unify(flagA, flags...); } assert(flagA == flagB); return flagA; } template bool checkConstraints(std::vector&& flags) { assert(flags.size()); InterpretationResolution flag = flags.front(); return details::checkConstraints(flag); } template bool checkConstraints(std::vector&& flags) { assert(flags.size()); InterpretationResolution flag = flags.front(); flags.pop_back(); if (details::checkConstraints(flag)){ return checkConstraints(move(flags)); } return false; } bool InterpretationData::isDefault() const{ return (resolution == ANY && op == NONE); } void recognizeTags(const Expression& e){ InterpretationData tag{details::recognizeTags(e.tags), NONE}; if (!tag.isDefault()) Attachments::put(e, tag); } InterpretationResolution recognizeTags(const ManagedFnPtr& f){ return details::recognizeTags(f->getTags()); } InterpretationPass::InterpretationPass(PassManager* manager) : AbstractPass(manager) { Attachments::init(); Attachments::init(); } void InterpretationPass::run(){ ManagedFnPtr f = man->root->begin(); auto& visitedSymbols = getSymbolCache(); while (f.isValid()) { const Symbol& symbolFunction{ScopedSymbol::RetSymbol, f->getEntryScope()}; if (!visitedSymbols.isCached(symbolFunction)){ visitedSymbols.setCachedValue(symbolFunction, process(f)); } ++f; } } InterpretationResolution InterpretationPass::process(const Expression& expression, PassContext context, const std::string& decl){ recognizeTags(expression); InterpretationResolution resolution = ANY; InterpretationOperator op = NONE; switch (expression.__state){ case Expression::VARIANT: case Expression::NUMBER: case Expression::STRING: { break; } case Expression::IDENT: { resolution = Parent::processSymbol(Attachments::get(expression), context); break; } case Expression::COMPOUND: break; default: { resolution = CMPL_ONLY; break;} } if (expression.__state == Expression::COMPOUND) switch(expression.op){ case Operator::EQU: case Operator::NE: { InterpretationResolution left = process(expression.operands[0], context); InterpretationResolution right = process(expression.operands[1], context); resolution = unify(left, right); break; } case Operator::LOGIC_AND: { assert(expression.operands.size() == 1); resolution = process (expression.operands[0], context); break; } case Operator::CALL: { //TODO cope with static/dynamic context //TODO BUG here: if several variants they all are processed as CMPL careless of signature list callees = man->root->getFunctionVariants(expression.getValueString()); if (callees.size()!=1){ resolution = CMPL_ONLY; break; } ManagedFnPtr callee = callees.front(); const Symbol& symbCalleeFunc{ScopedSymbol::RetSymbol, callee->getEntryScope()}; //recursion-aware processing: // - skip self recursion const Symbol& symbSelfFunc{ScopedSymbol::RetSymbol, context.function->getEntryScope()}; if (!(symbSelfFunc == symbCalleeFunc)){ InterpretationResolution resCallee = processFnCall(callee, context); assert(resCallee != FUNC_POSTPONED && "Indirect recursion detected: can't decide on interpretation resolution"); resolution = unify(resolution, resCallee); } //check arguments compatibility const FunctionInterpretationData& calleeSignature = FunctionInterpretationHelper::getSignature(callee); for (size_t op=0, size = expression.operands.size(); op < size; ++op){ const Expression &operand = expression.operands[op]; InterpretationResolution argActual = process(operand, context); InterpretationResolution argExpected = calleeSignature.signature[op]; //TODO use args unification result to properly process function call unify(argActual, argExpected); } if (FunctionInterpretationHelper::needPartialInterpretation(callee)){ op= CALL_INTERPRET_PARTIAL; } break; } case Operator::IF:{ InterpretationResolution flagCondition = process(expression.getOperands()[0], context); InterpretationResolution flagScope1 = Parent::process(expression.blocks.front(), context); InterpretationResolution flagScope2 = Parent::process(expression.blocks.back(), context); //special case: IF_INTERPRET_CONDITION if (checkConstraints({flagCondition})){ op= IF_INTERPRET_CONDITION; flagCondition = ANY; } resolution = unify(flagCondition, flagScope1, flagScope2); break; } case Operator::FOLD: { InterpretationResolution flagInput = process(expression.getOperands()[0], context); InterpretationResolution flagAccumInit = process(expression.getOperands()[1], context); CodeScope* scopeBody = expression.blocks.front(); const std::string& nameEl = expression.bindings[0]; - Symbol symbEl{ScopedSymbol{scopeBody->__identifiers.at(nameEl), VERSION_NONE}, scopeBody}; + Symbol symbEl{ScopedSymbol{scopeBody->__identifiers.at(nameEl), versions::VERSION_NONE}, scopeBody}; getSymbolCache().setCachedValue(symbEl, InterpretationResolution(flagInput)); const std::string& nameAccum = expression.bindings[1]; - Symbol symbAccum{ScopedSymbol{scopeBody->__identifiers.at(nameAccum), VERSION_NONE}, scopeBody}; + Symbol symbAccum{ScopedSymbol{scopeBody->__identifiers.at(nameAccum), versions::VERSION_NONE}, scopeBody}; getSymbolCache().setCachedValue(symbAccum, InterpretationResolution(flagAccumInit)); InterpretationResolution flagBody = Parent::process(expression.blocks.front(), context); //special case: FOLD_INTERPRET_INPUT if (checkConstraints({flagInput})){ op= FOLD_INTERPRET_INPUT; flagInput = ANY; } resolution = unify(flagInput, flagAccumInit, flagBody); break; } case Operator::INDEX: { resolution = unify( process(expression.operands[0], context), process(expression.operands[1], context) ); break; } case Operator::SWITCH: { InterpretationResolution flagCondition = process(expression.operands[0], context); bool hasDefaultCase = expression.operands[1].op == Operator::CASE_DEFAULT; //determine conditions resolution InterpretationResolution flagHeaders = flagCondition; for (size_t size = expression.operands.size(), i= hasDefaultCase? 2: 1; i({flagHeaders})){ op= SWITCH_INTERPRET_CONDITION; flagHeaders = ANY; } //determine body resolutions resolution = flagHeaders; for (size_t size = expression.operands.size(), i= 1; i(expression, {ANY, NONE}).resolution; resolution = unify(resolution, resolutionExpected); if (resolution != resolutionExpected && (op!=NONE || resolution == INTR_ONLY)){ Attachments::put(expression, {resolution, op}); } return resolution; } InterpretationResolution InterpretationPass::processFnCall(ManagedFnPtr function, PassContext context){ return process(function); } InterpretationResolution InterpretationPass::process(ManagedFnPtr function){ CodeScope* entry = function->getEntryScope(); std::vector arguments = entry->__bindings; const Symbol& symbSelfFunc{ScopedSymbol::RetSymbol, function->getEntryScope()}; auto& cache = getSymbolCache(); if (cache.isCached(symbSelfFunc)) return cache.getCachedValue(symbSelfFunc); const FunctionInterpretationData& fnSignature = FunctionInterpretationHelper::getSignature(function); InterpretationResolution fnResolutionExpected = details::recognizeTags(function->getTags()); //mark preliminary function resolution as expected if (fnResolutionExpected != ANY){ cache.setCachedValue(symbSelfFunc, move(fnResolutionExpected)); } else { // - in order to recognize indirect recursion mark this function resolution as POSTPONED cache.setCachedValue(symbSelfFunc, FUNC_POSTPONED); } //set resolution for function arguments as expected for (int argNo = 0, size = arguments.size(); argNo< size; ++argNo){ - Symbol symbArg{ScopedSymbol{entry->__identifiers.at(arguments[argNo]), VERSION_NONE}, entry}; + Symbol symbArg{ScopedSymbol{entry->__identifiers.at(arguments[argNo]), versions::VERSION_NONE}, entry}; cache.setCachedValue(symbArg, InterpretationResolution(fnSignature.signature[argNo])); } PassContext context; context.function = function; context.scope = entry; InterpretationResolution resActual = process(CodeScope::getDeclaration(symbSelfFunc), context); resActual = unify(resActual, fnResolutionExpected); return cache.setCachedValue(symbSelfFunc, move(resActual)); } const FunctionInterpretationData FunctionInterpretationHelper::getSignature(ManagedFnPtr function){ if (Attachments::exists(function)){ return Attachments::get(function); } FunctionInterpretationData&& data = recognizeSignature(function); Attachments::put(function, data); return data; } FunctionInterpretationData FunctionInterpretationHelper::recognizeSignature(ManagedFnPtr function){ CodeScope* entry = function->__entry; FunctionInterpretationData result; result.signature.reserve(entry->__bindings.size()); bool flagPartialInterpretation = false; for(size_t no=0, size=entry->__bindings.size(); no < size; ++no){ const std::string& argName = entry->__bindings[no]; - Symbol symbArg{ScopedSymbol{entry->__identifiers.at(argName), VERSION_NONE}, entry}; + Symbol symbArg{ScopedSymbol{entry->__identifiers.at(argName), versions::VERSION_NONE}, entry}; const Expression& arg = CodeScope::getDeclaration(symbArg); InterpretationResolution argResolution = details::recognizeTags(arg.tags); flagPartialInterpretation |= (argResolution == INTR_ONLY); result.signature.push_back(argResolution); } result.flagPartialInterpretation = flagPartialInterpretation; return result; } bool FunctionInterpretationHelper::needPartialInterpretation(ManagedFnPtr function){ const FunctionInterpretationData& data = getSignature(function); return data.flagPartialInterpretation; } }} //end of namespace xreate::interpretation diff --git a/cpp/src/serialization.h b/cpp/src/serialization.h index af74e11..7131ab3 100644 --- a/cpp/src/serialization.h +++ b/cpp/src/serialization.h @@ -1,30 +1,30 @@ /* * serialization.h * * Created on: 13 февр. 2016 * Author: pgess */ #ifndef SRC_SERIALIZATION_SERIALIZATION_H_ #define SRC_SERIALIZATION_SERIALIZATION_H_ -#include "misc/serialization/expressionserializer.h" +#include "aux/serialization/expressionserializer.h" namespace xreate { struct RequirementIntegralCode{}; template struct ExpressionSerialization { typedef PackedExpression Code; typedef ExpressionSerializer Serializer; }; template<> struct ExpressionSerialization{ typedef size_t Code; typedef ExpressionSerializerIntegral Serializer; }; } #endif /* SRC_SERIALIZATION_SERIALIZATION_H_ */ diff --git a/cpp/src/xreatemanager.cpp b/cpp/src/xreatemanager.cpp index b7029c4..63af268 100644 --- a/cpp/src/xreatemanager.cpp +++ b/cpp/src/xreatemanager.cpp @@ -1,123 +1,123 @@ /* * xreatemanager.cpp * * Author: pgess * Created on July 3, 2017, 6:03 PM */ #include "xreatemanager.h" #include "clasplayer.h" -#include "misc/xreatemanager-decorators.h" +#include "aux/xreatemanager-decorators.h" #include "llvmlayer.h" #include "main/Parser.h" #include #include namespace xreate { void PassManager::registerPass(AbstractPassBase* pass, const PassId& id, AbstractPassBase* parent) { __passes.emplace(id, pass); __passDependencies.emplace(parent, pass); } AbstractPassBase* 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()){ AbstractPassBase* parent = passes.front(); auto range = __passDependencies.equal_range(parent); for (auto i=range.first; i!=range.second; ++i){ AbstractPassBase* pass = i->second; pass->run(); pass->finish(); passes.push_back(pass); } passes.pop_front(); } } void PassManager::prepare(AST* ast){ root = ast; clasp = new ClaspLayer(); clasp->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; } }} 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; } } diff --git a/cpp/tests/ExpressionSerializer.cpp b/cpp/tests/ExpressionSerializer.cpp index dae45e5..a5764da 100644 --- a/cpp/tests/ExpressionSerializer.cpp +++ b/cpp/tests/ExpressionSerializer.cpp @@ -1,65 +1,65 @@ /* * testExpressionSerializer.cpp * * Created on: Jan 4, 2016 * Author: pgess */ -#include "misc/serialization/expressionserializer.h" +#include "aux/serialization/expressionserializer.h" #include "serialization.h" #include "ast.h" #include "gtest/gtest.h" using namespace xreate; using namespace std; TEST(ExpressionSerializer, pack1){ PackedExpression x; x << std::make_pair(0xA1, 0x100); size_t* storage = reinterpret_cast (*x); ASSERT_EQ(0xA100000000000000, *storage); x << std::make_pair(0x23456, 0x100000); ASSERT_EQ(0xA123456000000000, *storage); x << std::make_pair(0x7654321, 0x10000000); ASSERT_EQ(0xA123456765432100, *storage); x << std::make_pair(0xABBA, 0x10000); storage = reinterpret_cast (*x); ASSERT_EQ(0xA1234567654321AB, *storage); ASSERT_EQ(0xBA00000000000000, *(storage+1)); } TEST(ExpressionSerializer, serialize1){ Expression a(Operator::CALL, {Expression(string("a")), Expression(string("a"))}); Expression b(Operator::CALL, {Expression(string("a")), Expression(string("b"))}); ExpressionSerializer serializer(vector{a, b}); PackedExpression packA = serializer.getId(a); PackedExpression packB = serializer.getId(b); PackedExpression packA2 = serializer.getId(a); ASSERT_EQ(packA, packA2); ASSERT_NE(packA, packB); } TEST(ExpressionSerializer, serialize2){ Expression a(Operator::CALL, {Expression(string("a")), Expression(string("a"))}); Expression b(Operator::CALL, {Expression(string("a")), Expression(string("b"))}); Expression c(Atom("c")); typedef ExpressionSerialization::Serializer Serializer; Serializer serializer(vector{a, b}); ASSERT_EQ(2, serializer.size()); ASSERT_EQ(1, serializer.count(a)); ASSERT_EQ(1, serializer.count(b)); ASSERT_EQ(0, serializer.count(c)); Serializer serializer2(move(serializer)); ASSERT_EQ(1, serializer2.count(a)); } diff --git a/cpp/tests/interpretation.cpp b/cpp/tests/interpretation.cpp index 1e313d1..1eb60fc 100644 --- a/cpp/tests/interpretation.cpp +++ b/cpp/tests/interpretation.cpp @@ -1,384 +1,384 @@ #include "attachments.h" using namespace xreate; #include "xreatemanager.h" #include "compilation/targetinterpretation.h" #include "gtest/gtest.h" #include "boost/scoped_ptr.hpp" //#define FRIENDS_INTERPRETATION_TESTS \ // friend class ::Modules_AST2_Test; \ // friend class ::Modules_Discovery1_Test; \ // friend class ::Modules_Solve1_Test; #include "pass/interpretationpass.h" using namespace xreate::grammar::main; using namespace xreate::interpretation; TEST(Interpretation, Analysis_StatementIF_1){ XreateManager* man = XreateManager::prepare( R"Code( main = function::bool { x = "a":: string. y = if (x=="b"):: bool; interpretation(force) { true } else { false }. y } )Code" ); InterpretationPass* pass = new InterpretationPass(man); pass->run(); CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope(); Symbol symbolY{scopeEntry->getSymbol("y"), scopeEntry}; InterpretationData& dataSymbolY = Attachments::get(symbolY); ASSERT_EQ(INTR_ONLY, dataSymbolY.resolution); } TEST(Interpretation, Compilation_StatementIF_1){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( main = function::int; entry { x = "a":: string. y = if (x=="b"):: string; interpretation(force) { 1 } else { 0 }. y } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(0, result); } TEST(Interpretation, Analysis_StatementIF_InterpretCondition_1){ XreateManager* man = XreateManager::prepare( R"Code( main = function(x:: int):: int { comm= "inc":: string; interpretation(force). y = if (comm == "inc")::int {x+1} else {x}. y } )Code" ); InterpretationPass* pass = new InterpretationPass(man); pass->run(); CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope(); Symbol symbolY{scopeEntry->getSymbol("y"), scopeEntry}; InterpretationData& dataSymbolY = Attachments::get(symbolY); ASSERT_EQ(CMPL_ONLY, dataSymbolY.resolution); ASSERT_EQ(IF_INTERPRET_CONDITION, dataSymbolY.op); } TEST(Interpretation, Compilation_StatementIF_InterpretCondition_1){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( main = function(x:: int):: int; entry { comm= "inc":: string; interpretation(force). y = if (comm == "inc")::int {x+1} else {x}. y } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } int (*main)(int) = (int (*)(int))man->run(); int result = main(1); ASSERT_EQ(2, result); } TEST(Interpretation, Compilation_StatementFOLD_INTERPRET_INPUT_1){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( main = function(x:: int):: int; entry { commands = ["inc", "double", "dec"]:: [string]; interpretation(force). loop fold(commands->comm::string, x->operand):: int{ switch(comm)::int case ("inc"){ operand + 1 } case ("dec"){ operand - 1 } case ("double"){ operand * 2 } } } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } const ManagedFnPtr& funcMain = man->root->findFunction("main"); InterpretationData& dataBody = Attachments::get(funcMain); ASSERT_EQ(FOLD_INTERPRET_INPUT, dataBody.op); int (*main)(int) = (int (*)(int))man->run(); int result = main(10); ASSERT_EQ(21, result); } TEST(Interpretation, StatementCall_RecursionNo_1){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( unwrap = function(data::undef, keys::undef):: undef; interpretation(force){ loop fold(keys->key::string, data->a):: undef { a[key] } } start = function::num; entry{ result = unwrap( { a = { b = { c = "core" } } }, ["a", "b", "c"])::undef. result == "core" } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(1, result); } TEST(Interpretation, StatementCall_RecursionDirect_1){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( unwrap = function(data:: X):: Y { if (data[0] == "a")::Y {0} else {unwrap(data[0])} } entry = function:: i8; entry { unwrap([[[["a"]]]]):: i8; interpretation(force) } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } InterpretationResolution resolutionActual = pass->process(man->root->findFunction("unwrap")); ASSERT_EQ(ANY, resolutionActual); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(0, result); } TEST(Interpretation, StatementCall_RecursionIndirect_1){ XreateManager* man = XreateManager::prepare( R"Code( funcA = function(data:: X):: Y { if (data == "a")::Y {0} else {funcB(data)} } funcB = function(data:: X):: Y { if (data == "b")::Y {1} else {funcA(data)} } entry = function:: i8; entry { funcA(""):: i8; interpretation(force) } )Code" ); InterpretationPass* pass = new InterpretationPass(man); ASSERT_DEATH(pass->run(), "Indirect recursion detected"); } TEST(Interpretation, PartialIntr_1){ XreateManager* man = XreateManager::prepare( R"Code( evaluate= function(argument:: num, code:: string; interpretation(force)):: num { switch(code)::int case ("inc") {argument + 1} case ("dec") {argument - 1} case ("double") {argument * 2} } main = function::int; entry { commands= ["inc", "double", "dec"]:: [string]; interpretation(force). loop fold(commands->comm::string, 10->operand):: int{ evaluate(operand, comm) } } )Code" ); InterpretationPass* pass = new InterpretationPass(man); pass->run(); ManagedFnPtr fnEvaluate = man->root->findFunction("evaluate"); InterpretationResolution resFnEvaluate= pass->process(fnEvaluate); ASSERT_EQ(CMPL_ONLY, resFnEvaluate); ASSERT_TRUE(FunctionInterpretationHelper::needPartialInterpretation(fnEvaluate)); const Expression& exprLoop = man->root->findFunction("main")->__entry->getBody(); - Symbol symbCallEv{{0, VERSION_NONE}, exprLoop.blocks.front()}; + Symbol symbCallEv{{0, versions::VERSION_NONE}, exprLoop.blocks.front()}; InterpretationData dataCallEv = Attachments::get(symbCallEv); ASSERT_EQ(CMPL_ONLY, dataCallEv.resolution); ASSERT_EQ(CALL_INTERPRET_PARTIAL, dataCallEv.op); } TEST(Interpretation, Compilation_PartialIntr_2){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( evaluate= function(argument:: num, code:: string; interpretation(force)):: num { switch(code)::int case ("inc") {argument + 1} case ("dec") {argument - 1} case ("double") {argument * 2} case default {argument} } main = function::int; entry { commands= ["inc", "double", "dec"]:: [string]; interpretation(force). loop fold(commands->comm::string, 10->operand):: int{ evaluate(operand, comm) } } )Code" ); man->analyse(); if (!man->isPassRegistered(PassId::InterpretationPass)){ InterpretationPass* pass = new InterpretationPass(man); pass->run(); } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(21, result); } TEST(Interpretation, PartialIntr_3){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( Command= type variant (INC, DEC, DOUBLE). evaluate= function(argument:: num, code:: Command; interpretation(force)):: num { switch(code)::int case (INC) {argument + 1} case (DEC) {argument - 1} case (DOUBLE) {argument * 2} case default {argument} } main = function::int; entry { commands= [INC, DOUBLE, DEC]:: [Command]; interpretation(force). loop fold(commands->comm::Command, 10->operand):: int{ evaluate(operand, comm) } } )Code" ); man->analyse(); if (!man->isPassRegistered(PassId::InterpretationPass)){ InterpretationPass* pass = new InterpretationPass(man); pass->run(); } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(21, result); } TEST(InterpretationExamples, Regexp1){ FILE* input = fopen("scripts/dsl/regexp.xreate","r"); assert(input != nullptr); std::unique_ptr man(XreateManager::prepare(input)); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(4, result); } //TOTEST call indirect recursion(w/o tags) //TASk implement and test Loop Inf (fix acc types in coco grammar) diff --git a/cpp/tests/modules.cpp b/cpp/tests/modules.cpp index ed0df5a..d2f0e62 100644 --- a/cpp/tests/modules.cpp +++ b/cpp/tests/modules.cpp @@ -1,321 +1,321 @@ /* * modules.cpp * * Author: pgess * Created on June 18, 2017, 8:25 PM */ class Modules_AST2_Test; class Modules_Discovery1_Test; class Modules_Solve1_Test; #define FRIENDS_MODULES_TESTS \ friend class ::Modules_AST2_Test; \ friend class ::Modules_Discovery1_Test; \ friend class ::Modules_Solve1_Test; #include "modules.h" -#include "misc/xreatemanager-decorators.h" -#include "misc/xreatemanager-modules.h" +#include "aux/xreatemanager-decorators.h" +#include "aux/xreatemanager-modules.h" #include "xreatemanager.h" #include "modules/Parser.h" #include "gtest/gtest.h" #include #include #include namespace fs = boost::filesystem; using namespace std; using namespace xreate; using namespace xreate::modules; TEST(Modules, AST1) { FILE* input = fopen("scripts/dsl/regexp.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); ASSERT_EQ(parser.errors->count, 0); } TEST(Modules, AST2){ string code = R"Code( module { name(test1). status(untested). require provides(logging). include controller("/tmp/test-controller.ls"). discover("/tmp/root/"). } )Code"; Scanner scanner(reinterpret_cast(code.c_str()), code.size()); Parser parser(&scanner); parser.Parse(); ModuleRecord module = parser.module; ASSERT_EQ(2, module.__properties.size()); ASSERT_EQ("name", module.__properties.front().getValueString()); ASSERT_EQ("status", module.__properties.back().getValueString()); ASSERT_EQ(1, module.__queries.size()); ASSERT_EQ("provides", module.__queries.front().getValueString()); ASSERT_EQ(1, module.__controllers.size()); ASSERT_EQ("/tmp/test-controller.ls", module.__controllers.front()); ASSERT_EQ(1, module.__discoveries.size()); ASSERT_EQ("/tmp/root/", module.__discoveries.front()); } TEST(Modules, Discovery1){ const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54723/"; string codeA = R"Code(module { name(testA). status(needToTestMore). })Code"; string codeB = R"Code(module { name(testB). status(needToTestEvenMore). })Code"; string codeMain = string("module{discover \"") + dirModulesRoot + "\".}"; fs::create_directories(dirModulesRoot); fs::ofstream fileA(dirModulesRoot + "a.xreate"); fileA << codeA; fileA.close(); fs::ofstream fileB(dirModulesRoot + "b.xreate"); fileB << codeB; fileB.close(); Scanner scanner(reinterpret_cast(codeMain.c_str()), codeMain.size()); Parser parser(&scanner); parser.Parse(); ModulesRegistry registry; ModulesSolver solver(®istry); solver.discoverModules(parser.module); fs::remove_all(dirModulesRoot); std::string output = solver.__program.str(); cout << output << endl; ASSERT_NE(string::npos, output.find("bind_module(0, name(testA)).")); ASSERT_NE(string::npos, output.find("bind_module(1, status(needToTestEvenMore)).")); } TEST(Modules, Requests1){ } TEST(Modules, Solve1){ const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54724/"; string codeA = R"Code(module { name(testA). provide(superService). status(needToTestMore). })Code"; string codeB = R"Code(module { name(testB). provide(superService). status(needToTestEvenMore). })Code"; string codeMain = R"Code(module { discover("/tmp/testModulesDiscovery1_t54724/") include controller ("/tmp/testModulesDiscovery1_t54724/controller") require (superService) })Code"; string codeController = R"Code( status_score(0, needToTestEvenMore). status_score(1, needToTestMore). module_include_candidate(X, Y, Request):- module_require(X, Request); bind_module(Y, provide(Request)). module_include_winner(X, Request, MaxScore) :- MaxScore = #max{Score: module_include_candidate(X, Y, Request), bind_module(Y, status(Status)), status_score(Score, Status)}; module_require(X, Request). module_include(X, Y) :- module_include_winner(X, Request, MaxScore); bind_module(Y, provide(Request)); bind_module(Y, status(Status)); status_score(MaxScore, Status). )Code"; fs::create_directories(dirModulesRoot); fs::ofstream fileA(dirModulesRoot + "a.xreate"); fileA << codeA; fileA.close(); fs::ofstream fileB(dirModulesRoot + "b.xreate"); fileB << codeB; fileB.close(); fs::ofstream fileController(dirModulesRoot + "controller"); fileController << codeController; fileController.close(); Scanner scanner(reinterpret_cast(codeMain.c_str()), codeMain.size()); Parser parser(&scanner); parser.Parse(); ModulesRegistry registry; ModulesSolver solver(®istry); solver.init("", parser.module); fs::remove_all(dirModulesRoot); cout << solver.__program.str() << endl; std::list modulesRequired = solver.run(parser.module); ASSERT_EQ(1, modulesRequired.size()); string moduleActualRequired = modulesRequired.front(); string moduleExpected = dirModulesRoot + "a.xreate"; ASSERT_EQ(moduleExpected, moduleActualRequired); } TEST(Modules, Compilation1){ const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54726/"; string codeMain = R"Code( module { discover("/tmp/testModulesDiscovery1_t54726/") include controller("/tmp/testModulesDiscovery1_t54726/controller") require (superService) } test = function:: int; entry { getYourNumber() } )Code"; string codeA = R"Code(module { name(testA). provide(superService). status(needToTestEvenMore). } getYourNumber= function:: int {0} )Code"; string codeB = R"Code(module { name(testB). provide(superService). status(needToTestMore). } getYourNumber= function:: int {1} )Code"; string codeController = R"Code( status_score(0, needToTestEvenMore). status_score(1, needToTestMore). module_include_candidate(X, Y, Request):- module_require(X, Request); bind_module(Y, provide(Request)). module_include_winner(X, Request, MaxScore) :- MaxScore = #max{Score: module_include_candidate(X, Y, Request), bind_module(Y, status(Status)), status_score(Score, Status)}; module_require(X, Request). module_include(X, Y) :- module_include_winner(X, Request, MaxScore); bind_module(Y, provide(Request)); bind_module(Y, status(Status)); status_score(MaxScore, Status). )Code"; fs::create_directories(dirModulesRoot); fs::ofstream fileA(dirModulesRoot + "a.xreate"); fileA << codeA; fileA.close(); fs::ofstream fileB(dirModulesRoot + "b.xreate"); fileB << codeB; fileB.close(); fs::ofstream fileController(dirModulesRoot + "controller"); fileController << codeController; fileController.close(); auto man = new XreateManagerImpl>(); man->prepareCode(std::move(codeMain)); fs::remove_all(dirModulesRoot); int (*funcMain)() = (int (*)()) man->run(); int result = funcMain(); ASSERT_EQ(1, result); } TEST(Modules, Compilation_AssignModulePath1){ const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54725/"; string codeMain = R"Code( module { discover("/tmp/testModulesDiscovery1_t54725/") include controller("/tmp/testModulesDiscovery1_t54725/controller") require (superService) } test = function:: int; entry { getYourNumber() } )Code"; string codeA = R"Code(module { name(testA). provide(superService). status(needToTestEvenMore). } getYourNumber= function:: int {0} )Code"; string codeController = R"Code( module_include(X, "/tmp/testModulesDiscovery1_t54725/a.xreate") :- module_require(X, superService). )Code"; fs::create_directories(dirModulesRoot); fs::ofstream fileA(dirModulesRoot + "a.xreate"); fileA << codeA; fileA.close(); fs::ofstream fileController(dirModulesRoot + "controller"); fileController << codeController; fileController.close(); auto man = new XreateManagerImpl>(); man->prepareCode(std::move(codeMain)); fs::remove_all(dirModulesRoot); int (*funcMain)() = (int (*)()) man->run(); int result = funcMain(); ASSERT_EQ(0, result); -} \ No newline at end of file +} diff --git a/grammar/xreate.ATG b/grammar/xreate.ATG index 932c766..5dccd2f 100644 --- a/grammar/xreate.ATG +++ b/grammar/xreate.ATG @@ -1,625 +1,625 @@ //TODO add ListLiteral //TODO ExprTyped: assign default(none) type #include "ast.h" #include "ExternLayer.h" #include "pass/adhocpass.h" #include #include #define wprintf(format, ...) \ char __buffer[100]; \ wcstombs(__buffer, format, 100); \ fprintf(stderr, __buffer, __VA_ARGS__) using namespace std; COMPILER Xreate details::incomplete::AST* root = nullptr; // current program unit void ensureInitalizedAST(){ if (root == nullptr) root = new details::incomplete::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)){ if (!root->recognizeVariantIdentifier(i)){ root->postponeIdentifier(context.scope, i); } } } enum SwitchKind{SWITCH_NORMAL, SWITCH_META}; CHARACTERS letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". any = ANY - '"'. digit = "0123456789". cr = '\r'. lf = '\n'. tab = '\t'. TOKENS ident = (letter | '_') {letter | digit | '_'}. number = (digit | '-' digit) {digit}. string = '"' { any } '"'. function = "function". pre = "pre". lparen = '('. rparen = ')'. lbrack = '['. rbrack = ']'. lcurbrack = '{'. rcurbrack = '}'. equal = "==". assign = '='. implic = '-' '>'. colon = ':'. context = "context". tagcolon = "::". lse = "<=". lss = "<". gte = ">=". gtr = ">". ne1 = "!=". ne2= "<>". COMMENTS FROM "/*" TO "*/" NESTED COMMENTS FROM "//" TO lf IGNORE cr + lf + tab PRODUCTIONS Xreate = (. Function* function; ensureInitalizedAST(); .) {( RuleDecl | InterfaceData | Imprt | ContextSection | 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()); .) + | 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));.) } ')'] [ tagcolon ( IF(flagIsPrefunct) FnTag | Type ) {';' FnTag }] BDecl (. entry->getBody().bindType(move(typOut));.) . ContextSection<>= (. Expression context; Function* f; .) "case" "context" tagcolon MetaSimpExpr lcurbrack { FDecl (. f->guardContext = context; 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 | 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()); .) } 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); .) } ')'] ) . TList = (. TypeAnnotation ty; .) '[' Type ']' (. typ = TypeAnnotation(TypeOperator::ARRAY, {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::STRUCT, {t}); typ.fields.push_back(Atom(key).get()); .) {',' ( IF(checkTokenAfterIdent(_tagcolon)) Ident tagcolon Type | Type (. key = to_wstring(keyCounter++); .) ) (. typ.__operands.push_back(t); typ.fields.push_back(Atom(key).get()); .) } rcurbrack. TDecl = (. std::wstring ttag; TypeAnnotation t, t1; std::wstring tname, arg; std::vector> args; .) Ident assign "type" ( "alias" Type (. root->add(move(t), Atom(tname)); .) | "variant" lparen Ident (. t = TypeAnnotation(TypeOperator::VARIANT, {}); args.push_back(Atom(arg)); .) {',' Ident (. args.push_back(Atom(arg)); .) } rparen (. t.addFields(move(args)); root->add(move(t), Atom(tname)); .) | Ident ['(' Ident (. args.push_back(Atom(arg)); .) {',' Ident (. args.push_back(Atom(arg)); .) } ')'] Type (. 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 (. f->addDeclaration(move(var), move(value)); .) +VDecl = (. std::wstring vname; Expression var, value;.) + VarIdent assign ExprTyped (. f->addDeclaration(move(var), move(value)); .) . -//TODO forbid multiple body declaration (ExprTyped) BDecl = lcurbrack (. Expression body; pushContextScope(scope); .) {(IF(checkAssignment()) VDecl '.' | RuleContextDecl | ContextDecl'.' - | ExprTyped (. scope->setBody(body); .) - )} (. popContextScope(); .) - rcurbrack . + | ExprTyped (. scope->setBody(body); .) + )} + 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}); .) 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 BDecl<&*block> (. e.addBindings({Atom(varEl)}); block->addBinding(Atom(varEl), move(tagsEl)); e.addBlock(block); .) |"fold" ("inf" '(' Expr implic Ident ')' (. e = Expression(Operator::FOLD_INF, {eAcc}); e.addBindings({Atom(varAcc)}); .) tagcolon ExprAnnotations BDecl<&*block> (. block->addBinding(Atom(varAcc), Expression()); e.addBlock(block); .) | '(' Expr implic Ident tagcolon ExprAnnotations ['|' Expr ] ',' Expr implic Ident')' (. e = Expression(Operator::FOLD, {eIn, eAcc}); e.addBindings({Atom(varEl), Atom(varAcc)}); .) tagcolon ExprAnnotations BDecl<&*block> (. block->addBinding(Atom(varEl), move(tagsEl)); block->addBinding(Atom(varAcc), Expression()); e.addBlock(block); .) ) | "context" '(' string (. contextClass = t->val; .) ')' BDecl<&*block> (. e = Expression(Operator::LOOP_CONTEXT, {Expression(Atom(std::move(contextClass)))}); e.addBlock(block); .) ). SwitchDecl = (. TypeAnnotation typ; eSwitch = Expression(Operator::SWITCH, {}); Expression eCondition; Expression tag;.) ["switch" ( "ad" "hoc" lparen Expr tagcolon MetaSimpExpr rparen (. eSwitch.op = Operator::SWITCH_ADHOC; eSwitch.operands.push_back(eCondition); eSwitch.addTags({tag}); flagSwitchKind = SWITCH_META; .) | lparen Expr 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)); .) } (. scope->setBody(guard); popContextScope(); .) . IntrinsicDecl= (. std::wstring name; .) "intrinsic" Ident< name> (. outer = Expression(Operator::CALL_INTRINSIC, {}); outer.setValue(Atom(name)); .) lparen [CalleeParams] rparen . /*============================ INTERFACES ===============================*/ Imprt<> = "import" "raw" lparen string (. root->__rawImports.push_back(Atom(t->val).get()); .) rparen '.'. InterfaceData<> = "interface" '(' ( "dfa" ')' InterfaceDFA | "extern-c" ')' InterfaceExternC | "cfa" ')' InterfaceCFA | "adhoc" ')' InterfaceAdhoc ). InterfaceAdhoc<> = '{' { PrefunctionSchemeDecl } '}'. PrefunctionSchemeDecl<> = (. TypeAnnotation typReturn; std::wstring prefName; Expression exprCases; .) pre function Ident tagcolon Type lcurbrack SwitchDecl rcurbrack (. Expression prefData(Operator::CALL, {Atom(prefName), exprCases}); prefData.bindType(typReturn); root->addInterfaceData(Adhoc, move(prefData)); .). InterfaceExternC<> = (. ExternData data; .) '{' {IncludeExternDecl | LibExternDecl } '}' (. root->addExternData(move(data)); .) . LibExternDecl = (. std::wstring pkgname, libname; .) Ident assign "library" tagcolon "pkgconfig" '(' string (. pkgname = t->val; .) ')' '.' (. data.addLibrary(Atom(libname), Atom(pkgname)); .) . IncludeExternDecl = (. Expression inc; .) "include" StructLiteral '.' (. data.addIncludeDecl(move(inc)); .) . InterfaceDFA<> = '{' { InstructDecl } '}' . InstructDecl = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; tags.push_back(Expression()); /* return value */ .) "operator" InstructAlias tagcolon '(' (.scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { ',' MetaSimpExpr (. tags.push_back(tag); .) } ] ')' [ implic MetaSimpExpr (. tags[0] = tag; .) ] (. root->addDFAData(move(scheme)); .) '.'. 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 } '}' . 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); .) } ] '.' (. 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 '}' . /* - 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})); .). 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 ')' | 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 ] ')' | 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(Atom(i1)); .) +| Ident (. e = Expression(Operator::CALL, {Atom(i1)}); .) ). MetaCalleeParams = (. Expression e2; .) MetaSimpExpr (. e.addArg(Expression(e2)); .) {',' 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 [lbrack (. e = Expression(Operator::INDEX, {e}); .) CalleeParams rbrack ]. Term< Expression& e> (. std::wstring name; e = Expression(); .) = (IF (checkParametersList()) Ident< name> (. e = Expression(Operator::CALL, {Atom(name)}); .) '(' [CalleeParams] ')' | VarIdent (. recognizeIdentifier(e); .) | ListLiteral (. /* tuple */.) | StructLiteral (. /* struct */.) | LoopDecl | IfDecl | SwitchDecl | AdhocDecl | IntrinsicDecl - | "true" (. e = Expression(Atom(1)); e.bindType(TypePrimitive::Bool); .) - | "false" (. e = Expression(Atom(0)); e.bindType(TypePrimitive::Bool); .) | 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); .) | '-' Term (. e = Expression(Operator::NEG, {e}); .) | '(' ExprTyped ')' ). StructLiteral = (. std::wstring key; Expression val; std::list> keys; size_t keyCounter=0; .) lcurbrack (IF(checkTokenAfterIdent(_assign)) Ident '=' Expr | Expr (. key = to_wstring(keyCounter++); .) ) (. keys.push_back(Atom(key)); e = Expression(Operator::LIST_NAMED, {val}); .) {',' (IF(checkTokenAfterIdent(_assign)) Ident '=' 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; .) '[' [ Expr (. e.addArg(Expression(eFrom)); .) (".." Expr (. e.addArg(Expression(eTo)); e.setOp(Operator::LIST_RANGE); .) |{',' Expr (. e.addArg(Expression(eFrom)); .) } (. e.setOp(Operator::LIST); .) ) ] ']'. AdhocDecl = (. Expression command; .) "ad" "hoc" MetaSimpExpr (. adhoc::AdhocExpression exprAdhoc; exprAdhoc.setCommand(command); e = exprAdhoc; .). CalleeParams = (. Expression e2; .) ExprTyped (. e.addArg(Expression(e2)); .) {',' 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} '}'. END Xreate.