diff --git a/config/default.json b/config/default.json index 33f43d3..1fda882 100644 --- a/config/default.json +++ b/config/default.json @@ -1,70 +1,70 @@ { "containers": { "id": { "implementations": "impl_fulfill_cluster", "clusters": "var_cluster", "prototypes": "proto_cluster", "linkedlist": "linkedlist" }, "impl": { "solid": "solid", "onthefly": "on_the_fly" } }, "logging": { "id": "logging" }, "function-entry": "entry", "clasp": { "bindings" : { "variable": "bind", "function": "bind_func", "scope": "bind_scope", "function_demand" : "bind_function_demand", "scope_decision": "bind_scope_decision" }, "context" : { "decisions":{ "dependent": "resolution_dependency" }, }, "nonevalue": "nonevalue", "ret": { "symbol": "retv", "tag": "ret" } }, "tests": { "template": "default", "templates": { "default": "*-", "adhocs": "Adhoc.*", "effects": "Effects.*", "basic": "Attachments.*", "ast": "AST.*", "cfa": "CFA.*", "dfa": "DFA.*", - "compilation": "Compilation.functionEntry1*", + "compilation": "Compilation.*", "diagnostic": "Diagnostic.*", "ExpressionSerializer": "ExpressionSerializer.*", "externc": "InterfaceExternC.*", "types": "Types.*-", "vendorsAPI/clang": "ClangAPI.*", "vendorsAPI/xml2": "libxml2*", "dsl": "Interpretation.*:InterpretationExamples.*", "context": "Context.*", "containers": "Containers.*", "loops": "Loop.*", "modules": "Modules.*" } } } diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index 82c04c7..de1b0c3 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -1,228 +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 - compilation/pointerarithmetic.cpp + compilation/operators.cpp compilation/transformations.cpp compilation/transformersaturation.cpp pass/compilepass.cpp pass/dfapass.cpp analysis/dfagraph.cpp pass/versionspass.cpp compilation/targetinterpretation.cpp attachments.cpp 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 ) set(XREATE_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/ ) INCLUDE_DIRECTORIES(${XREATE_INCLUDE_DIRS}) set(XREATE_PRIVATE_INCLUDE_DIRS ${XREATE_INCLUDE_DIRS} ${COCO_GRAMMAR_PATH} ${JEAYESON_INCLUDE_PATH} ${LLVM_INCLUDE_DIRS} ${POTASSCO_INCLUDE_PATH} ) add_library(${PROJECT_NAME} SHARED ${COCO_SOURCE_FILES} ${SOURCE_FILES}) target_link_libraries(${PROJECT_NAME}) target_include_directories(${PROJECT_NAME} INTERFACE ${XREATE_INCLUDE_DIRS} ${COCO_GRAMMAR_PATH} ${JEAYESON_INCLUDE_PATH} ${LLVM_INCLUDE_DIRS} ${POTASSCO_INCLUDE_PATH} ) get_directory_property(DEFINITIONS_ALL DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_DEFINITIONS) message("definitions all: " ${DEFINITIONS_ALL}) target_compile_definitions(${PROJECT_NAME} INTERFACE ${DEFINITIONS_ALL}) get_directory_property(COMPILATION_OPTIONS_ALL DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_OPTIONS) message("compilations all: " ${COMPILATION_OPTIONS_ALL}) target_compile_options(${PROJECT_NAME} INTERFACE ${COMPILATION_OPTIONS_ALL}) SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY INTERFACE_LINK_LIBRARIES ${LIBCLASP_LIBS} ${CLANG_LIBS} ${LLVM_LIBS} tbb boost_system boost_filesystem ) #${CLANG_LIBS} #set (LINK_INTERFACE_LIBRARIES "") # FUNCTION(PREPEND var prefix) # SET(listVar "") # FOREACH(f ${ARGN}) # LIST(APPEND listVar "${prefix}/${f}") # ENDFOREACH(f) # SET(${var} "${listVar}" PARENT_SCOPE) # ENDFUNCTION(PREPEND) #set(COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "-j4") #cotire(xreate) # MACRO (ADD_PCH_RULE _header_filename _src_list) # SET(_gch_filename "${_header_filename}.gch") # LIST(APPEND ${_src_list} ${_gch_filename}) # SET (_args ${CMAKE_CXX_FLAGS}) # LIST(APPEND _args -c ${_header_filename} -o ${_gch_filename}) # GET_DIRECTORY_PROPERTY(DIRINC INCLUDE_DIRECTORIES) # foreach (_inc ${DIRINC}) # LIST(APPEND _args "-I" ${_inc}) # endforeach(_inc ${DIRINC}) # SEPARATE_ARGUMENTS(_args) # add_custom_command(OUTPUT ${_gch_filename} # COMMAND rm -f ${_gch_filename} # COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1} ${_args} # DEPENDS ${_header_filename}) # ENDMACRO(ADD_PCH_RULE _header_filename _src_list) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/ast.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/llvmlayer.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/clasplayer.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/pass/abstractpass.h SOURCE_FILES) diff --git a/cpp/src/analysis/typeinference.cpp b/cpp/src/analysis/typeinference.cpp new file mode 100644 index 0000000..564650c --- /dev/null +++ b/cpp/src/analysis/typeinference.cpp @@ -0,0 +1,55 @@ +/* + * 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 analysis {namespace typeinference { + +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"); +} + + + +} } } \ No newline at end of file diff --git a/cpp/src/analysis/typeinference.h b/cpp/src/analysis/typeinference.h new file mode 100644 index 0000000..621a5a7 --- /dev/null +++ b/cpp/src/analysis/typeinference.h @@ -0,0 +1,27 @@ +/* + * File: typeinference.h + * Author: pgess + * + * Created on April 16, 2017, 10:17 AM + */ + +#ifndef TYPEINFERENCE_H +#define TYPEINFERENCE_H + +#include "ast.h" +#include "llvm/IR/IRBuilder.h" + +namespace llvm { + class Value; + class Type; +}; + +namespace xreate {namespace analysis {namespace typeinference { + +llvm::Value* doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, llvm::IRBuilder<>& builder); +ExpandedType getType(const Expression& expression, const AST& ast); + +} } } //namespace xreate + +#endif /* TYPEINFERENCE_H */ + diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp index 2a890b2..d11b636 100644 --- a/cpp/src/ast.cpp +++ b/cpp/src/ast.cpp @@ -1,934 +1,926 @@ #include "ast.h" #include "ExternLayer.h" +#include "analysis/typeinference.h" + #include #include 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&& pack = expandOperands(t.__operands); - auto tnew = TypeAnnotation(TypeOperator::STRUCT, move(pack)); - tnew.fields = t.fields; + std::vector&& packOperands = expandOperands(t.__operands); + auto typNew = TypeAnnotation(TypeOperator::STRUCT, move(packOperands)); + typNew.fields = t.fields; - return ExpandedType(move(tnew)); + 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::TUPLE: - { - assert(t.__operands.size()); - - std::vector pack; - pack.reserve(t.__operands.size()); - - std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(pack, pack.end()), - [this](const TypeAnnotation & t) { - return expandType(t); - }); - - return ExpandedType(TypeAnnotation(TypeOperator::TUPLE, move(pack))); - } - case TypeOperator::VARIANT: { return ExpandedType(TypeAnnotation(t)); } case TypeOperator::NONE: { return ExpandedType(TypeAnnotation(t)); } default: assert(false); } assert(false); return ExpandedType(TypeAnnotation()); } }; TypeAnnotation::TypeAnnotation() : __operator(TypeOperator::NONE), __value(TypePrimitive::Invalid) {} TypeAnnotation::TypeAnnotation(TypePrimitive typ) : __value(typ) { } TypeAnnotation::TypeAnnotation(TypeOperator op, std::initializer_list 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(); } 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 analysis::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); 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); 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}; } 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}; } diff --git a/cpp/src/ast.h b/cpp/src/ast.h index 3ca65f2..fe90e83 100644 --- a/cpp/src/ast.h +++ b/cpp/src/ast.h @@ -1,573 +1,575 @@ #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, TUPLE, STRUCT, ACCESS, LINK + 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; template<> struct AttachmentsDict { typedef VariableVersion Data; static const unsigned int key = 6; }; struct ScopedSymbol{ VNameId id; VariableVersion version; static const ScopedSymbol RetSymbol; }; struct Symbol { ScopedSymbol identifier; CodeScope * scope; }; template<> struct AttachmentsDict { 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/compilation/adhocfunctiondecorator.h b/cpp/src/compilation/adhocfunctiondecorator.h new file mode 100644 index 0000000..44a2dbf --- /dev/null +++ b/cpp/src/compilation/adhocfunctiondecorator.h @@ -0,0 +1,46 @@ +/* + * File: adhocfunctiondecorator.h + * Author: pgess + * + * Created on July 29, 2017, 12:26 PM + */ + +#ifndef ADHOCFUNCTIONDECORATOR_H +#define ADHOCFUNCTIONDECORATOR_H + +#include "ast.h" +#include "llvmlayer.h" + +using namespace xreate::compilation; + +namespace xreate{ namespace adhoc{ +template +class AdhocFunctionDecorator: public Parent{ +public: + AdhocFunctionDecorator(ManagedFnPtr f, CompilePass* p) + : Parent(f, p) {} + +protected: + llvm::Type* prepareResult(){ + PassManager* man = Parent::pass->man; + CodeScope* entry = Parent::function->__entry; + LLVMLayer* llvm = Parent::pass->man->llvm; + AST* ast = Parent::pass->man->root; + adhoc::AdhocPass* adhocpass = reinterpret_cast(man->getPassById(PassId::AdhocPass)); + + if (! Parent::function->isPrefunction){ + return Parent::prepareResult(); + } + + adhocImplementation = adhocpass->findAssotiatedScheme(entry); + return llvm->toLLVMType(ast->expandType(adhocImplementation->getResultType())); + } + +public: + AdhocScheme* adhocImplementation=nullptr; +}; + +}} //end of namespace xreate::adhoc + +#endif /* ADHOCFUNCTIONDECORATOR_H */ + diff --git a/cpp/src/compilation/advanced.cpp b/cpp/src/compilation/advanced.cpp index c83705f..f5c489b 100644 --- a/cpp/src/compilation/advanced.cpp +++ b/cpp/src/compilation/advanced.cpp @@ -1,404 +1,399 @@ /* * File: InstructionsAdvanced.cpp * Author: pgess * * Created on June 26, 2016, 6:00 PM */ //#include #include "compilation/advanced.h" #include "compilation/containers.h" #include "compilation/transformersaturation.h" #include "query/context.h" #include "query/containers.h" #include "llvmlayer.h" #include "ast.h" using namespace std; using namespace llvm; using namespace xreate; using namespace xreate::containers; using namespace xreate::compilation; #define NAME(x) (hintRetVar.empty()? x : hintRetVar) #define UNUSED(x) (void)(x) #define EXPAND_CONTEXT \ LLVMLayer* llvm = context.pass->man->llvm; \ compilation::AbstractCodeScopeUnit* scope = context.scope; \ compilation::FunctionUnit* function = context.function; Advanced::Advanced(compilation::Context ctx) : context(ctx), tyNum(static_cast (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); 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) { - std::vector refs; - - llvm::IntegerType* tyInt = llvm::Type::getInt32Ty(llvm::getGlobalContext()); - llvm::ConstantInt* zero = llvm::ConstantInt::get(tyInt, 0, false); - - llvm::BasicBlock *blockSafe = llvm::BasicBlock::Create(llvm::getGlobalContext(), "safe", function->raw); - + //TODO DISABLEDFEATURE validptr // TODO review safety check: validPtr for `aggregate` // SECTIONTAG validptr exception - PointerType* tyAggr = dyn_cast(aggregate->getType()); - llvm::Value* null = llvm::ConstantPointerNull::get(tyAggr); - Value* condNull = llvm->builder.CreateICmpNE(aggregate, null); - - llvm::BasicBlock *blockException = llvm::BasicBlock::Create(llvm::getGlobalContext(), "exception", function->raw); - llvm->builder.CreateCondBr(condNull, blockSafe, blockException); - llvm->initExceptionBlock(blockException); - - llvm->builder.SetInsertPoint(blockSafe); - std::vector indexes; +// 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)) { - indexes.push_back(zero); + llvm::Value* addr = llvm->builder.CreateConstGEP2_32(nullptr, aggregate, 0, i); + return llvm->builder.CreateLoad(addr); } - indexes.push_back(ConstantInt::get(tyInt, i)); - - Value* addr = llvm->builder.CreateGEP(aggregate, indexes); - return llvm->builder.CreateLoad(addr); + aggregate->getType()->dump(); + return llvm->builder.CreateExtractValue(aggregate, llvm::ArrayRef{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); 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); unitLoop->bindArg(accum, move(accumName)); Value* accumNext = unitLoop->compile(); // * Loop saturation checks bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockNext, blockAfterLoop, context); assert(flagSaturationTriggered); // * computing next iteration state llvm->builder.SetInsertPoint(blockNext); accum->addIncoming(accumNext, llvm->builder.GetInsertBlock()); llvm->builder.CreateBr(blockLoop); // finalization: llvm->builder.SetInsertPoint(blockAfterLoop); return accumNext; } llvm::Value* Advanced::compileIf(const Expression& exprIf, const std::string& hintRetVar) { EXPAND_CONTEXT //initialization: const Expression& condExpr = exprIf.getOperands()[0]; llvm::IRBuilder<>& builder = llvm->builder; //llvm::Type* tyResultType = llvm->toLLVMType(llvm->ast->expandType(exprIf.type)); llvm::BasicBlock *blockAfter = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifAfter", function->raw); llvm::BasicBlock *blockTrue = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifTrue", function->raw); llvm::BasicBlock *blockFalse = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifFalse", function->raw); llvm::Value* cond = scope->process(condExpr); llvm->builder.CreateCondBr(cond, blockTrue, blockFalse); builder.SetInsertPoint(blockTrue); CodeScope* scopeTrue = exprIf.blocks.front(); llvm::Value* resultTrue = function->getScopeUnit(scopeTrue)->compile(); blockTrue = builder.GetInsertBlock(); builder.CreateBr(blockAfter); builder.SetInsertPoint(blockFalse); CodeScope* scopeFalse = exprIf.blocks.back(); llvm::Value* resultFalse = function->getScopeUnit(scopeFalse)->compile(); blockFalse = builder.GetInsertBlock(); builder.CreateBr(blockAfter); builder.SetInsertPoint(blockAfter); llvm::PHINode *ret = builder.CreatePHI(resultTrue->getType(), 2, NAME("if")); ret->addIncoming(resultTrue, blockTrue); ret->addIncoming(resultFalse, blockFalse); return ret; } //TODO Switch: default variant no needed when all possible conditions are considered llvm::Value* Advanced::compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar) { EXPAND_CONTEXT + AST* root = context.pass->man->root; UNUSED(function); + assert(exprSwitch.operands.size() >= 2); assert(exprSwitch.operands[1].op == Operator::CASE_DEFAULT && "No default case in Switch Statement"); int countCases = exprSwitch.operands.size() - 1; llvm::IRBuilder<>& builder = llvm->builder; llvm::BasicBlock* blockProlog = builder.GetInsertBlock(); llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "switchAfter", function->raw); builder.SetInsertPoint(blockEpilog); - llvm::Type* exprSwitchType = llvm->toLLVMType(ExpandedType(exprSwitch.type)); + llvm::Type* exprSwitchType = llvm->toLLVMType(root->getType(exprSwitch)); llvm::PHINode *ret = builder.CreatePHI(exprSwitchType, countCases, NAME("switch")); builder.SetInsertPoint(blockProlog); llvm::Value * conditionSwitch = scope->process(exprSwitch.operands[0]); llvm::BasicBlock *blockDefault = llvm::BasicBlock::Create(llvm::getGlobalContext(), "caseDefault", function->raw); llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(conditionSwitch, blockDefault, countCases); for (int size = exprSwitch.operands.size(), i = 2; i < size; ++i) { llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm::getGlobalContext(), "case" + std::to_string(i), function->raw); llvm::Value* condCase = function->getScopeUnit(exprSwitch.operands[i].blocks.front())->compile(); builder.SetInsertPoint(blockCase); llvm::Value* resultCase = function->getScopeUnit(exprSwitch.operands[i].blocks.back())->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultCase, builder.GetInsertBlock()); builder.SetInsertPoint(blockProlog); instructionSwitch->addCase(dyn_cast(condCase), blockCase); } //compile default block: builder.SetInsertPoint(blockDefault); CodeScope* scopeDefault = exprSwitch.operands[1].blocks.front(); llvm::Value* resultDefault = function->getScopeUnit(scopeDefault)->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultDefault, builder.GetInsertBlock()); builder.SetInsertPoint(blockEpilog); return ret; } //TODO recognize cases to make const arrays/stored in global mem/stack alloced. llvm::Value* Advanced::compileListAsSolidArray(const Expression &expr, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(scope); UNUSED(function); AST* root = context.pass->man->root; const size_t& length = expr.getOperands().size(); const Expression& expression = expr; llvm::Value* zero = ConstantInt::get(tyNum, 0); llvm::Value* one = ConstantInt::get(tyNum, 1); - ExpandedType typAggrExpanded = root->expandType(expression.type); + ExpandedType typAggrExpanded = root->getType(expression); assert(typAggrExpanded->__operator == TypeOperator::ARRAY); llvm::Type* typEl = llvm->toLLVMType(ExpandedType(typAggrExpanded->__operands[0])); ArrayType* typAggr = (ArrayType*) llvm::ArrayType::get(typEl, length); llvm::Value* list = llvm->builder.CreateAlloca(typAggr, ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), length, false), hintRetVar); const std::vector& 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 f60f5ed..c86d08d 100644 --- a/cpp/src/compilation/containers.cpp +++ b/cpp/src/compilation/containers.cpp @@ -1,195 +1,195 @@ #include "compilation/containers.h" using namespace std; using namespace llvm; using namespace xreate; using namespace xreate::containers; Iterator* Iterator::create(xreate::compilation::Context context, const xreate::Symbol& var){ const Implementation& data = Query::queryImplementation(var); switch(data.impl){ case ON_THE_FLY: return new IteratorForward(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); 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->expandType(CodeScope::getDeclaration(source).type); + ExpandedType tySource = llvm->ast->getType(CodeScope::getDeclaration(source)); assert(tySource->__operator == TypeOperator::ARRAY && "Linked list implementation has to have ARRAY type"); assert(tySource->__operands.size()); return xreate::compilation::Advanced(context).compileStructIndex(index, ExpandedType(TypeAnnotation(tySource->__operands.at(0))), linkedlist.fieldPointer); } assert(false && "Unknown declaration"); return nullptr; } //const ImplementationRec& 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/operators.cpp b/cpp/src/compilation/operators.cpp new file mode 100644 index 0000000..14266cf --- /dev/null +++ b/cpp/src/compilation/operators.cpp @@ -0,0 +1,67 @@ +/* + * operators.cpp + * + * Author: pgess + * Created on April 8, 2017, 1:35 PM + */ + +#include "operators.h" +#include "llvmlayer.h" +#include "ExternLayer.h" +#include + +using namespace llvm; +using namespace std; + +namespace xreate { + +namespace pointerarithmetic { +llvm::Value* +PointerArithmetic::add(llvm::Value *left, llvm::Value *right, compilation::Context context, const std::string& hintVarDecl){ + LLVMLayer* llvm = context.pass->man->llvm; + + if (left->getType()->isPointerTy() && right->getType()->isIntegerTy()){ + + std::vector indexes{right}; + //{llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 0)}; + //indexes.push_back(right); + + return llvm->builder.CreateGEP(left, llvm::ArrayRef(indexes), hintVarDecl); + } + + return nullptr; +} +}//end of pointgerarithmetic namespace + +llvm::Value* +StructUpdate::add(const Expression& left, llvm::Value *leftRaw, const Expression& right, compilation::Context context, const std::string& hintVarDecl){\ + if (!(right.__state == Expression::COMPOUND && right.op == Operator::LIST_NAMED)){ + return nullptr; + } + + PassManager* man = context.pass->man; + + ExpandedType tyOperandLeft = man->root->getType(left); + + const std::vector fieldsFormal = (tyOperandLeft.get().__operator == TypeOperator::CUSTOM)? + man->llvm->layerExtern->getStructFields(man->llvm->layerExtern->lookupType(tyOperandLeft.get().__valueCustom)) + : tyOperandLeft.get().fields; + + std::map indexFields; + for(size_t i=0, size = fieldsFormal.size(); iprocess(value, right.bindings.at(i)); + unsigned int fieldId = indexFields.at(right.bindings.at(i)); + + result = man->llvm->builder.CreateInsertValue(result, valueRaw, llvm::ArrayRef({fieldId})); + } + + return result; +} + +} //end of xreate namespace \ No newline at end of file diff --git a/cpp/src/compilation/operators.h b/cpp/src/compilation/operators.h new file mode 100644 index 0000000..10437b7 --- /dev/null +++ b/cpp/src/compilation/operators.h @@ -0,0 +1,33 @@ +/* + * File: operators.h + * Author: pgess + * + * Created on April 8, 2017, 1:33 PM + */ + +#ifndef OPERATORS_H +#define OPERATORS_H + +#include "pass/compilepass.h" + +namespace llvm { + class Value; +} + +namespace xreate { + +namespace pointerarithmetic { + class PointerArithmetic { + public: + static llvm::Value* add(llvm::Value *left, llvm::Value *right, compilation::Context context, const std::string& hintVarDecl); + }; +} //end of pointerarithmetic namespace + +class StructUpdate { +public: + static llvm::Value* add(const Expression& left, llvm::Value *leftRaw, const Expression& right, compilation::Context context, const std::string& hintVarDecl); +}; +} //namespace xreate + +#endif /* OPERATORS_H */ + diff --git a/cpp/src/compilation/pointerarithmetic.cpp b/cpp/src/compilation/pointerarithmetic.cpp deleted file mode 100644 index ed1e020..0000000 --- a/cpp/src/compilation/pointerarithmetic.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - * pointerarithmetic.cpp - * - * Author: pgess - * Created on March 29, 2017, 11:52 AM - */ -#include "pointerarithmetic.h" -#include "llvmlayer.h" -#include - -using namespace llvm; - -namespace xreate { namespace pointerarithmetic { - -llvm::Value* -PointerArithmetic::add(llvm::Value *left, llvm::Value *right, compilation::Context context, const std::string& hintVarDecl){ - LLVMLayer* llvm = context.pass->man->llvm; - - if (left->getType()->isPointerTy() && right->getType()->isIntegerTy()){ - - std::vector indexes{right}; - //{llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 0)}; - //indexes.push_back(right); - - return llvm->builder.CreateGEP(left, llvm::ArrayRef(indexes), hintVarDecl); - } - - return nullptr; -} - -} } \ No newline at end of file diff --git a/cpp/src/compilation/pointerarithmetic.h b/cpp/src/compilation/pointerarithmetic.h deleted file mode 100644 index 14fe7f6..0000000 --- a/cpp/src/compilation/pointerarithmetic.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * File: pointerarithmetic.h - * Author: pgess - * - * Created on March 29, 2017, 11:52 AM - */ - -#ifndef POINTERARITHMETIC_H -#define POINTERARITHMETIC_H - -#include "pass/compilepass.h" - -namespace llvm { - class Value; -} - -namespace xreate { namespace pointerarithmetic { - -class PointerArithmetic { -public: - static llvm::Value* add(llvm::Value *left, llvm::Value *right, compilation::Context context, const std::string& hintVarDecl); -}; - - -} } - - -#endif /* POINTERARITHMETIC_H */ - diff --git a/cpp/src/llvmlayer.cpp b/cpp/src/llvmlayer.cpp index 2d9cce1..e031be7 100644 --- a/cpp/src/llvmlayer.cpp +++ b/cpp/src/llvmlayer.cpp @@ -1,258 +1,257 @@ #include "ast.h" #include "llvmlayer.h" #include "ExternLayer.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/MCJIT.h" #include "llvm/Support/TargetSelect.h" #include #include using namespace llvm; using namespace xreate; using namespace std; LLVMLayer::LLVMLayer(AST* root) : ast(root), builder(getGlobalContext()) { module = new llvm::Module(root->getModuleName(), llvm::getGlobalContext()); layerExtern = new ExternLayer(this); layerExtern->init(root); } void* LLVMLayer::getFunctionPointer(llvm::Function* function){ uint64_t entryAddr = jit->getFunctionAddress(function->getName().str()); return (void*) entryAddr; } void LLVMLayer::initJit(){ std::string ErrStr; LLVMInitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); llvm::EngineBuilder builder((std::unique_ptr(module))); jit = builder .setEngineKind(llvm::EngineKind::JIT) .setErrorStr(&ErrStr) .setVerifyModules(true) .create(); } void LLVMLayer::print(){ llvm::PassManager PM; PM.addPass(llvm::PrintModulePass(llvm::outs(), "banner")); PM.run(*module); } llvm::BasicBlock* LLVMLayer::initExceptionBlock(llvm::BasicBlock* blockException){ initExceptionsSupport(); PointerType* tyInt8P = PointerType::getInt8PtrTy(llvm::getGlobalContext()); Value* nullInt8P = llvm::ConstantPointerNull::get(tyInt8P); builder.SetInsertPoint(blockException); llvm::Function* fAllocate = module->getFunction("__cxa_allocate_exception"); llvm::Function* fThrow = module->getFunction("__cxa_throw"); auto exception = builder.CreateCall(fAllocate, ConstantInt::get(IntegerType::getInt64Ty(getGlobalContext()), 4)); vector throwParams{exception, nullInt8P, nullInt8P}; builder.CreateCall(fThrow, ArrayRef(throwParams)); builder.CreateUnreachable(); return blockException; } void LLVMLayer::moveToGarbage(void *o) { __garbage.push_back(o); } llvm::Type* LLVMLayer:: toLLVMType(const ExpandedType& ty) const { std::map empty; return toLLVMType(ty, empty); } llvm::Type* LLVMLayer:: toLLVMType(const ExpandedType& ty, std::map& conjuctions) const { TypeAnnotation t = ty; switch (t.__operator) { case TypeOperator::ARRAY: { assert(t.__operands.size()==1); TypeAnnotation elTy = t.__operands.at(0); return llvm::ArrayType::get(toLLVMType(ExpandedType(move(elTy)), conjuctions), t.__size); } case TypeOperator::STRUCT: - case TypeOperator::TUPLE: { assert(t.__operands.size()); std::vector pack_; pack_.reserve(t.__operands.size()); std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(pack_, pack_.end()), [this, &conjuctions](const TypeAnnotation& t){ return toLLVMType(ExpandedType(TypeAnnotation(t)), conjuctions); }); llvm::ArrayRef pack(pack_); //process recursive types: if (conjuctions.count(t.conjuctionId)) { auto result = conjuctions[t.conjuctionId]; result->setBody(pack, false); return result; } return llvm::StructType::get(llvm::getGlobalContext(), pack, false); }; case TypeOperator::LINK: { llvm::StructType* conjuction = llvm::StructType::create(llvm::getGlobalContext()); int id = t.conjuctionId; conjuctions.emplace(id, conjuction); return conjuction; }; case TypeOperator::CALL: { assert(false); }; case TypeOperator::CUSTOM: { //Look in extern types clang::QualType qt = layerExtern->lookupType(t.__valueCustom); return layerExtern->toLLVMType(qt); }; case TypeOperator::VARIANT: { int size = t.fields.size(); assert(size); int bitcount = ceil(log2(size)); return llvm::Type::getIntNTy(llvm::getGlobalContext(), bitcount); } case TypeOperator::NONE: { switch (t.__value) { case TypePrimitive::I32: case TypePrimitive::Int: case TypePrimitive::Num: return llvm::Type::getInt32Ty(llvm::getGlobalContext()); case TypePrimitive::Bool: return llvm::Type::getInt1Ty(llvm::getGlobalContext()); case TypePrimitive::I8: return llvm::Type::getInt8Ty(llvm::getGlobalContext()); case TypePrimitive::I64: return llvm::Type::getInt64Ty(llvm::getGlobalContext()); case TypePrimitive::Float: return llvm::Type::getDoubleTy(llvm::getGlobalContext()); case TypePrimitive::String: return llvm::Type::getInt8PtrTy(llvm::getGlobalContext()); default: assert(false); } } default: assert(false); } assert(false); return nullptr; } void LLVMLayer::initExceptionsSupport(){ Type* typInt8Ptr = PointerType::get(IntegerType::get(module->getContext(), 8), 0); if (!module->getFunction("__cxa_throw")) { std::vector fThrowSignature{typInt8Ptr, typInt8Ptr, typInt8Ptr}; FunctionType* tyFThrow = FunctionType::get( /*Result=*/Type::getVoidTy(module->getContext()), /*Params=*/fThrowSignature, /*isVarArg=*/false); llvm::Function::Create( /*Type=*/tyFThrow, /*Linkage=*/GlobalValue::ExternalLinkage, /*Name=*/"__cxa_throw", module); // (external, no body) } if (!module->getFunction("__cxa_allocate_exception")) { std::vectorfAllocateSignature{IntegerType::get(module->getContext(), 64)}; FunctionType* tyFAllocate = FunctionType::get( /*Result=*/typInt8Ptr, /*Params=*/fAllocateSignature, /*isVarArg=*/false); llvm::Function::Create( /*Type=*/tyFAllocate, /*Linkage=*/GlobalValue::ExternalLinkage, /*Name=*/"__cxa_allocate_exception", module); // (external, no body) } } bool TypeUtils::isStruct(const ExpandedType& ty){ const TypeAnnotation& t = ty.get(); if (t.__operator==TypeOperator::STRUCT) { return true; } if (t.__operator != TypeOperator::CUSTOM) { return false; } clang::QualType tqual = llvm->layerExtern->lookupType(t.__valueCustom); const clang::Type * raw = tqual.getTypePtr(); // TODO skip ALL the pointers until non-pointer type found if (raw->isStructureType()) return true; if (!raw->isAnyPointerType()) return false; clang::QualType pointee = raw->getPointeeType(); return pointee->isStructureType(); } bool TypeUtils::isPointer(const ExpandedType &ty) { if (ty.get().__operator != TypeOperator::CUSTOM) return false; clang::QualType qt = llvm->layerExtern->lookupType(ty.get().__valueCustom); return llvm->layerExtern->isPointer(qt); } std::vector TypeUtils::getStructFields(const ExpandedType &t) { return (t.get().__operator == TypeOperator::STRUCT) ? t.get().fields : llvm->layerExtern->getStructFields( llvm->layerExtern->lookupType(t.get().__valueCustom)); } diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp index 76425ba..b402cb2 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,770 +1,769 @@ #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/pointerarithmetic.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) namespace xreate { -llvm::Value* -doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, llvm::IRBuilder<>& builder){ - if (tyTarget->isIntegerTy() && source->getType()->isIntegerTy()) - { - llvm::IntegerType* tyTargetInt = llvm::dyn_cast(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; -} - - std::string BasicFunctionDecorator::prepareName(){ AST* ast = FunctionUnit::pass->man->root; string name = ast->getFunctionVariants(FunctionUnit::function->__name).size() > 1? FunctionUnit::function->__name + std::to_string(FunctionUnit::function.id()) : FunctionUnit::function->__name; return name; } std::vector BasicFunctionDecorator::prepareArguments(){ LLVMLayer* llvm = FunctionUnit::pass->man->llvm; AST* ast = FunctionUnit::pass->man->root; CodeScope* entry = FunctionUnit::function->__entry; std::vector signature; std::transform(entry->__bindings.begin(), entry->__bindings.end(), std::inserter(signature, signature.end()), [llvm, ast, entry](const std::string &arg)->llvm::Type* { assert(entry->__identifiers.count(arg)); ScopedSymbol argid{entry->__identifiers.at(arg), VERSION_NONE}; return llvm->toLLVMType(ast->expandType(entry->__declarations.at(argid).type)); }); return signature; } llvm::Type* BasicFunctionDecorator::prepareResult(){ LLVMLayer* llvm = FunctionUnit::pass->man->llvm; AST* ast = FunctionUnit::pass->man->root; CodeScope* entry = FunctionUnit::function->__entry; return llvm->toLLVMType(ast->expandType(entry->__declarations.at(ScopedSymbol::RetSymbol).type)); } llvm::Function::arg_iterator BasicFunctionDecorator::prepareBindings(){ CodeScope* entry = FunctionUnit::function->__entry; AbstractCodeScopeUnit* entryCompilation = FunctionUnit::getScopeUnit(entry); llvm::Function::arg_iterator fargsI = FunctionUnit::raw->arg_begin(); for (std::string &arg : entry->__bindings) { ScopedSymbol argid{entry->__identifiers[arg], VERSION_NONE}; entryCompilation->bindArg(&*fargsI, argid); fargsI->setName(arg); ++fargsI; } return fargsI; } //SECTIONTAG late-context FunctionDecorator template class 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< adhoc::AdhocFunctionDecorator< BasicFunctionDecorator>> DefaultFunctionUnit; AbstractCodeScopeUnit::AbstractCodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass) : pass(compilePass), function(f), scope(codeScope) {} llvm::Value* CallStatementRaw::operator() (std::vector&& args, const std::string& hintDecl) { llvm::Function* calleeInfo = dyn_cast(__callee); if (calleeInfo){ auto argsFormal = calleeInfo->args(); int pos=0; //SECTIONTAG types/convert function ret value for (auto argFormal = argsFormal.begin(); argFormal!=argsFormal.end(); ++argFormal, ++pos){ - args[pos] = doAutomaticTypeConversion(args[pos], argFormal->getType(), llvm->builder); + args[pos] = analysis::typeinference::doAutomaticTypeConversion(args[pos], argFormal->getType(), llvm->builder); } } return llvm->builder.CreateCall(__calleeTy, __callee, args, hintDecl); } //DESABLEDFEATURE implement inlining class CallStatementInline: public CallStatement{ public: CallStatementInline(FunctionUnit* caller, FunctionUnit* callee, LLVMLayer* l) : __caller(caller), __callee(callee), llvm(l) {} llvm::Value* operator() (std::vector&& 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; } }; BasicCodeScopeUnit::BasicCodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass) : AbstractCodeScopeUnit(codeScope, f, compilePass) {} llvm::Value* BasicCodeScopeUnit::processSymbol(const Symbol& s, std::string hintRetVar){ Expression declaration = CodeScope::getDeclaration(s); CodeScope* scope = s.scope; AbstractCodeScopeUnit* self = AbstractCodeScopeUnit::function->getScopeUnit(scope); return self->process(declaration, hintRetVar); } //SECTIONTAG late-context find callee function //TOTEST static late context decisions //TOTEST dynamic late context decisions CallStatement* BasicCodeScopeUnit::findFunction(const std::string& calleeName){ LLVMLayer* llvm = pass->man->llvm; ClaspLayer* clasp = pass->man->clasp; DefaultFunctionUnit* function = dynamic_cast(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){ llvm::Function* external = llvm->layerExtern->lookupFunction(calleeName); llvm::outs() << "Debug/External function: " << calleeName; external->getType()->print(llvm::outs(), true); llvm::outs() << "\n"; return new CallStatementRaw(external, llvm); } //no decisions required if (specializations.size()==1){ if (!specializations.front()->guardContext.isValid()) { return new CallStatementRaw( pass->getFunctionUnit(specializations.front())->compile(), llvm); } } //TODO move dictSpecialization over to a separate function in order to perform cache, etc. //prepare specializations dictionary std::map dictSpecializations; boost::optional variantDefault; boost::optional variant; for(const ManagedFnPtr& f: specializations){ const Expression& guard = f->guardContext; //default case: if (!guard.isValid()){ variantDefault = f; continue; } assert(dictSpecializations.emplace(guard, f).second && "Found several identical specializations"); } //check static context ScopePacked scopeCaller = clasp->pack(this->scope); const string atomSpecialization = "specialization"; const Expression topicSpecialization(Operator::CALL, {(Atom(string(atomSpecialization))), (Atom(string(calleeName))), (Atom(scopeCaller))}); const context::Decisions& decisions = queryContext->getFinalDecisions(scopeCaller); if (decisions.count(topicSpecialization)){ variant = dictSpecializations.at(decisions.at(topicSpecialization)); } //TODO check only demand for this particular topic. size_t sizeDemand = function->contextCompiler.getFunctionDemandSize(); //decision made if static context found or no late context exists(and there is default variant) bool flagHasStaticDecision = variant || (variantDefault && !sizeDemand); //if no late context exists if (flagHasStaticDecision) { FunctionUnit* calleeUnit = pass->getFunctionUnit(variant? *variant: *variantDefault); //inlining possible based on static decision only // if (calleeUnit->isInline()) { // return new CallStatementInline(function, calleeUnit); // } return new CallStatementRaw(calleeUnit->compile(), llvm); } //require default variant if no static decision made assert(variantDefault); llvm::Function* functionVariantDefault = this->pass->getFunctionUnit(*variantDefault)->compile(); llvm::Value* resultFn = function->contextCompiler.findFunction(calleeName, functionVariantDefault, scopeCaller); llvm::PointerType *resultPTy = cast(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){ #define DEFAULT(x) (hintVarDecl.empty()? x: hintVarDecl) llvm::Value *left; llvm::Value *right; LLVMLayer& l = *pass->man->llvm; xreate::compilation::Advanced instructions = xreate::compilation::Advanced({this, function, pass}); switch (expr.op) { - case Operator::ADD: case Operator::SUB: case Operator::MUL: + case Operator::SUB: case Operator::MUL: case Operator::DIV: case Operator::EQU: case Operator::LSS: case Operator::GTR: case Operator::NE: case Operator::LSE: case Operator::GTE: assert(expr.__state == Expression::COMPOUND); assert(expr.operands.size() == 2); left = process(expr.operands[0]); right = process(expr.operands[1]); //SECTIONTAG types/convert binary operation - right = doAutomaticTypeConversion(right, left->getType(), l.builder); + right = analysis::typeinference::doAutomaticTypeConversion(right, left->getType(), l.builder); break; default:; } switch (expr.op) { case Operator::ADD:{ - llvm::Value* resultAdd = pointerarithmetic::PointerArithmetic::add(left, right, {this, function, pass}, DEFAULT("tmp_add")); - if (resultAdd) {return resultAdd;} + left = process(expr.operands[0]); + Context context{this, function, pass}; + + llvm::Value* resultSU = StructUpdate::add(expr.operands[0], left, expr.operands[1], context, DEFAULT("tmp_add")); + if (resultSU) return resultSU; + + right = process(expr.operands[1]); + + llvm::Value* resultAddPA = pointerarithmetic::PointerArithmetic::add(left, right, context,DEFAULT("tmp_add")); + if (resultAddPA) {return resultAddPA;} return l.builder.CreateAdd(left, right, DEFAULT("tmp_add")); break; } case Operator::SUB: return l.builder.CreateSub(left, right, DEFAULT("tmp_sub")); break; case Operator::MUL: return l.builder.CreateMul(left, right, DEFAULT("tmp_mul")); break; case Operator::DIV: return l.builder.CreateSDiv(left, right, DEFAULT("tmp_div")); break; case Operator::EQU: if (left->getType()->isIntegerTy()) return l.builder.CreateICmpEQ(left, right, DEFAULT("tmp_equ")); if (left->getType()->isFloatingPointTy()) return l.builder.CreateFCmpOEQ(left, right, DEFAULT("tmp_equ")); break; case Operator::NE: return l.builder.CreateICmpNE(left, right, DEFAULT("tmp_ne")); break; case Operator::LSS: return l.builder.CreateICmpSLT(left, right, DEFAULT("tmp_lss")); break; case Operator::LSE: return l.builder.CreateICmpSLE(left, right, DEFAULT("tmp_lse")); break; case Operator::GTR: return l.builder.CreateICmpSGT(left, right, DEFAULT("tmp_gtr")); break; case Operator::GTE: return l.builder.CreateICmpSGE(left, right, DEFAULT("tmp_gte")); break; case Operator::NEG: left = process(expr.operands[0]); return l.builder.CreateNeg(left, DEFAULT("tmp_neg")); break; case Operator::CALL: { assert(expr.__state == Expression::COMPOUND); std::string nameCallee = expr.getValueString(); shared_ptr 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); } ); 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); } return (*callee)(move(args), DEFAULT("res_"+nameCallee)); } case Operator::IF: { return instructions.compileIf(expr, DEFAULT("tmp_if")); } case Operator::SWITCH: { return instructions.compileSwitch(expr, DEFAULT("tmp_switch")); } case Operator::LOOP_CONTEXT: { assert(false); return nullptr; //return instructions.compileLoopContext(expr, DEFAULT("tmp_loop")); } case Operator::LOGIC_AND: { assert(expr.operands.size() == 1); return process (expr.operands[0]); } case Operator::LIST: { return instructions.compileListAsSolidArray(expr, DEFAULT("tmp_list")); }; case Operator::LIST_RANGE: { assert(false); //no compilation phase for a range list // return InstructionList(this).compileConstantArray(expr, l, hintRetVar); }; case Operator::LIST_NAMED: { typedef Expanded ExpandedType; - ExpandedType tyRaw = l.ast->expandType(expr.type); + ExpandedType tyStructLiteral = l.ast->getType(expr); - const std::vector fields = (tyRaw.get().__operator == TypeOperator::CUSTOM)? - l.layerExtern->getStructFields(l.layerExtern->lookupType(tyRaw.get().__valueCustom)) - : tyRaw.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 = fields.size(); i(l.toLLVMType(tyRaw)); - llvm::Value* record = llvm::UndefValue::get(tyRecord); + llvm::StructType* tyLiteralRaw = llvm::cast(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); // } 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); assert(expr.operands[0].__state == Expression::IDENT); const std::string& hintIdent= expr.operands[0].getValueString(); Symbol s = Attachments::get(expr.operands[0]); - const ExpandedType& t2 = pass->man->root->expandType(CodeScope::getDeclaration(s).type); + const ExpandedType& t2 = pass->man->root->getType(expr.operands[0]); llvm::Value* aggr = processSymbol(s, hintIdent); switch (t2.get().__operator) { case TypeOperator::STRUCT: case TypeOperator::CUSTOM: { + std::string idxField; const Expression& idx = expr.operands.at(1); - assert(idx.__state == Expression::STRING); - std::string idxField = idx.getValueString(); + switch (idx.__state) { + + //named struct field + case Expression::STRING: + idxField = idx.getValueString(); + break; + + //anonymous struct field + case Expression::NUMBER: + idxField = to_string((int)idx.getValueDouble()); + break; + + default: + assert(false&& "Wrong index for a struct"); + } return instructions.compileStructIndex(aggr, t2, idxField); }; case TypeOperator::ARRAY: { std::vector indexes; std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()), [this] (const Expression& op){ return process(op); } ); return instructions.compileArrayIndex(aggr, indexes, DEFAULT(string("el_") + hintIdent)); }; default: assert(false); } }; //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); //SECTIONTAG types/convert ADHOC ret convertation llvm::Type* resultTy = l.toLLVMType( pass->man->root->expandType(function->adhocImplementation->getResultType())); - return doAutomaticTypeConversion(unitScope->compile(), resultTy, l.builder); + return analysis::typeinference::doAutomaticTypeConversion(unitScope->compile(), resultTy, l.builder); }; case Operator::CALL_INTRINSIC:{ const std::string op = expr.getValueString(); if (op == "copy") { llvm::Value* result = process(expr.getOperands().at(0)); auto decoratorVersions = Decorators::getInterface(this); llvm::Value* storage = decoratorVersions->processIntrinsicInit(result->getType()); decoratorVersions->processIntrinsicCopy(result, storage); return l.builder.CreateLoad(storage, hintVarDecl); } assert(false && "undefined intrinsic"); } case Operator::NONE: assert(expr.__state != Expression::COMPOUND); switch (expr.__state) { case Expression::IDENT: { Symbol s = Attachments::get(expr); return processSymbol(s, expr.getValueString()); } case Expression::NUMBER: { llvm::Type* typConst; if (expr.type.isValid()){ - typConst = l.toLLVMType(pass->man->root->expandType(expr.type)); + typConst = l.toLLVMType(pass->man->root->getType(expr)); } else { typConst = llvm::Type::getInt32Ty(llvm::getGlobalContext()); } int literal = expr.getValueDouble(); return llvm::ConstantInt::get(typConst, literal); } case Expression::STRING: { return instructions.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str")); }; case Expression::VARIANT: { - const ExpandedType& typVariant = pass->man->root->expandType(expr.type); + const ExpandedType& typVariant = pass->man->root->getType(expr); llvm::Type* typRaw = l.toLLVMType(typVariant); int value = expr.getValueDouble(); return llvm::ConstantInt::get(typRaw, value); } default: { break; } }; break; default: break; } assert(false); return 0; } llvm::Value* BasicCodeScopeUnit::compile(const std::string& hintBlockDecl){ if (!hintBlockDecl.empty()) { llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm::getGlobalContext(), hintBlockDecl, function->raw); pass->man->llvm->builder.SetInsertPoint(block); } Symbol symbScope = Symbol{ScopedSymbol::RetSymbol, scope}; return processSymbol(symbScope); } AbstractCodeScopeUnit::~AbstractCodeScopeUnit() {} FunctionUnit::~FunctionUnit() {} llvm::Function* FunctionUnit::compile(){ if (raw != nullptr) return raw; LLVMLayer* llvm = pass->man->llvm; llvm::IRBuilder<>& builder = llvm->builder; string&& functionName = prepareName(); std::vector&& types = prepareArguments(); llvm::Type* expectedResultType = prepareResult(); llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false); raw = llvm::cast(llvm->module->getOrInsertFunction(functionName, ft)); prepareBindings(); const std::string&blockName = "entry"; llvm::BasicBlock* blockCurrent = builder.GetInsertBlock(); llvm::Value* result =getScopeUnit(function->__entry)->compile(blockName); assert(result); //SECTIONTAG types/convert function ret value - builder.CreateRet(doAutomaticTypeConversion(result, expectedResultType, llvm->builder)); + builder.CreateRet(analysis::typeinference::doAutomaticTypeConversion(result, expectedResultType, llvm->builder)); if (blockCurrent){ builder.SetInsertPoint(blockCurrent); } llvm->moveToGarbage(ft); return raw; } AbstractCodeScopeUnit* FunctionUnit::getScopeUnit(CodeScope* scope){ if (__scopes.count(scope)) { auto result = __scopes.at(scope).lock(); if (result){ return result.get(); } } std::shared_ptr unit(new DefaultScopeUnit(scope, this, pass)); if (scope->__parent != nullptr){ auto parentUnit = Decorators::getInterface(getScopeUnit(scope->__parent)); parentUnit->registerChildScope(unit); } else { __orphanedScopes.push_back(unit); } if (!__scopes.emplace(scope, unit).second){ __scopes[scope] = unit; } return unit.get(); } AbstractCodeScopeUnit* FunctionUnit::getScopeUnit(ManagedScpPtr scope){ return getScopeUnit(&*scope); } AbstractCodeScopeUnit* FunctionUnit::getEntry(){ return getScopeUnit(function->getEntryScope()); } FunctionUnit* CompilePass::getFunctionUnit(const ManagedFnPtr& function){ unsigned int id = function.id(); if (!functions.count(id)){ FunctionUnit* unit = new DefaultFunctionUnit(function, this); functions.emplace(id, unit); return unit; } return functions.at(id); } void CompilePass::run(){ managerTransformations = new TransformationsManager(); targetInterpretation = new 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)); entry = unitMain->compile(); } llvm::Function* CompilePass::getEntryFunction(){ assert(entry); return entry; } void CompilePass::prepareQueries(ClaspLayer* clasp){ clasp->registerQuery(new containers::Query(), QueryId::ContainersQuery); clasp->registerQuery(new context::ContextQuery(), QueryId::ContextQuery); } } //end of namespace xreate diff --git a/cpp/tests/compilation.cpp b/cpp/tests/compilation.cpp index 8c00e14..18b8705 100644 --- a/cpp/tests/compilation.cpp +++ b/cpp/tests/compilation.cpp @@ -1,37 +1,95 @@ #include "xreatemanager.h" #include "gtest/gtest.h" using namespace xreate; //DEBT implement no pkgconfig ways to link libs //TOTEST FunctionUnit::compileInline TEST(Compilation, DISABLED_functionInline1){ } TEST(Compilation, functionEntry1){ std::unique_ptr program(XreateManager::prepare( "func1 = function(a:: int):: int {a+8} \ func2 = function::int; entry {12 + func1(4)} \ ")); void* entryPtr = program->run(); int (*entry)() = (int (*)())(intptr_t)entryPtr; int answer = entry(); ASSERT_EQ(24, answer); } TEST(Compilation, full_IFStatementWithVariantType){ XreateManager* man = XreateManager::prepare( "Color = type variant (RED, BLUE, GREEN).\n" "\n" " main = function(x::int):: bool; entry {\n" " color = if (x == 0 )::Color {RED} else {BLUE}.\n" " if (color == BLUE)::bool {true} else {false}\n" " }" ); bool (*main)(int) = (bool (*)(int)) man->run(); ASSERT_FALSE(main(0)); ASSERT_TRUE(main(1)); } +TEST(Compilation, full_StructUpdate){ + XreateManager* man = XreateManager::prepare( + R"Code( + + Rec = type alias { + a :: int, + b:: int + }. + + test= function:: int; entry { + a = {a = 18, b = 20}:: Rec. + + b = a + {a = 11}:: Rec. + b["a"] + } + )Code"); + + int (*main)() = (int (*)()) man->run(); + int result = main(); + + ASSERT_EQ(11, result); +} + +TEST(Compilation, AnonymousStruct_init_index){ + std::string code = +R"Code( + + main = function:: int; entry { + x = {10, 15} :: {int, int}. + x[1] + } + +)Code"; + + std::unique_ptr man(XreateManager::prepare(move(code))); + int (*main)() = (int (*)()) man->run(); + + EXPECT_EQ(15, main()); +} + +TEST(Compilation, AnonymousStruct_init_update){ + std::string code = +R"Code( + + main = function:: int; entry { + x = {10, 15} :: {int, int}. + y = x + {6}:: {int, int}. + y[0] + } + +)Code"; + + std::unique_ptr man(XreateManager::prepare(move(code))); + int (*main)() = (int (*)()) man->run(); + + EXPECT_EQ(6, main()); +} + diff --git a/cpp/tests/externc.cpp b/cpp/tests/externc.cpp index c9486e9..97799f8 100644 --- a/cpp/tests/externc.cpp +++ b/cpp/tests/externc.cpp @@ -1,107 +1,106 @@ #include "gtest/gtest.h" #include "xreatemanager.h" #include "main/Scanner.h" #include "main/Parser.h" #include #include using namespace std; using namespace xreate; TEST(InterfaceExternC, testAST) { std::string code = " \ interface(extern-c){ \ xml2 = library:: pkgconfig(\"libxml-2.0\"). \ \ include { \ xml2 = [\"libxml/tree.h\"] \ }. \ } \ "; xreate::grammar::main::Scanner scanner(reinterpret_cast (code.c_str()), code.size()); xreate::grammar::main::Parser parser(&scanner); parser.Parse(); ASSERT_EQ(1, parser.root->__externdata.size()); for (const ExternEntry& lib : parser.root->__externdata) { ASSERT_EQ("libxml-2.0", lib.package); ASSERT_EQ(1, lib.headers.size()); ASSERT_EQ("libxml/tree.h", lib.headers.at(0)); } } TEST(InterfaceExternC, testfetchPackageHeaders) { ExternEntry entry{"libxml-2.0", {}}; vector args = ExternLayer::fetchPackageFlags(entry); ASSERT_EQ(1, args.size()); ASSERT_EQ("-I/usr/include/libxml2", args.at(0)); } TEST(InterfaceExternC, testfetchPackageLibs) { ExternEntry entry{"libxml-2.0", {}}; vector args = ExternLayer::fetchPackageLibs(entry); ASSERT_EQ(1, args.size()); ASSERT_EQ("xml2", args.at(0)); } TEST(InterfaceExternC, testLoadLib) { std::string msgErr; if (!llvm::sys::DynamicLibrary::LoadLibraryPermanently("-lpcre -lxml2", &msgErr)) { cout << msgErr; ASSERT_EQ("", msgErr); } ASSERT_TRUE(true); } TEST(InterfaceExternC, testBSD1) { std::string code = " \n\ interface(extern-c){ \n\ libbsd = library:: pkgconfig(\"libbsd\"). \n\ \n\ include { \n\ libbsd = [\"bsd/stdlib.h\"] \n\ }. \n\ } \n" "main= function:: int; entry{arc4random_uniform(24) }"; std::unique_ptr program(XreateManager::prepare(move(code))); void* entryPtr = program->run(); int (*entry)() = (int (*)())(intptr_t) entryPtr; int answer = 24; answer = entry(); cout << answer; ASSERT_LT(answer, 24); } TEST(InterfaceExternC, testStructFields1) { FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate", "r"); assert(input != nullptr); xreate::grammar::main::Scanner scanner(input); xreate::grammar::main::Parser parser(&scanner); parser.Parse(); AST* ast = parser.root->finalize(); CodeScope* body = ast->findFunction("test")->getEntryScope(); - const TypeAnnotation& tTree = body->getDeclaration(body->getSymbol("tree")).type; - const ExpandedType& t2Tree = ast->expandType(tTree); + const ExpandedType& t2Tree = ast->getType(body->getDeclaration(body->getSymbol("tree"))); LLVMLayer llvm(ast); TypeUtils utils(&llvm); std::vectorfields = utils.getStructFields(t2Tree); auto field = std::find(fields.begin(), fields.end(), "children"); ASSERT_TRUE(field != fields.end()); } diff --git a/cpp/tests/types.cpp b/cpp/tests/types.cpp index ababa6e..1287263 100644 --- a/cpp/tests/types.cpp +++ b/cpp/tests/types.cpp @@ -1,165 +1,165 @@ /* * types.cpp * * Created on: Jun 4, 2015 * Author: pgess */ #include "gtest/gtest.h" #include "xreatemanager.h" #include "llvmlayer.h" #include "main/Parser.h" using namespace std; using namespace xreate; using namespace xreate::grammar::main; TEST(Types, DependantTypes1) { string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n"; std::unique_ptr program(XreateManager::prepare(move(code))); ExpandedType typeXmlNode = program->root->findType("XmlNode"); ASSERT_EQ(TypeOperator::STRUCT, typeXmlNode->__operator); ASSERT_EQ(2, typeXmlNode->__operands.size()); ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(0).__value); ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(1).__value); } -TEST(Types, DependantTypes2) { +TEST(Types, DependantTypes_FeatureTypeIndex_2) { string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n" "" - "Template = type Template(Leaf) [Leaf, [Leaf[content]]]." + "Template = type Template(Leaf) {Leaf, [Leaf[content]]}." "Concrete = type alias Template(XmlNode)."; std::unique_ptr program(XreateManager::prepare(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); - ASSERT_EQ(TypeOperator::TUPLE, typeConcrete->__operator); + ASSERT_EQ(TypeOperator::STRUCT, typeConcrete->__operator); ASSERT_EQ(2, typeConcrete->__operands.size()); ASSERT_EQ(TypeOperator::STRUCT, typeConcrete->__operands.at(0).__operator); ASSERT_EQ(TypeOperator::ARRAY, typeConcrete->__operands.at(1).__operator); ASSERT_EQ(TypePrimitive::String, typeConcrete->__operands.at(1).__operands.at(0).__value); } TEST(Types, TreeType1) { string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n" "" - "Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]." + "Tree = type Tree(Leaf) {Leaf, [Tree(Leaf)]}." "Concrete = type alias Tree(XmlNode)."; std::unique_ptr program(XreateManager::prepare(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); - ASSERT_EQ(TypeOperator::TUPLE, typeConcrete->__operator); + ASSERT_EQ(TypeOperator::STRUCT, typeConcrete->__operator); ASSERT_EQ(2, typeConcrete->__operands.size()); ASSERT_EQ(TypeOperator::STRUCT, typeConcrete->__operands.at(0).__operator); ASSERT_EQ(TypeOperator::ARRAY, typeConcrete->__operands.at(1).__operator); auto typeLink = typeConcrete->__operands.at(1).__operands.at(0); ASSERT_EQ(TypeOperator::LINK, typeLink.__operator); ASSERT_EQ(typeConcrete->conjuctionId,typeLink.conjuctionId); } TEST(Types, TreeType1LLvm){ string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n" "" - "Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]." + "Tree = type Tree(Leaf) {Leaf, [Tree(Leaf)]}." "Concrete = type alias Tree(XmlNode)."; std::unique_ptr program(XreateManager::prepare(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); llvm::Type* raw = program->llvm->toLLVMType(typeConcrete); } TEST(Types, ArrayOfExternal1){ FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST* ast = parser.root->finalize(); CodeScope* body = ast->findFunction("test")->getEntryScope(); - const TypeAnnotation& t = body->getDeclaration(body->getSymbol("childrenRaw")).type; - const ExpandedType& t2 = ast->expandType(t); + const ExpandedType& t2 = ast->getType(body->getDeclaration(body->getSymbol("childrenRaw"))); EXPECT_EQ(t2->__operator, TypeOperator::ARRAY); } TEST(Types, ExternType1){ FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST* ast = parser.root->finalize(); CodeScope* body = ast->findFunction("test")->getEntryScope(); - const TypeAnnotation& t = body->getDeclaration(body->getSymbol("tree")).type; - const ExpandedType& t2 = ast->expandType(t); + const ExpandedType& t2 = ast->getType(body->getDeclaration(body->getSymbol("tree"))); EXPECT_EQ(t2->__operator, TypeOperator::CUSTOM); } TEST(Types, ast_VariantType1){ string&& code = " colors = type variant (RED, BLUE, GREEN).\n" " test = function:: colors; entry {GREEN}"; std::unique_ptr program(XreateManager::prepare(move(code))); ExpandedType typ = program->root->findType("colors"); EXPECT_EQ(TypeOperator::VARIANT, typ->__operator); Expression eRed = program->root->findFunction("test")->getEntryScope()->getBody(); EXPECT_EQ(Expression::VARIANT, eRed.__state); - const ExpandedType& typ2 = program->root->expandType(eRed.type); + const ExpandedType& typ2 = program->root->getType(eRed); EXPECT_EQ(TypeOperator::VARIANT, typ2->__operator); program->run(); } TEST(Types, full_VariantType_Switch1){ string&& code = " colors = type variant (RED, BLUE, GREEN). \n" " test = function:: colors {GREEN} \n" "main = function:: int; entry { \n" " switch(test()):: int \n" " case (GREEN) {0} \n" " case default {1} \n" "}"; XreateManager* man = XreateManager::prepare(move(code)); int (*main)() = (int (*)()) man->run(); EXPECT_EQ(0, main()); } +//TEST(Types, A) + //TOTEST string type diff --git a/grammar/xreate.ATG b/grammar/xreate.ATG index f57d3e4..932c766 100644 --- a/grammar/xreate.ATG +++ b/grammar/xreate.ATG @@ -1,606 +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()); .) ) 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}); .) - {',' Type (. typ.__operator = TypeOperator::TUPLE; typ.__operands.push_back(ty); .) - }']' - . - -TStruct = (. TypeAnnotation t; std::wstring field; .) +TList = (. TypeAnnotation ty; .) + '[' Type ']' (. typ = TypeAnnotation(TypeOperator::ARRAY, {ty}); .) +. + +TStruct = (. TypeAnnotation t; std::wstring key; size_t keyCounter=0; .) lcurbrack - Ident tagcolon Type (. typ = TypeAnnotation(TypeOperator::STRUCT, {t}); typ.fields.push_back(Atom(field).get()); .) - {',' Ident tagcolon Type} (. typ.__operands.push_back(t); typ.fields.push_back(Atom(field).get()); .) - rcurbrack. + ( + 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)); .) . //TODO forbid multiple body declaration (ExprTyped) BDecl = lcurbrack (. Expression body; pushContextScope(scope); .) {(IF(checkAssignment()) VDecl '.' | RuleContextDecl | ContextDecl'.' | ExprTyped (. scope->setBody(body); .) )} (. popContextScope(); .) rcurbrack . 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)); .) ). 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)); .) | '-' Term (. e = Expression(Operator::NEG, {e}); .) | '(' ExprTyped ')' ). -StructLiteral = (. std::wstring key; Expression val; std::list> keys; .) - '{' Ident '=' Expr (. keys.push_back(Atom(key)); e = Expression(Operator::LIST_NAMED, {val}); .) - {',' Ident '=' Expr (.e.addArg(Expression(val)); keys.push_back(Atom(key)); .) - } '}' (. e.addBindings(keys.begin(), keys.end()); .) +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. diff --git a/problems/basket/cond.lp b/problems/basket/cond.lp deleted file mode 100644 index 9f98097..0000000 --- a/problems/basket/cond.lp +++ /dev/null @@ -1,6 +0,0 @@ -person(jane). person(john). -day(mon). day(tue). day(wed). day(thu). day(fri). -available(jane) :- not on(fri). -available(john) :- not on(mon), not on(wed). -meet :- available(X) : person(X). -on(X) : day(X) :- meet. diff --git a/problems/basket/containers.lp b/problems/basket/containers.lp deleted file mode 100644 index 6243fe6..0000000 --- a/problems/basket/containers.lp +++ /dev/null @@ -1,54 +0,0 @@ - -implementation(hashlist). implementation(linkedlist). implementation(treelist). -operation(at). operation(sort). operation(insert). -relation (recommends). relation (satisfied). relation(unsupported). - -relation_score(satisfied, 0). -relation_score(recommends, 1). -relation_score(unsupported, -1). - -relation_op(at, hashlist, recommends). relation_op(at,treelist, satisfied). -relation_op(sort, linkedlist, satisfied). relation_op(sort, treelist, satisfied). relation_op(sort, hashlist, unsupported). - - -impl_fulfill(OP, IMPL, SCORE):- relation_op(OP, IMPL, RL), relation_score(RL, SCORE), operation(OP), implementation(IMPL), RL!=unsupported. -impl_not_fulfill(OP, IMPL):- relation_op(OP, IMPL, unsupported). - - -%static analysis: -var(a).var(b). -bind_var_op(a, at). -bind_var_op(a, sort). -bind_var_op(b, insert). -var_connection(a, b). - -%* var_connection(VAR_FROM, VAR_TO, connection_type) *% -%* var_cluster(VAR_FROM, VAR_TO) *% - -connection_type(ct_inherits). connection_type(ct_convert). - -var_connection(VAR_FROM, VAR_TO, CT):connection_type(CT) :- var_connection(VAR_FROM, VAR_TO). - -var_cluster_root(VAR) :- {var_connection(VAR_F, VAR, ct_inherits): var(VAR_F)} 0, var(VAR). -var_cluster(VAR0, VAR_TO) :- var_connection(VAR0, VAR_TO, ct_inherits), var_cluster_root(VAR0). -var_cluster(VAR0, VAR_TO2) :- var_connection(VAR_TO1, VAR_TO2, ct_inherits), var_cluster(VAR0, VAR_TO1). -var_cluster(VAR0, VAR0):- var_cluster_root(VAR0). - - -#domain implementation(IMPL). -%#domain var(VAR). - -impl_fulfill_cluster(VAR0, OP, IMPL, SCORE) :- var_cluster(VAR0, VAR_ANY), bind_var_op(VAR_ANY, OP), impl_fulfill(OP, IMPL, SCORE), var_cluster_root(VAR0). -impl_not_fulfill_cluster(VAR0, IMPL):-var_cluster(VAR0, VAR_ANY), bind_var_op(VAR_ANY, OP), impl_not_fulfill(OP, IMPL), var_cluster_root(VAR0). -%bind_cluster_op(VAR0, OP) :- bind_var_op(VAR0, OP). -bind_var_impl(VAR0, IMPL, SCORE_RESULT) :- SCORE_RESULT = #sum[impl_fulfill_cluster(VAR0, _, IMPL, SCORE) = SCORE], {impl_not_fulfill_cluster(VAR0, IMPL)}0, var_cluster_root(VAR0). -%:- bind_var_impl(VAR0, IMPL, _), var_cluster(VAR0, VAR_ANY), bind_var_op(VAR_ANY, OP), impl_not_fulfill(OP, IMPL). - -%impl_fulfill(OP, IMPL, SCORE) : bind_var_op(VAR, OP), var(VAR), SCORE_RESULT = 0 , relation_score(_, SCORE). -%%* *% - -#hide. -#show bind_var_impl/3. -#show var_cluster_owner/1. -#show var_connection/3. -#show bind_var_op/2. diff --git a/problems/basket/dependencies.lp b/problems/basket/dependencies.lp deleted file mode 100644 index abbe0c4..0000000 --- a/problems/basket/dependencies.lp +++ /dev/null @@ -1,8 +0,0 @@ -node(a; b; c; d). -depends(b,a). -depends(c,a). -depends(d, a). -depends(d, c). - -level(X, 0) :- not depends(X, _); node(X). -level(X, LEVEL):- LEVEL = #max{L+1, level(Y, L): level(Y, L), depends(X, Y)}; node(X); LEVEL > 0. diff --git a/problems/basket/example-computations.lp b/problems/basket/example-computations.lp deleted file mode 100644 index 4cdd8a3..0000000 --- a/problems/basket/example-computations.lp +++ /dev/null @@ -1,49 +0,0 @@ -%defines: - implementation(hashlist). implementation(linkedlist). implementation(treelist). implementation(computation). - operation(at). operation(sort). operation(insert). operation(seqaccess). - connection_type(ct_inherits). connection_type(ct_convert). - - relation (recommends). relation (satisfied). relation(unsupported). - relation_score(satisfied, 0). - relation_score(recommends, 1). - relation_score(unsupported, -1). - -%integration facts: - relation_op(seqaccess, computation, recommends). - relation_op(at, hashlist, recommends). relation_op(at,treelist, satisfied). - relation_op(sort, linkedlist, satisfied). relation_op(sort, treelist, satisfied). relation_op(sort, hashlist, unsupported). - - - -%static analysis: - var(a).var(tmp2). var(b). var(tmp3). - - var_connection(a, tmp2). - bind_var_op(tmp2, seqaccess). - var_connection(tmp2, b, ct_inherits). - var_connection(b, tmp3). - bind_var_op(tmp3, seqaccess). - -%domain rules: - impl_fulfill(OP, IMPL, SCORE):- relation_op(OP, IMPL, RL), relation_score(RL, SCORE), operation(OP), implementation(IMPL), RL!=unsupported. - impl_not_fulfill(OP, IMPL):- relation_op(OP, IMPL, unsupported). - -%reasoning rules: - { var_connection(VAR_FROM, VAR_TO, CT):connection_type(CT) }1 :- var_connection(VAR_FROM, VAR_TO). - - var_cluster_root(VAR) :- {var_connection(VAR_F, VAR, ct_inherits): var(VAR_F)} 0, var(VAR). - var_cluster(VAR0, VAR_TO) :- var_connection(VAR0, VAR_TO, ct_inherits), var_cluster_root(VAR0). - var_cluster(VAR0, VAR_TO2) :- var_connection(VAR_TO1, VAR_TO2, ct_inherits), var_cluster(VAR0, VAR_TO1). - var_cluster(VAR0, VAR0):- var_cluster_root(VAR0). - - impl_fulfill_cluster(VAR0, OP, IMPL, SCORE) :- var_cluster(VAR0, VAR_ANY), bind_var_op(VAR_ANY, OP), impl_fulfill(OP, IMPL, SCORE), var_cluster_root(VAR0). - impl_not_fulfill_cluster(VAR0, IMPL):-var_cluster(VAR0, VAR_ANY), bind_var_op(VAR_ANY, OP), impl_not_fulfill(OP, IMPL), var_cluster_root(VAR0). - bind_var_impl(VAR0, IMPL, SCORE_RESULT) :- SCORE_RESULT = #sum[impl_fulfill_cluster(VAR0, _, IMPL, SCORE) = SCORE], {impl_not_fulfill_cluster(VAR0, IMPL)}0, var_cluster_root(VAR0), implementation(IMPL). - -%pretty output: - #hide. - #show chosen_impl/2. - #show bind_var_impl/3. - #show var_cluster_owner/1. - #show var_connection/3. - #show bind_var_op/2. diff --git a/problems/basket/example-computations2.lp b/problems/basket/example-computations2.lp deleted file mode 100644 index 7a54272..0000000 --- a/problems/basket/example-computations2.lp +++ /dev/null @@ -1,55 +0,0 @@ -%defines: - implementation(hashlist). implementation(linkedlist). implementation(treelist). implementation(computation). - operation(at). operation(sort). operation(insert). operation(seqaccess). - connection_type(ct_inherits). connection_type(ct_convert). - - relation (recommends). relation (satisfied). relation(unsupported). - relation_score(satisfied, 0). - relation_score(recommends, 1). - relation_score(unsupported, -1). - -%integration facts: - relation_op(seqaccess, computation, recommends). relation_op(seqaccess, hashlist, unsupported). - relation_op(at, hashlist, recommends). relation_op(at,treelist, satisfied). - relation_op(sort, linkedlist, satisfied). relation_op(sort, treelist, satisfied). relation_op(sort, hashlist, unsupported). - - - -%static analysis: - var(a).var(tmp2). var(b). var(tmp3). var(tmp4). - - var_connection(a, tmp2). - bind_var_op(tmp2, seqaccess). - var_connection(tmp2, b). - var_connection(tmp2, b, ct_inherits). - var_connection(b, tmp3). - bind_var_op(tmp3, seqaccess). - bind_var_op(tmp4, sort). - -%domain rules: - impl_fulfill(OP, IMPL, SCORE):- relation_op(OP, IMPL, RL), relation_score(RL, SCORE), operation(OP), implementation(IMPL), RL!=unsupported. - impl_not_fulfill(OP, IMPL):- relation_op(OP, IMPL, unsupported). - impl_avail(VAR, IMPL) :- not impl_not_fulfill(OP, IMPL) : bind_var_op(VAR, OP), var(VAR), implementation(IMPL). - -%reasoning rules: - 1{setup_impl(VAR, IMPL) : implementation(IMPL) }1 :- var(VAR). - :- setup_impl(VAR, IMPL), not impl_avail(VAR, IMPL). - - var_connection(VAR1, VAR2, ct_convert) :- var(VAR1), var(VAR2), var_connection(VAR1, VAR2), setup_impl(VAR1, IMPL1), setup_impl(VAR2, IMPL2), IMPL1 != IMPL2. - :- var(VAR1), var(VAE2), 2{var_connection(VAR1, VAR2, _)} . - - setup_var_impl_fulfill(VAR, SCORE) :- SCORE := #min[impl_fulfill(OP, IMPL, RATE): bind_var_op(VAR, OP) = RATE], var(VAR). - - model_score_convert(SCORE) :- SCORE := #count{var_connection(VAR1, VAR2, ct_convert): var(VAR1) : var(VAR2)}. - model_score_impl(SCORE) :- SCORE:= [setup_var_fulfill(VAR, RATE): var(VAR) = RATE]. - -%pretty output: - #hide. - #show setup_impl/2. - #show model_score/1. - #show setup_var_impl_fulfill/2. - %#show var_connection/3. - %#show bind_var_impl/3. - %#show var_cluster_owner/1. - %#show var_connection/3. - %#show bind_var_op/2. diff --git a/problems/basket/gte.lp b/problems/basket/gte.lp deleted file mode 100644 index a9d9588..0000000 --- a/problems/basket/gte.lp +++ /dev/null @@ -1,3 +0,0 @@ -fact(a). fact(b). fact(8). a<10. - -gezero(X) :- X>=11, fact(X). diff --git a/problems/basket/kitchen.lp b/problems/basket/kitchen.lp deleted file mode 100644 index f9f0fc9..0000000 --- a/problems/basket/kitchen.lp +++ /dev/null @@ -1,13 +0,0 @@ -room(bedroom; diningroom; kitchen). - -%location(bedroom). -door(bedroom, diningroom). -door(diningroom, kitchen). - -{move(A, B)} :- location(A); door(A, B); room(A); room(B). -{move(A, B)} :- move(_, A); door(A, B); room(A); room(B). - -goal:- location(kitchen). -goal:- move(_, kitchen). - -:- not goal. diff --git a/problems/basket/test-list.lp b/problems/basket/test-list.lp deleted file mode 100644 index 6063a16..0000000 --- a/problems/basket/test-list.lp +++ /dev/null @@ -1,7 +0,0 @@ -% WORKING WITH TUPLES POSSIBILITY TESTING - -eqq(x, (0, 0)). -eqq(y, (1, 1)). -iszerosum(X, Y) :- X1 == Y1, X2 == Y2, eqq(X, (X1, X2)), eqq(Y, (Y1, Y2)). - -%plus(X, Y) :- eq(X, (ax, ay)), eq(Y, (bx, by)), ax + ay + bx + by. \ No newline at end of file diff --git a/problems/basket/test.lp b/problems/basket/test.lp deleted file mode 100644 index 8c8a729..0000000 --- a/problems/basket/test.lp +++ /dev/null @@ -1,12 +0,0 @@ -% p(1..3). q(2..4). -% { r(X): p(X), r(X): q(X) }. -% s :- #sum { r(X)=X: p(X): q(X) } 1. - -%p(1..50). -%count(X, Y):- Y = #sum {Z, Z: p(Z), Z >= X}, p(X). - -p(1..3). -2 {q(X) : p(X)}. -q(2). -:- not q(3). -:~ p(X), not q(X).[X] \ No newline at end of file diff --git a/problems/basket/timetable-tests.lp b/problems/basket/timetable-tests.lp deleted file mode 100644 index 32dcea6..0000000 --- a/problems/basket/timetable-tests.lp +++ /dev/null @@ -1,54 +0,0 @@ -man(brian; joe; chris; bob). -professor(brian; joe). -phd(chris). -asisstant(bob). - -lesson(1..10). -day(1..5). -week(even; odd). - -course(a;b;c;d;e;f;j;h;k;l;m;n). - -time(a, 10). -time(b, 12). -time(c, 20). -time(d, 3). -time(e, 17). -time(f, 15). -time(j, 9). -time(h, 7). -time(k, 11). -time(l, 14). -time(m, 8). -time(n, 17). - -room(402; 403; 404). - -course_room(a, 402). -course_room(c, 404). -course_room(d, 403). -course_room(d, 404). - -% ---- timetable(Teacher, Course, Lesson, Room, Day, Week) - - - - timetable(brian, a, 1, 402, 1, even). - timetable(brian, a, 3, 402, 1, even). - timetable(brian, a, 4, 402, 1, even). - - owl(joe) % no first lesson - :- owl(T); timetable(T, _, 1,_, _, _). - -earlybird(bob). -earlybird_score(T, Score) :- Score = #count {timetable(T, C, 1, R, D, W): course(C), room(R), day(D), week(W)}; earlybird(T) . -earlybird_score(Score) :- Score = #sum{Score2, 1: earlybird_score(T, Score2)}. -:- earlybird_score(X); X<2. - - -courseDuration(C, Span) :- Span = #count{(T, C, L, R, D, W):timetable(T, C, L, R, D, W), man(T), room(R), day(D), week(W), lesson(L)};course(C). - - - - -#show courseDuration/2. \ No newline at end of file diff --git a/problems/basket/timetable.lp b/problems/basket/timetable.lp deleted file mode 100644 index 7b0b924..0000000 --- a/problems/basket/timetable.lp +++ /dev/null @@ -1,73 +0,0 @@ -man(brian; joe; chris; bob). -professor(brian; joe). -phd(chris). -asisstant(bob). - -lesson(1..10). -day(1..5). -week(even; odd). - -course(a;b;c;d;e;f;j;h;k;l;m;n). - -time(a, 10). -time(b, 12). -time(c, 20). -time(d, 3). -time(e, 17). -time(f, 15). -time(j, 9). -time(h, 7). -time(k, 11). -time(l, 14). -time(m, 8). -time(n, 17). - -room(402; 403; 404). - -course_room(a, 402). -course_room(c, 404). -course_room(d, 403). -course_room(d, 404). - -% ---- timetable(Teacher, Course, Lesson, Room, Day, Week) - - {timetable(T, C, L, R, D, W) : lesson(L), room(R), course_assignment(T, C)} 4 :- man(T) ; day(D); week(W) . - :- timetable(T, C1, L, _, D, W); timetable(T, C2, L, _, D, W); C1 != C2. - :- timetable(T, _, L, R1, D, W); timetable(T, _, L, R2, D, W); R1 != R2. - :- timetable(T1, _, L, R, D, W); timetable(T2, _, L, R, D, W); T1 != T2. - - courseDuration(C, Span) :- Span = #count{(T, C, L, R, D, W):timetable(T, C, L, R, D, W), man(T), room(R), day(D), week(W), lesson(L)};course(C). - :- courseDuration(C, Dur); time(C, Time); Dur > Time + 10; course(C). - :- courseDuration(C, Dur); time(C, Time); Dur < Time - 10; course(C). - - %COURSE ASSIGNMENT -1{course_assignment(T, C): man(T)}1 :- course(C). - - % FIRST LESSONS ATTENDANCE, EARLY BIRDS, OWLS -owl(joe) % no first lesson -:- owl(T); timetable(T, _, 1,_, _, _). - -earlybird(bob). -earlybird_score(T, Score) :- Score = #count {timetable(T, C, 1, R, D, W): course(C), room(R), day(D), week(W)}; earlybird(T) . -earlybird_score(Score) :- Score = #sum{Score2, 1: earlybird_score(T, Score2)}. - - % CONSEQUENT LESSONS REQUIREMENTS -noholes(brian; joe). % consequent lessons -maxlesson(T, D, W, Max) :- Max = #max{L, 1: timetable(T, C, L, R, D, W), course(C), lesson(L), room(R)};day(D); week(W); noholes(T); timetable(T,_,_,_,D,W). -minlesson(T, D, W, Min) :- Min = #min{L, 1:timetable(T, C, L, R, D, W), course(C), lesson(L), room(R)};day(D); week(W); noholes(T);timetable(T,_,_,_,D,W). -numlessons(T, D, W, Nu) :- Nu = #count{L:timetable(T, C, L, R, D, W), course(C), lesson(L), room(R)};day(D); week(W); noholes(T);timetable(T,_,_,_,D,W). -noholes_score_neg(T, D, W, Score) :- Score = (1 + M1 - M2 - Num); maxlesson(T, D, W, M1); minlesson(T, D, W, M2); numlessons(T, D, W, Num); day(D); week(W); noholes(T). - - %ATTENDANCE -%scheme: attends(Man, Day, Week). -attends(chris, 1, even). % days he can attend -%:-timetable(T, _, _, _, D, W); not attends(T, D, W). - - -%spike(brian; bob). %spike load all in one day -%steady(chris). % load the same in all days - - -%order(e, k). -%order(a, n). -#show timetable/6. \ No newline at end of file diff --git a/problems/code-bugs.lp b/problems/code-bugs.lp deleted file mode 100644 index a90de4f..0000000 --- a/problems/code-bugs.lp +++ /dev/null @@ -1,12 +0,0 @@ -tag(fun1, bug(1)). -tag(fun2, bug(2)). - - -call(fun1, fun2). - - -warning(X, Y, no):- call(X, Y), tag(Y, bug(Z)), not tag(X, bug(Z)), no=Z. -%:- call(X, Y), tag(Y, bug(Z)), not tag(X, bug(Z)). - - -%#show warning/3. \ No newline at end of file diff --git a/problems/code-containers-impl.lp b/problems/code-containers-impl.lp deleted file mode 100644 index fb5941d..0000000 --- a/problems/code-containers-impl.lp +++ /dev/null @@ -1,50 +0,0 @@ -%defines - impl(llvm_array; llvm_const_array; on_the_fly). - op(seqaccess). op(randaccess). - - relation(recommends; satisfied; unsupported). - relation_score(satisfied, 0). - relation_score(recommends, 1). - relation_score(unsupported, -1). - score(-1..1). - -%domain facts: - relation_op(seqaccess, on_the_fly, recommends). - relation_op(randaccess, llvm_const_array, recommends). - relation_op(randaccess, on_the_fly, unsupported). - -%dfa analysis: - dfa_connection((5,0),(4,0),strong). - v((5,0)). %c c = b : [num]; - v((3,0)). %a2 a2 = [1 .. 100] : [num]; - v((4,0)). %b b = loop map (a1 -> el: num) : [num] - v((2,0)). %a1 a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] : [num]; - -%compilation: - bind((5,0), op(randaccess)). - bind((4,0),impl(llvm_array)). - bind((3,0),impl(on_the_fly)). - bind((3,0),op(seqaccess)). - bind((2,0),op(seqaccess)). - bind((2,0),impl(llvm_const_array)). - -%domain rules: - -impl_fulfill(OP, IMPL) :- relation_op(OP, IMPL, unsupported). - impl_fulfill(OP, IMPL, SCORE):- SCORE = #sum{SCORE1, (OP, IMPL, RL): relation_op(OP, IMPL, RL),relation_score(RL, SCORE1)} - ; op(OP); impl(IMPL); not -impl_fulfill(OP, IMPL). - - cluster_root(VAR) :- not dfa_connection(VAR, _, strong), v(VAR). - var_cluster(VAR0, VAR_TO) :- dfa_connection(VAR_TO, VAR0, strong), cluster_root(VAR0). - var_cluster(VAR0, VAR_TO2) :- dfa_connection(VAR_TO2, VAR_TO1, strong), var_cluster(VAR0, VAR_TO1). - var_cluster(VAR0, VAR0):- cluster_root(VAR0). - - -impl_fulfill_cluster(Var0, Impl) :- var_cluster(Var0, Var_Any); bind(Var_Any, op(Op)); -impl_fulfill(Op, Impl). - impl_fulfill_cluster(VAR0, IMPL, Score) :- - Score = #sum{SCORE, (OP, IMPL, VAR_ANY): impl_fulfill(OP, IMPL, SCORE), var_cluster(VAR0, VAR_ANY), bind(VAR_ANY, op(OP))} - ; bind(VAR0, impl(IMPL)); cluster_root(VAR0); not -impl_fulfill_cluster(VAR0, IMPL). - -%optimization: -% #maximize {SCORE, (VAR0, IMPL) : impl_fulfill_cluster(VAR0, IMPL, SCORE)}. - -#show var_cluster/2. -#show impl_fulfill_cluster/3. \ No newline at end of file diff --git a/problems/unsafe-code.lp b/problems/unsafe-code.lp deleted file mode 100644 index 82d0b44..0000000 --- a/problems/unsafe-code.lp +++ /dev/null @@ -1,10 +0,0 @@ -%Static analysis: CFG -function(testfunc3) . -function(testfunc2) . -call(testfunc2, testfunc3) . - -%Function tags: -tag(testfunc3, unsafe). -%tag(testfunc2, unsafe). - -:- call(X, Y), tag(Y, unsafe), not tag(X, unsafe), function(X), function(Y). \ No newline at end of file diff --git a/scripts/containers/Containers_Implementation_LinkedList1.xreate b/scripts/containers/Containers_Implementation_LinkedList1.xreate index c1998de..e99ac95 100644 --- a/scripts/containers/Containers_Implementation_LinkedList1.xreate +++ b/scripts/containers/Containers_Implementation_LinkedList1.xreate @@ -1,47 +1,47 @@ // EXTERN INCLUDES interface(extern-c){ xml2 = library:: pkgconfig("libxml-2.0"). include { xml2 = ["libxml/tree.h"] }. } // CONTAINERS interface(dfa) { operator map:: (op(seqaccess)) -> impl(solid). operator list_range:: ()->impl(on_the_fly). operator list:: ()->impl(solid). operator fold:: (op(seqaccess)). /* operator index:: (op(randaccess)). - BREAKS THE ANALYSIS. MAKE tree VIEWED AS COLLECTION */ /* operator map: (op(seqaccess)) -> impl(llvm_array | on_the_fly); */ } import raw("core/containers.lp"). // PROGRAM XmlNode = type alias { tag:: string, /* attrs:: [string],*/ content:: string }. -Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]. +Tree = type Tree(Leaf) {Leaf, [Tree(Leaf)]}. XmlTree = type alias Tree(XmlNode). test= function:: num; entry { filename = "scripts/containers/Containers_Implementation_LinkedList1-data.xml" :: string. docRaw = xmlParseFile(filename) :: xmlDocPtr. tree= xmlDocGetRootElement(docRaw) :: xmlNodePtr. childrenRaw = tree["children"]:: [xmlNodePtr]; linkedlist(next, null). size = loop fold(childrenRaw->child:: xmlNodePtr, 0->count):: int { count +1::int }. size }