diff --git a/config/default.json b/config/default.json index 04ec9d5..a2522d6 100644 --- a/config/default.json +++ b/config/default.json @@ -1,69 +1,69 @@ { "containers": { "id": { "implementations": "impl_fulfill_cluster", "clusters": "var_cluster", "prototypes": "proto_cluster", "linkedlist": "linkedlist" }, "impl": { "solid": "solid", "onthefly": "on_the_fly" } }, "logging": { "id": "logging" }, "function-entry": "entry", "clasp": { "bindings" : { "variable": "bind", "function": "bind_func", "scope": "bind_scope", "function_demand" : "bind_function_demand", "scope_decision": "bind_scope_decision" }, "context" : { "decisions":{ "dependent": "resolution_dependency" }, }, "nonevalue": "nonevalue", "ret": { "symbol": "retv", "tag": "ret" } }, "tests": { "template": "default", "templates": { - "default": "*-", + "default": "*-Adhoc.*:Compilation.full_IFStatementWithVariantType:Types.full_VariantType_Switch1", "ast": "AST.*", "adhocs": "Adhoc.*", "effects": "Effects.*", "basic": "Attachments.*", "context": "Context.*", "compilation": "Compilation.*", "cfa": "CFA.*", "containers": "Containers.*", "dfa": "DFA.*", "diagnostic": "Diagnostic.*", - "dsl": "Interpretation.*:InterpretationExamples.*", + "dsl": "Interpretation.*", "ExpressionSerializer": "ExpressionSerializer.*", "externc": "InterfaceExternC.*", "loops": "Loop.*", "modules": "Modules.*", - "types": "Types.*-", + "types": "Types.*", "vendorsAPI/clang": "ClangAPI.*", "vendorsAPI/xml2": "libxml2*" } } } diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index 9f4c71a..61049e9 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -1,229 +1,229 @@ cmake_minimum_required(VERSION 2.8.11) project(xreate) cmake_policy(SET CMP0022 NEW) message("MODULES" ${CMAKE_MODULE_PATH}) # LLVM #====================== FIND_PACKAGE (LLVM REQUIRED) set(LLVM_VERSION ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message("LLVM LIB PATH:" ${LLVM_LIBRARY_DIRS}) message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") INCLUDE_DIRECTORIES(${LLVM_INCLUDE_DIRS}) message(STATUS "INCLUDE DIR: ${LLVM_INCLUDE_DIRS}") add_definitions(${LLVM_DEFINITIONS}) message("LLVM DEFS: " ${LLVM_DEFINITIONS}) llvm_map_components_to_libnames(LLVM_LIBS core nativecodegen native executionengine mcjit support option) message("LLVM LIBS: " ${LLVM_LIBS}) # CLANG #====================== set(CLANG_LIBS clangCodeGen clangASTMatchers clangQuery clangTooling clangFrontend clangSerialization clangDriver clangParse clangSema clangAnalysis clangAST clangEdit clangLex clangBasic ) # POTASSCO #====================== set(POTASSCO_PATH "/opt/potassco/clingo" CACHE PATH "Path to potassco sources") set(POTASSCO_INCLUDE_PATH ${POTASSCO_PATH}/libgringo ${POTASSCO_PATH}/libclasp ${POTASSCO_PATH}/libclingo ${POTASSCO_PATH}/libprogram_opts ${POTASSCO_PATH}/liblp ) INCLUDE_DIRECTORIES(${POTASSCO_INCLUDE_PATH}) set(LIBCLASP_LIBS clingo clasp gringo program_opts reify lp ) message("CLASP LIBS: " ${LIBCLASP_LIBS}) # OTHER DEPENDENCIES #=========================== set(JEAYESON_INCLUDE_PATH ${CMAKE_HOME_DIRECTORY}/../vendors/jeayeson/include/ ) INCLUDE_DIRECTORIES(${JEAYESON_INCLUDE_PATH}) # COCO #=========================== set(COCO_EXECUTABLE "" CACHE PATH "Path to coco executable") set(COCO_FRAMES_PATH "" CACHE PATH "Path to coco frames") set(COCO_GRAMMAR_PATH ${CMAKE_HOME_DIRECTORY}/../grammar/) set(COCO_SOURCE_FILES_MAIN ${COCO_GRAMMAR_PATH}/main/Parser.cpp ${COCO_GRAMMAR_PATH}/main/Scanner.cpp ) set(COCO_SOURCE_FILES_MODULES ${COCO_GRAMMAR_PATH}/modules/Parser.cpp ${COCO_GRAMMAR_PATH}/modules/Scanner.cpp ) set(COCO_SOURCE_FILES ${COCO_SOURCE_FILES_MODULES} ${COCO_SOURCE_FILES_MAIN}) INCLUDE_DIRECTORIES(${COCO_GRAMMAR_PATH}) add_custom_command(OUTPUT ${COCO_SOURCE_FILES_MAIN} COMMAND ${COCO_GRAMMAR_PATH}/gen-grammar main ${COCO_EXECUTABLE} ${COCO_FRAMES_PATH} WORKING_DIRECTORY ${COCO_GRAMMAR_PATH} MAIN_DEPENDENCY ${COCO_GRAMMAR_PATH}/xreate.ATG ) add_custom_command(OUTPUT ${COCO_SOURCE_FILES_MODULES} COMMAND ${COCO_GRAMMAR_PATH}/gen-grammar modules ${COCO_EXECUTABLE} ${COCO_FRAMES_PATH} WORKING_DIRECTORY ${COCO_GRAMMAR_PATH} MAIN_DEPENDENCY ${COCO_GRAMMAR_PATH}/modules.ATG ) message(STATUS "COCO GRAMMAR BUILD STATUS:" ${COCO_OUTPUT}) # XREATE #====================== set(SOURCE_FILES - modules.cpp + compilation/targetinterpretation.cpp + pass/interpretationpass.cpp ast.cpp xreatemanager.cpp analysis/typeinference.cpp aux/xreatemanager-decorators.cpp compilation/operators.cpp compilation/transformations.cpp compilation/transformersaturation.cpp pass/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 aux/serialization/expressionserializer.cpp + modules.cpp ) set(XREATE_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/ ) INCLUDE_DIRECTORIES(${XREATE_INCLUDE_DIRS}) set(XREATE_PRIVATE_INCLUDE_DIRS ${XREATE_INCLUDE_DIRS} ${COCO_GRAMMAR_PATH} ${JEAYESON_INCLUDE_PATH} ${LLVM_INCLUDE_DIRS} ${POTASSCO_INCLUDE_PATH} ) -add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${COCO_SOURCE_FILES}) +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/ast.cpp b/cpp/src/ast.cpp index 87c974b..06cdd55 100644 --- a/cpp/src/ast.cpp +++ b/cpp/src/ast.cpp @@ -1,928 +1,951 @@ #include "ast.h" #include "ExternLayer.h" #include "analysis/typeinference.h" #include #include //TODO BDecl. forbid multiple body declaration (ExprTyped) -namespace std{ +namespace std { + std::size_t - hash::operator()(xreate::ScopedSymbol const& s) const - {return s.id ^ (s.version << 2);} + 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; } + 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{ + 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; + 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) -{} +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)); + 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: +class ExpressionHints { +public: - static bool - isStringValueValid(const Expression& e) { - switch (e.__state) { - case Expression::INVALID: - assert(false); + static bool + isStringValueValid(const Expression& e) { + switch (e.__state) { + case Expression::INVALID: + assert(false); - case Expression::IDENT: - case Expression::STRING: - return true; + case Expression::IDENT: + case Expression::STRING: + return true; - case Expression::NUMBER: - case Expression::BINDING: - return false; + case Expression::NUMBER: + case Expression::BINDING: + return false; - case Expression::COMPOUND: - { - switch (e.op) { - case Operator::CALL: - return true; + case Expression::COMPOUND: + { + switch (e.op) { + case Operator::CALL: + return true; - default: return false; - } + default: return false; } } - - return false; } - static bool - isDoubleValueValid(const Expression& e) { - switch (e.__state) { - case Expression::NUMBER: - return true; - - case Expression::INVALID: - assert(false); - - case Expression::IDENT: - case Expression::STRING: - case Expression::BINDING: - return false; - - case Expression::COMPOUND:{ - switch (e.op) { - case Operator::VARIANT: - return true; - default: return false; - } + return false; + } + + static bool + isDoubleValueValid(const Expression& e) { + switch (e.__state) { + case Expression::NUMBER: + return true; + + case Expression::INVALID: + assert(false); + + case Expression::IDENT: + case Expression::STRING: + case Expression::BINDING: + return false; + + case Expression::COMPOUND: { + switch (e.op) { + case Operator::VARIANT: + return true; + default: return false; } } - - return false; } - }; - class TypesResolver { - private: - const AST* ast; - std::map scope; - std::map signatures; + return false; + } +}; - ExpandedType expandType(const TypeAnnotation &t, const std::vector &args = std::vector()) { - return TypesResolver(ast, scope, signatures)(t, args); - } +class TypesResolver { +private: + const AST* ast; + std::map scope; + std::map signatures; - std::vector - expandOperands(const std::vector& operands) { - std::vector pack; + ExpandedType expandType(const TypeAnnotation &t, const std::vector &args = std::vector()) { + return TypesResolver(ast, scope, signatures)(t, args); + } - pack.reserve(operands.size()); - std::transform(operands.begin(), operands.end(), std::inserter(pack, pack.end()), - [this](const TypeAnnotation & t) { - return expandType(t); - }); + std::vector + expandOperands(const std::vector& operands) { + std::vector pack; - return pack; - } + pack.reserve(operands.size()); + std::transform(operands.begin(), operands.end(), std::inserter(pack, pack.end()), + [this](const TypeAnnotation & t) { + return expandType(t); + }); - public: + return pack; + } - TypesResolver(const AST* root, const std::map& scopeOuter = std::map(), - std::map signaturesOuter = std::map()) - : ast(root), scope(scopeOuter), signatures(signaturesOuter) { - } +public: - 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); - } + TypesResolver(const AST* root, const std::map& scopeOuter = std::map(), + std::map signaturesOuter = std::map()) + : ast(root), scope(scopeOuter), signatures(signaturesOuter) { + } - switch (t.__operator) { - case TypeOperator::ARRAY: - { - assert(t.__operands.size() == 1); + 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); + } - Expanded elTy = expandType(t.__operands.at(0)); - return ExpandedType(TypeAnnotation(tag_array, elTy, 0)); - } + switch (t.__operator) { + case TypeOperator::ARRAY: + { + assert(t.__operands.size() == 1); - case TypeOperator::STRUCT: - { - assert(t.__operands.size()); + Expanded elTy = expandType(t.__operands.at(0)); + return ExpandedType(TypeAnnotation(tag_array, elTy, 0)); + } - std::vector&& packOperands = expandOperands(t.__operands); - auto typNew = TypeAnnotation(TypeOperator::STRUCT, move(packOperands)); - typNew.fields = t.fields; + case TypeOperator::STRUCT: + { + assert(t.__operands.size()); - return ExpandedType(move(typNew)); - }; + std::vector&& packOperands = expandOperands(t.__operands); + auto typNew = TypeAnnotation(TypeOperator::STRUCT, move(packOperands)); + typNew.fields = t.fields; - case TypeOperator::CALL: - { - std::string alias = t.__valueCustom; + return ExpandedType(move(typNew)); + }; - //find in local scope: - TypeAnnotation ty; - if (scope.count(alias)) { - ty = scope.at(alias); + case TypeOperator::CALL: + { + std::string alias = t.__valueCustom; - } else if (ast->__indexTypeAliases.count(alias)) { - ty = ast->__indexTypeAliases.at(alias); + //find in local scope: + TypeAnnotation ty; + if (scope.count(alias)) { + ty = scope.at(alias); - } else { - assert(false && "Undefined or external type"); - } + } else if (ast->__indexTypeAliases.count(alias)) { + ty = ast->__indexTypeAliases.at(alias); - std::vector&& operands = expandOperands(t.__operands); - TypeAnnotation signature(TypeOperator::CALL, move(operands)); - signature.__valueCustom = alias; + } else { + assert(false && "Undefined or external type"); + } - if (signatures.count(signature)) { - auto link = TypeAnnotation(TypeOperator::LINK,{}); - link.conjuctionId = signatures.at(signature); + std::vector&& operands = expandOperands(t.__operands); + TypeAnnotation signature(TypeOperator::CALL, move(operands)); + signature.__valueCustom = alias; - return ExpandedType(move(link)); - } + if (signatures.count(signature)) { + auto link = TypeAnnotation(TypeOperator::LINK,{}); + link.conjuctionId = signatures.at(signature); - int cid = signatures.size(); - signatures[signature] = cid; - TypeAnnotation tyResult = expandType(ty, operands); - tyResult.conjuctionId = cid; + return ExpandedType(move(link)); + } - return ExpandedType(move(tyResult)); - }; + int cid = signatures.size(); + signatures[signature] = cid; + TypeAnnotation tyResult = expandType(ty, operands); + tyResult.conjuctionId = cid; - case TypeOperator::CUSTOM: - { - std::string alias = t.__valueCustom; + return ExpandedType(move(tyResult)); + }; - /* - if (signatures.count(alias)) { - return ExpandedType(TypeAnnotation(TypeOperator::LINK, {t})); - } - signatures[alias].emplace(t); - */ + case TypeOperator::CUSTOM: + { + std::string alias = t.__valueCustom; - //find in local scope: - if (scope.count(alias)) { - return expandType(scope.at(alias)); - } + /* + if (signatures.count(alias)) { + return ExpandedType(TypeAnnotation(TypeOperator::LINK, {t})); + } + signatures[alias].emplace(t); + */ - // find in general scope: - if (ast->__indexTypeAliases.count(alias)) { - return expandType(ast->__indexTypeAliases.at(t.__valueCustom)); - } + //find in local scope: + if (scope.count(alias)) { + return expandType(scope.at(alias)); + } - //if type is unknown keep it as is. - return ExpandedType(TypeAnnotation(t)); - }; + // find in general scope: + if (ast->__indexTypeAliases.count(alias)) { + return expandType(ast->__indexTypeAliases.at(t.__valueCustom)); + } - case TypeOperator::ACCESS: - { - std::string alias = t.__valueCustom; - ExpandedType tyAlias = ExpandedType(TypeAnnotation()); + //if type is unknown keep it as is. + return ExpandedType(TypeAnnotation(t)); + }; - //find in local scope: - if (scope.count(alias)) { - tyAlias = expandType(scope.at(alias)); + case TypeOperator::ACCESS: + { + std::string alias = t.__valueCustom; + ExpandedType tyAlias = ExpandedType(TypeAnnotation()); - //find in global scope: - } else if ((ast->__indexTypeAliases.count(alias))) { - tyAlias = expandType(ast->__indexTypeAliases.at(alias)); + //find in local scope: + if (scope.count(alias)) { + tyAlias = expandType(scope.at(alias)); - } else { - assert(false && "Undefined or external type"); - } + //find in global scope: + } else if ((ast->__indexTypeAliases.count(alias))) { + tyAlias = expandType(ast->__indexTypeAliases.at(alias)); - assert(tyAlias->__operator == TypeOperator::STRUCT); + } else { + assert(false && "Undefined or external type"); + } - for (const string& field : t.fields) { - auto fieldIt = std::find(tyAlias->fields.begin(), tyAlias->fields.end(), field); - assert(fieldIt != tyAlias->fields.end() && "unknown field"); + assert(tyAlias->__operator == TypeOperator::STRUCT); - int fieldId = fieldIt - tyAlias->fields.begin(); - tyAlias = expandType(tyAlias->__operands.at(fieldId)); - } + for (const string& field : t.fields) { + auto fieldIt = std::find(tyAlias->fields.begin(), tyAlias->fields.end(), field); + assert(fieldIt != tyAlias->fields.end() && "unknown field"); - return tyAlias; + int fieldId = fieldIt - tyAlias->fields.begin(); + tyAlias = expandType(tyAlias->__operands.at(fieldId)); } - case TypeOperator::VARIANT: - { - return ExpandedType(TypeAnnotation(t)); - } + return tyAlias; + } - case TypeOperator::NONE: - { - return ExpandedType(TypeAnnotation(t)); - } + case TypeOperator::VARIANT: + { + return ExpandedType(TypeAnnotation(t)); + } - default: - assert(false); + case TypeOperator::NONE: + { + return ExpandedType(TypeAnnotation(t)); } - assert(false); - return ExpandedType(TypeAnnotation()); + default: + assert(false); } - }; - TypeAnnotation::TypeAnnotation() - : __operator(TypeOperator::NONE), __value(TypePrimitive::Invalid) - {} - - TypeAnnotation::TypeAnnotation(TypePrimitive typ) - : __value(typ) { + assert(false); + return ExpandedType(TypeAnnotation()); } +}; - TypeAnnotation::TypeAnnotation(TypeOperator op, std::initializer_list operands) - : __operator(op), __operands(operands) { +TypeAnnotation::TypeAnnotation() +: __operator(TypeOperator::NONE), __value(TypePrimitive::Invalid) { +} - } +TypeAnnotation::TypeAnnotation(TypePrimitive typ) +: __value(typ) { +} - TypeAnnotation::TypeAnnotation(TypeOperator op, std::vector&& operands) - : __operator(op), __operands(operands) { - } +TypeAnnotation::TypeAnnotation(TypeOperator op, std::initializer_list 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); - } +TypeAnnotation::TypeAnnotation(TypeOperator op, std::vector&& operands) +: __operator(op), __operands(operands) { +} - bool - TypeAnnotation::operator<(const TypeAnnotation& t) const { - if (__operator != t.__operator) return __operator < t.__operator; +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); +} - if (__operator == TypeOperator::NONE) - return __value < t.__value; +bool +TypeAnnotation::operator<(const TypeAnnotation& t) const { + if (__operator != t.__operator) return __operator < t.__operator; - if (__operator == TypeOperator::CALL || __operator == TypeOperator::CUSTOM || __operator == TypeOperator::ACCESS) { - if (__valueCustom != t.__valueCustom) - return __valueCustom < t.__valueCustom; - } + if (__operator == TypeOperator::NONE) + return __value < t.__value; - return __operands < t.__operands; + if (__operator == TypeOperator::CALL || __operator == TypeOperator::CUSTOM || __operator == TypeOperator::ACCESS) { + if (__valueCustom != t.__valueCustom) + return __valueCustom < t.__valueCustom; } - /* - TypeAnnotation (struct_tag, std::initializer_list) - {} - */ + return __operands < t.__operands; +} - void - TypeAnnotation::addBindings(std::vector>&& params) { - bindings.reserve(bindings.size() + params.size()); +/* +TypeAnnotation (struct_tag, std::initializer_list) +{} + */ - std::transform(params.begin(), params.end(), std::inserter(bindings, bindings.end()), - [](const Atom& ident) { - return ident.get(); }); - } +void +TypeAnnotation::addBindings(std::vector>&& params) { + bindings.reserve(bindings.size() + params.size()); - void - TypeAnnotation::addFields(std::vector>&& listFields) { - fields.reserve(fields.size() + listFields.size()); + std::transform(params.begin(), params.end(), std::inserter(bindings, bindings.end()), + [](const Atom& ident) { + return ident.get(); }); +} - std::transform(listFields.begin(), listFields.end(), std::inserter(fields, fields.end()), - [](const Atom& ident) { - return ident.get(); }); - } +void +TypeAnnotation::addFields(std::vector>&& listFields) { + fields.reserve(fields.size() + listFields.size()); - unsigned int Expression::nextVacantId = 0; + std::transform(listFields.begin(), listFields.end(), std::inserter(fields, fields.end()), + [](const Atom& ident) { + return ident.get(); }); +} - Expression::Expression(const Atom& number) - : Expression() { - __state=NUMBER; op=Operator::NONE; __valueD=number.get(); - } +unsigned int Expression::nextVacantId = 0; - Expression::Expression(const Atom& a) - : Expression(){ - __state=STRING; op=Operator::NONE; __valueS=a.get(); - } +Expression::Expression(const Atom& number) +: Expression() { + __state = NUMBER; + op = Operator::NONE; + __valueD = number.get(); +} - Expression::Expression(const Atom &ident) - : Expression() { - __state=IDENT; op=Operator::NONE; __valueS=ident.get(); - } +Expression::Expression(const Atom& a) +: Expression() { + __state = STRING; + op = Operator::NONE; + __valueS = a.get(); +} - Expression::Expression(const Operator &oprt, std::initializer_list params) - : Expression() { - __state=COMPOUND; op=oprt; +Expression::Expression(const Atom &ident) +: Expression() { + __state = IDENT; + op = Operator::NONE; + __valueS = ident.get(); +} - if (op == Operator::CALL) { - assert(params.size() > 0); - Expression arg = *params.begin(); +Expression::Expression(const Operator &oprt, std::initializer_list params) +: Expression() { + __state = COMPOUND; + op = oprt; - assert(arg.__state == Expression::IDENT); - __valueS = std::move(arg.__valueS); + if (op == Operator::CALL) { + assert(params.size() > 0); + Expression arg = *params.begin(); - operands.insert(operands.end(), params.begin() + 1, params.end()); - return; - } + assert(arg.__state == Expression::IDENT); + __valueS = std::move(arg.__valueS); - operands.insert(operands.end(), params.begin(), params.end()); + operands.insert(operands.end(), params.begin() + 1, params.end()); + return; } - void - Expression::setOp(Operator oprt) { - op = oprt; + operands.insert(operands.end(), params.begin(), params.end()); +} - switch (op) { - case Operator::NONE: - __state = INVALID; - break; +void +Expression::setOp(Operator oprt) { + op = oprt; - default: - __state = COMPOUND; - break; - } - } + switch (op) { + case Operator::NONE: + __state = INVALID; + break; - void - Expression::addArg(Expression &&arg) { - operands.push_back(arg); + 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){ +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::addBindings(std::initializer_list> params) { + addBindings(params.begin(), params.end()); +} - void - Expression::bindType(TypeAnnotation t) { - type = move(t); - } +void +Expression::bindType(TypeAnnotation t) { + type = move(t); +} - void - Expression::addBlock(ManagedScpPtr scope) { - blocks.push_back(scope.operator->()); - } +void +Expression::addBlock(ManagedScpPtr scope) { + blocks.push_back(scope.operator->()); +} - const std::vector& - Expression::getOperands() const { - return operands; - } +const std::vector& +Expression::getOperands() const { + return operands; +} - double - Expression::getValueDouble() const { - return __valueD; - } +double +Expression::getValueDouble() const { + return __valueD; +} - const std::string& - Expression::getValueString() const { - return __valueS; - } +const std::string& +Expression::getValueString() const { + return __valueS; +} - void - Expression::setValue(const Atom&& v) { - __valueS = v.get(); - } +void +Expression::setValue(const Atom&& v) { + __valueS = v.get(); +} - void Expression::setValueDouble(double value) { - __valueD = value; - } +void Expression::setValueDouble(double value) { + __valueD = value; +} - bool - Expression::isValid() const { - return (__state != INVALID); - } +bool +Expression::isValid() const { + return (__state != INVALID); +} - bool - Expression::isDefined() const { - return (__state != BINDING); - } +bool +Expression::isDefined() const { + return (__state != BINDING); +} - Expression::Expression() - : __state(INVALID), op(Operator::NONE), id(nextVacantId++) - { } +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); } void AST::recognizeVariantConstructor(Expression& function) { assert(function.op == Operator::CALL); std::string variant = function.getValueString(); if (!__dictVariants.count(variant)) { return; } auto record = __dictVariants.at(variant); const TypeAnnotation& typ = record.first; function.op = Operator::VARIANT; function.setValueDouble(record.second); function.type = typ; } +Atom +AST::recognizeVariantConstructor(Atom ident) { + std::string variant = ident.get(); + assert(__dictVariants.count(variant) && "Can't recognize variant constructor"); + auto record = __dictVariants.at(variant); + + return Atom(record.second); +} + void AST::postponeIdentifier(CodeScope* scope, const Expression& id) { bucketUnrecognizedIdentifiers.emplace(scope, id); } void AST::recognizePostponedIdentifiers() { - for(const auto& identifier: bucketUnrecognizedIdentifiers){ - if (!identifier.first->recognizeIdentifier(identifier.second)){ + for (const auto& identifier : bucketUnrecognizedIdentifiers) { + if (!identifier.first->recognizeIdentifier(identifier.second)) { //exception: Ident not found - std::cout << "Unknown symbol: "<< identifier.second.getValueString() << std::endl; + 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); + return reinterpret_cast (this); } -}} //namespace details::incomplete + +} } //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){ +AST::getType(const Expression& expression) { return typeinference::getType(expression, *this); } - Function::Function(const Atom& name) - : __entry(new CodeScope(0)) { - __name = name.get(); - } - - void - Function::addTag(Expression&& tag, const TagModifier mod) { - string name = tag.getValueString(); - __tags.emplace(move(name), move(tag)); - } +Function::Function(const Atom& name) +: __entry(new CodeScope(0)) { + __name = name.get(); +} - const std::map& - Function::getTags() const { - return __tags; - } +void +Function::addTag(Expression&& tag, const TagModifier mod) { + string name = tag.getValueString(); + __tags.emplace(move(name), move(tag)); +} - CodeScope* - Function::getEntryScope() const { - return __entry; - } +const std::map& +Function::getTags() const { + return __tags; +} - void - Function::addBinding(Atom && name, Expression&& argument) { - __entry->addBinding(move(name), move(argument)); - } +CodeScope* +Function::getEntryScope() const { + return __entry; +} - const std::string& - Function::getName() const { - return __name; - } +void +Function::addBinding(Atom && name, Expression&& argument) { + __entry->addBinding(move(name), move(argument)); +} - ScopedSymbol - CodeScope::registerIdentifier(const Expression& identifier) { - versions::VariableVersion version = Attachments::get(identifier, versions::VERSION_NONE); +const std::string& +Function::getName() const { + return __name; +} - auto result = __identifiers.emplace(identifier.getValueString(), __vCounter); - if (result.second){ - ++__vCounter; - return {__vCounter-1, version}; - } +ScopedSymbol +CodeScope::registerIdentifier(const Expression& identifier) { + versions::VariableVersion version = Attachments::get(identifier, versions::VERSION_NONE); - return {result.first->second, version}; + auto result = __identifiers.emplace(identifier.getValueString(), __vCounter); + if (result.second) { + ++__vCounter; + return { __vCounter - 1, version }; } - bool - CodeScope::recognizeIdentifier(const Expression& identifier) const{ - versions::VariableVersion version = Attachments::get(identifier, versions::VERSION_NONE); - const std::string& name = identifier.getValueString(); - - //search identifier in the current block - if (__identifiers.count(name)){ - VNameId id = __identifiers.at(name); + return { result.first->second, version }; +} - Symbol s; - s.identifier = ScopedSymbol{id, version}; - s.scope = const_cast(this); - Attachments::put(identifier, s); +bool +CodeScope::recognizeIdentifier(const Expression& identifier) const { + versions::VariableVersion version = Attachments::get(identifier, versions::VERSION_NONE); + const std::string& name = identifier.getValueString(); - return true; - } + //search identifier in the current block + if (__identifiers.count(name)) { + VNameId id = __identifiers.at(name); - //search in the parent scope - if (__parent) - { - return __parent->recognizeIdentifier(identifier); - } + Symbol s; + s.identifier = ScopedSymbol{id, version}; + s.scope = const_cast (this); + Attachments::put(identifier, s); - return false; + return true; } - ScopedSymbol - CodeScope::getSymbol(const std::string& alias){ - assert(__identifiers.count(alias)); - VNameId id = __identifiers.at(alias); - - return {id, versions::VERSION_NONE}; + //search in the parent scope + if (__parent) { + return __parent->recognizeIdentifier(identifier); } - void - CodeScope::addBinding(Expression&& var, Expression&& argument) { - argument.__state = Expression::BINDING; + return false; +} - __bindings.push_back(var.getValueString()); - ScopedSymbol binding = registerIdentifier(var); - __declarations[binding] = move(argument); - } +ScopedSymbol +CodeScope::getSymbol(const std::string& alias) { + assert(__identifiers.count(alias)); + VNameId id = __identifiers.at(alias); - void - CodeScope::addDeclaration(Expression&& var, Expression&& body) { - ScopedSymbol s = registerIdentifier(var); - __declarations[s] = move(body); - } + return {id, versions::VERSION_NONE }; +} - CodeScope::CodeScope(CodeScope* parent) - : __parent(parent) { - } +void +CodeScope::addBinding(Expression&& var, Expression&& argument) { + argument.__state = Expression::BINDING; - CodeScope::~CodeScope() { - } + __bindings.push_back(var.getValueString()); + ScopedSymbol binding = registerIdentifier(var); + __declarations[binding] = move(argument); +} - void - CodeScope::setBody(const Expression &body) { - __declarations[ScopedSymbol::RetSymbol] = body; - } +void +CodeScope::addDeclaration(Expression&& var, Expression&& body) { + ScopedSymbol s = registerIdentifier(var); + __declarations[s] = move(body); +} - Expression& - CodeScope::getBody() { - return __declarations[ScopedSymbol::RetSymbol]; - } +CodeScope::CodeScope(CodeScope* parent) +: __parent(parent) { +} - const Expression& - CodeScope::getDeclaration(const Symbol& symbol) { - CodeScope* self = symbol.scope; - return self->getDeclaration(symbol.identifier); - } +CodeScope::~CodeScope() { +} - const Expression& - CodeScope::getDeclaration(const ScopedSymbol& symbol){ - assert(__declarations.count(symbol) && "Symbol's declaration not found"); +void +CodeScope::setBody(const Expression &body) { + __declarations[ScopedSymbol::RetSymbol] = body; +} - return __declarations.at(symbol); - } +Expression& +CodeScope::getBody() { + return __declarations[ScopedSymbol::RetSymbol]; +} - void - RuleArguments::add(const Atom &arg, DomainAnnotation typ) { - emplace_back(arg.get(), typ); - } +const Expression& +CodeScope::getDeclaration(const Symbol& symbol) { + CodeScope* self = symbol.scope; + return self->getDeclaration(symbol.identifier); +} - void - RuleGuards::add(Expression&& e) { - push_back(e); - } +const Expression& +CodeScope::getDeclaration(const ScopedSymbol& symbol) { + assert(__declarations.count(symbol) && "Symbol's declaration not found"); - MetaRuleAbstract:: - MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards) - : __args(std::move(args)), __guards(std::move(guards)) { - } + return __declarations.at(symbol); +} - MetaRuleAbstract::~MetaRuleAbstract() { - } +void +RuleArguments::add(const Atom &arg, DomainAnnotation typ) { + emplace_back(arg.get(), typ); +} - RuleWarning:: - RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message) - : MetaRuleAbstract(std::move(args), std::move(guards)), __message(message.get()), __condition(condition) { - } +void +RuleGuards::add(Expression&& e) { + push_back(e); +} - RuleWarning::~RuleWarning() { - } +MetaRuleAbstract:: +MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards) +: __args(std::move(args)), __guards(std::move(guards)) { +} - void - RuleWarning::compile(ClaspLayer& layer) { - //TODO restore addRuleWarning - //layer.addRuleWarning(*this); - } +MetaRuleAbstract::~MetaRuleAbstract() { +} - bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2) { - return (s1.id < s2.id) || (s1.id==s2.id && s1.version < s2.version); - } +RuleWarning:: +RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message) +: MetaRuleAbstract(std::move(args), std::move(guards)), __message(message.get()), __condition(condition) { +} - bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2) { - return (s1.id == s2.id) && (s1.version == s2.version); - } +RuleWarning::~RuleWarning() { +} - bool operator<(const Symbol& s1, const Symbol& s2) { - return (s1.scope < s2.scope) || (s1.scope == s2.scope && s1.identifier < s2.identifier); - } +void +RuleWarning::compile(ClaspLayer& layer) { + //TODO restore addRuleWarning + //layer.addRuleWarning(*this); +} - bool operator==(const Symbol& s1, const Symbol& s2) { - return (s1.scope == s2.scope) && (s1.identifier == s2.identifier); - } +bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2) { + return (s1.id < s2.id) || (s1.id == s2.id && s1.version < s2.version); +} - 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::NUMBER: - return a.getValueDouble() < b.getValueDouble(); +bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2) { + return (s1.id == s2.id) && (s1.version == s2.version); +} - case Expression::COMPOUND: - { - assert(a.blocks.size() == 0); - assert(b.blocks.size() == 0); +bool operator<(const Symbol& s1, const Symbol& s2) { + return (s1.scope < s2.scope) || (s1.scope == s2.scope && s1.identifier < s2.identifier); +} - if (a.op != b.op){ - return a.op < b.op; - } +bool operator==(const Symbol& s1, const Symbol& s2) { + return (s1.scope == s2.scope) && (s1.identifier == s2.identifier); +} - bool flagAValid = ExpressionHints::isStringValueValid(a); - bool flagBValid = ExpressionHints::isStringValueValid(b); +bool operator<(const Expression&a, const Expression&b) { + if (a.__state != b.__state) return a.__state < b.__state; + assert(a.__state != Expression::INVALID); + switch (a.__state) { + case Expression::IDENT: + case Expression::STRING: + return a.getValueString() < b.getValueString(); + + case Expression::NUMBER: + return a.getValueDouble() < b.getValueDouble(); + + case Expression::COMPOUND: + { + assert(a.blocks.size() == 0); + assert(b.blocks.size() == 0); - if (flagAValid != flagBValid) { - return flagAValid < flagBValid; - } + if (a.op != b.op) { + return a.op < b.op; + } - if (flagAValid){ - if (a.getValueString() != b.getValueString()) { - return a.getValueString() < b.getValueString(); - } - } + bool flagAValid = ExpressionHints::isStringValueValid(a); + bool flagBValid = ExpressionHints::isStringValueValid(b); - flagAValid = ExpressionHints::isDoubleValueValid(a); - flagBValid = ExpressionHints::isDoubleValueValid(b); + if (flagAValid != flagBValid) { + return flagAValid < flagBValid; + } - if (flagAValid != flagBValid) { - return flagAValid < flagBValid; + if (flagAValid) { + if (a.getValueString() != b.getValueString()) { + return a.getValueString() < b.getValueString(); } + } - if (flagAValid){ - if (a.getValueDouble() != b.getValueDouble()) { - return a.getValueDouble() < b.getValueDouble(); - } - } + flagAValid = ExpressionHints::isDoubleValueValid(a); + flagBValid = ExpressionHints::isDoubleValueValid(b); - if (a.operands.size() != b.operands.size()) { - return (a.operands.size() < b.operands.size()); - } + if (flagAValid != flagBValid) { + return flagAValid < flagBValid; + } - for (size_t i = 0; i < a.operands.size(); ++i) { - bool result = a.operands[i] < b.operands[i]; - if (result) return true; + if (flagAValid) { + if (a.getValueDouble() != b.getValueDouble()) { + return a.getValueDouble() < b.getValueDouble(); } + } - return false; + if (a.operands.size() != b.operands.size()) { + return (a.operands.size() < b.operands.size()); } - case Expression::BINDING: - case Expression::INVALID: - assert(false); + for (size_t i = 0; i < a.operands.size(); ++i) { + bool result = a.operands[i] < b.operands[i]; + if (result) return true; + } + + return false; } - return false; + case Expression::BINDING: + case Expression::INVALID: + assert(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; - } + return false; +} - if (ExpressionHints::isDoubleValueValid(*this)) { - if (this->__valueD != other.__valueD) return false; - } +bool +Expression::operator==(const Expression& other) const { + if (this->__state != other.__state) return false; - if (this->__state != Expression::COMPOUND) { - return true; - } + if (ExpressionHints::isStringValueValid(*this)) { + if (this->__valueS != other.__valueS) return false; + } - if (this->op != other.op) { - return false; - } + if (ExpressionHints::isDoubleValueValid(*this)) { + if (this->__valueD != other.__valueD) return false; + } - if (this->operands.size() != other.operands.size()) { - return false; - } + if (this->__state != Expression::COMPOUND) { + return true; + } - for (size_t i = 0; ioperands.size(); ++i) { - if (!(this->operands[i] == other.operands[i])) return false; - } + if (this->op != other.op) { + return false; + } - assert(!this->blocks.size()); - assert(!other.blocks.size()); + if (this->operands.size() != other.operands.size()) { + return false; + } - return true; + for (size_t i = 0; ioperands.size(); ++i) { + if (!(this->operands[i] == other.operands[i])) return false; } + assert(!this->blocks.size()); + assert(!other.blocks.size()); + + return true; +} + const ScopedSymbol ScopedSymbol::RetSymbol = ScopedSymbol{0, versions::VERSION_NONE}; -} + +} //end of namespace xreate diff --git a/cpp/src/ast.h b/cpp/src/ast.h index 5a71e8e..0a9e308 100644 --- a/cpp/src/ast.h +++ b/cpp/src/ast.h @@ -1,577 +1,576 @@ #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{ +namespace xreate { struct ScopedSymbol; struct Symbol; } -namespace std -{ +namespace std { + template<> - struct hash{ + 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; + struct equal_to { + bool operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const; }; - + template<> - struct hash{ + 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; + 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 +template<> class Atom { public: Atom(const std::wstring& value); Atom(std::string && name); const std::string& get() const; - + private: std::string __value; }; -template<> +template<> class Atom { public: Atom(wchar_t* value); Atom(int value); double get()const; - + private: double __value; }; -template<> +template<> class Atom { public: Atom(const std::wstring& value); const std::string& get() const; private: std::string __value; }; enum class TypePrimitive { Invalid, Bool, I8, I32, I64, Num, Int, Float, String }; enum class TypeOperator { - NONE, CALL, CUSTOM, VARIANT, ARRAY, STRUCT, ACCESS, LINK + 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, + 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, SWITCH_VARIANT, + CASE, CASE_DEFAULT, LOGIC_AND, ADHOC, CONTEXT_RULE, VARIANT }; 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, 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&); +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; namespace versions { typedef int VariableVersion; const VariableVersion VERSION_NONE = -2; const VariableVersion VERSION_INIT = 0; } template<> -struct AttachmentsDict -{ +struct AttachmentsDict { typedef versions::VariableVersion Data; static const unsigned int key = 6; }; -struct ScopedSymbol{ +struct ScopedSymbol { VNameId id; versions::VariableVersion version; static const ScopedSymbol RetSymbol; }; struct Symbol { ScopedSymbol identifier; CodeScope * scope; }; template<> -struct AttachmentsDict -{ +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 void recognizeVariantConstructor(Expression& function); + Atom recognizeVariantConstructor(Atom ident); 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() {} +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/advanced.cpp b/cpp/src/compilation/advanced.cpp index f4c64d2..e4f787c 100644 --- a/cpp/src/compilation/advanced.cpp +++ b/cpp/src/compilation/advanced.cpp @@ -1,399 +1,401 @@ /* * 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::ICodeScopeUnit* scope = context.scope; \ compilation::IFunctionUnit* function = context.function; Advanced::Advanced(compilation::Context ctx) : context(ctx), tyNum(static_cast (ctx.pass->man->llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::Num))))) { } llvm::Value* Advanced::compileMapSolidOutput(const Expression &expr, const std::string hintRetVar) { EXPAND_CONTEXT + UNUSED(scope); //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::ICodeScopeUnit* scopeLoopUnit = function->getScopeUnit(scopeLoop); scopeLoopUnit->bindArg(elIn, move(varEl)); Value* elOut = scopeLoopUnit->compile(); Value *pElOut = builder.CreateGEP(dataOut, ArrayRef(std::vector{ConstantInt::get(tyNum, 0), stateLoop})); builder.CreateStore(elOut, pElOut); //next iteration preparing Value *stateLoopNext = builder.CreateAdd(stateLoop, llvm::ConstantInt::get(tyNum, 1)); stateLoop->addIncoming(stateLoopNext, builder.GetInsertBlock()); //next iteration checks: Value* condAfter = builder.CreateICmpSLE(stateLoopNext, rangeTo); builder.CreateCondBr(condAfter, blockLoop, blockAfterLoop); //finalization: builder.SetInsertPoint(blockAfterLoop); return dataOut; } Value* Advanced::compileArrayIndex(llvm::Value* aggregate, std::vector indexes, std::string hintRetVar) { EXPAND_CONTEXT UNUSED(function); + UNUSED(scope); 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); - + UNUSED(function); TypeUtils types(llvm); std::vector&& fields = types.getStructFields(t); for (unsigned i = 0, size = fields.size(); i < size; ++i) { if (fields.at(i) == idx) { //TODO DISABLEDFEATURE validptr // TODO review safety check: validPtr for `aggregate` // SECTIONTAG validptr exception // std::vector refs; // llvm::BasicBlock *blockSafe = llvm::BasicBlock::Create(llvm::getGlobalContext(), "safe", function->raw); // PointerType* tyAggr = dyn_cast(aggregate->getType()); // llvm::Value* null = llvm::ConstantPointerNull::get(tyAggr); // Value* condNull = llvm->builder.CreateICmpNE(aggregate, null); // // llvm::BasicBlock *blockException = llvm::BasicBlock::Create(llvm::getGlobalContext(), "exception", function->raw); // llvm->builder.CreateCondBr(condNull, blockSafe, blockException); // llvm->initExceptionBlock(blockException); // // llvm->builder.SetInsertPoint(blockSafe); //dereference pointer if (types.isPointer(t)) { llvm::Value* addr = llvm->builder.CreateConstGEP2_32(nullptr, aggregate, 0, i); return llvm->builder.CreateLoad(addr); } aggregate->getType()->dump(); return llvm->builder.CreateExtractValue(aggregate, llvm::ArrayRef{i}); } } assert(false && "not found required struct field"); return nullptr; } llvm::Value* Advanced::compileFold(const Expression& fold, const std::string& hintRetVar) { EXPAND_CONTEXT assert(fold.op == Operator::FOLD); //initialization: Symbol varInSymbol = Attachments::get(fold.getOperands()[0]); Implementation info = Query::queryImplementation(varInSymbol); Iterator* it = Iterator::create(context, varInSymbol); llvm::Value* rangeBegin = it->begin(); llvm::Value* rangeEnd = it->end(); llvm::Value* accumInit = scope->process(fold.getOperands()[1]); std::string varIn = fold.getOperands()[0].getValueString(); std::string varAccum = fold.bindings[1]; std::string varEl = fold.bindings[0]; llvm::BasicBlock *blockBeforeLoop = llvm->builder.GetInsertBlock(); std::unique_ptr transformerSaturation(new TransformerSaturation(blockBeforeLoop, context.pass->managerTransformations)); llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold", function->raw); llvm::BasicBlock *blockLoopBody = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold_body", function->raw); llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold_after", function->raw); llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold_next", function->raw); llvm->builder.CreateBr(blockLoop); // * create phi llvm->builder.SetInsertPoint(blockLoop); llvm::PHINode *accum = llvm->builder.CreatePHI(accumInit->getType(), 2, varAccum); accum->addIncoming(accumInit, blockBeforeLoop); llvm::PHINode *itLoop = llvm->builder.CreatePHI(rangeBegin->getType(), 2, "foldIt"); itLoop->addIncoming(rangeBegin, blockBeforeLoop); // * loop checks Value* condRange = llvm->builder.CreateICmpNE(itLoop, rangeEnd); llvm->builder.CreateCondBr(condRange, blockLoopBody, blockAfterLoop); // * loop body llvm->builder.SetInsertPoint(blockLoopBody); CodeScope* scopeLoop = fold.blocks.front(); compilation::ICodeScopeUnit* loopUnit = function->getScopeUnit(scopeLoop); Value* elIn = it->get(itLoop); loopUnit->bindArg(accum, move(varAccum)); loopUnit->bindArg(elIn, move(varEl)); Value* accumNext = loopUnit->compile(); // * Loop saturation checks bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockNext, blockAfterLoop, context); llvm::BasicBlock* blockSaturation = llvm->builder.GetInsertBlock(); if (!flagSaturationTriggered){ llvm->builder.CreateBr(blockNext); } // * computing next iteration state llvm->builder.SetInsertPoint(blockNext); Value *itLoopNext = it->advance(itLoop); accum->addIncoming(accumNext, llvm->builder.GetInsertBlock()); itLoop->addIncoming(itLoopNext, llvm->builder.GetInsertBlock()); llvm->builder.CreateBr(blockLoop); // * finalization: llvm->builder.SetInsertPoint(blockAfterLoop); if (!flagSaturationTriggered){ return accum; } llvm::PHINode* result = llvm->builder.CreatePHI(accumInit->getType(), 2); result->addIncoming(accum, blockLoop); result->addIncoming(accumNext, blockSaturation); return result; } llvm::Value* Advanced::compileFoldInf(const Expression& fold, const std::string& hintRetVar) { EXPAND_CONTEXT assert(fold.op == Operator::FOLD_INF); std::string accumName = fold.bindings[0]; llvm::Value* accumInit = scope->process(fold.getOperands()[0]); llvm::BasicBlock *blockBeforeLoop = llvm->builder.GetInsertBlock(); llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "foldinf", function->raw); llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm::getGlobalContext(), "foldinf_next", function->raw); llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "foldinf_post", function->raw); std::unique_ptr transformerSaturation(new TransformerSaturation(blockBeforeLoop, context.pass->managerTransformations)); llvm->builder.CreateBr(blockLoop); // * create phi llvm->builder.SetInsertPoint(blockLoop); llvm::PHINode *accum = llvm->builder.CreatePHI(accumInit->getType(), 2, accumName); accum->addIncoming(accumInit, blockBeforeLoop); // * loop body CodeScope* scopeLoop = fold.blocks.front(); compilation::ICodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); unitLoop->bindArg(accum, move(accumName)); Value* accumNext = unitLoop->compile(); // * Loop saturation checks bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockNext, blockAfterLoop, context); assert(flagSaturationTriggered); // * computing next iteration state llvm->builder.SetInsertPoint(blockNext); accum->addIncoming(accumNext, llvm->builder.GetInsertBlock()); llvm->builder.CreateBr(blockLoop); // finalization: llvm->builder.SetInsertPoint(blockAfterLoop); return accumNext; } llvm::Value* Advanced::compileIf(const Expression& exprIf, const std::string& hintRetVar) { EXPAND_CONTEXT //initialization: const Expression& condExpr = exprIf.getOperands()[0]; llvm::IRBuilder<>& builder = llvm->builder; //llvm::Type* tyResultType = llvm->toLLVMType(llvm->ast->expandType(exprIf.type)); llvm::BasicBlock *blockAfter = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifAfter", function->raw); llvm::BasicBlock *blockTrue = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifTrue", function->raw); llvm::BasicBlock *blockFalse = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifFalse", function->raw); llvm::Value* cond = scope->process(condExpr); llvm->builder.CreateCondBr(cond, blockTrue, blockFalse); builder.SetInsertPoint(blockTrue); CodeScope* scopeTrue = exprIf.blocks.front(); llvm::Value* resultTrue = function->getScopeUnit(scopeTrue)->compile(); blockTrue = builder.GetInsertBlock(); builder.CreateBr(blockAfter); builder.SetInsertPoint(blockFalse); CodeScope* scopeFalse = exprIf.blocks.back(); llvm::Value* resultFalse = function->getScopeUnit(scopeFalse)->compile(); blockFalse = builder.GetInsertBlock(); builder.CreateBr(blockAfter); builder.SetInsertPoint(blockAfter); llvm::PHINode *ret = builder.CreatePHI(resultTrue->getType(), 2, NAME("if")); ret->addIncoming(resultTrue, blockTrue); ret->addIncoming(resultFalse, blockFalse); return ret; } //TODO Switch: default variant no needed when all possible conditions are considered llvm::Value* Advanced::compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar) { EXPAND_CONTEXT AST* root = context.pass->man->root; UNUSED(function); assert(exprSwitch.operands.size() >= 2); assert(exprSwitch.operands[1].op == Operator::CASE_DEFAULT && "No default case in Switch Statement"); int countCases = exprSwitch.operands.size() - 1; llvm::IRBuilder<>& builder = llvm->builder; llvm::BasicBlock* blockProlog = builder.GetInsertBlock(); llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "switchAfter", function->raw); builder.SetInsertPoint(blockEpilog); llvm::Type* exprSwitchType = llvm->toLLVMType(root->getType(exprSwitch)); llvm::PHINode *ret = builder.CreatePHI(exprSwitchType, countCases, NAME("switch")); builder.SetInsertPoint(blockProlog); llvm::Value * conditionSwitch = scope->process(exprSwitch.operands[0]); llvm::BasicBlock *blockDefault = llvm::BasicBlock::Create(llvm::getGlobalContext(), "caseDefault", function->raw); llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(conditionSwitch, blockDefault, countCases); for (int size = exprSwitch.operands.size(), i = 2; i < size; ++i) { llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm::getGlobalContext(), "case" + std::to_string(i), function->raw); llvm::Value* condCase = function->getScopeUnit(exprSwitch.operands[i].blocks.front())->compile(); builder.SetInsertPoint(blockCase); llvm::Value* resultCase = function->getScopeUnit(exprSwitch.operands[i].blocks.back())->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultCase, builder.GetInsertBlock()); builder.SetInsertPoint(blockProlog); instructionSwitch->addCase(dyn_cast(condCase), blockCase); } //compile default block: builder.SetInsertPoint(blockDefault); CodeScope* scopeDefault = exprSwitch.operands[1].blocks.front(); llvm::Value* resultDefault = function->getScopeUnit(scopeDefault)->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultDefault, builder.GetInsertBlock()); builder.SetInsertPoint(blockEpilog); return ret; } //TODO recognize cases to make const arrays/stored in global mem/stack alloced. llvm::Value* Advanced::compileListAsSolidArray(const Expression &expr, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(scope); UNUSED(function); AST* root = context.pass->man->root; const size_t& length = expr.getOperands().size(); const Expression& expression = expr; llvm::Value* zero = ConstantInt::get(tyNum, 0); llvm::Value* one = ConstantInt::get(tyNum, 1); ExpandedType typAggrExpanded = root->getType(expression); assert(typAggrExpanded->__operator == TypeOperator::ARRAY); llvm::Type* typEl = llvm->toLLVMType(ExpandedType(typAggrExpanded->__operands[0])); ArrayType* typAggr = (ArrayType*) llvm::ArrayType::get(typEl, length); llvm::Value* list = llvm->builder.CreateAlloca(typAggr, ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), length, false), hintRetVar); const std::vector& operands = expression.getOperands(); llvm::Value* addrOperand = llvm->builder.CreateGEP(typAggr, list, ArrayRef(std::vector{zero, zero})); llvm->builder.CreateStore(scope->process(operands.front()), addrOperand) ; for (auto i=++operands.begin(); i!=operands.end(); ++i){ addrOperand = llvm->builder.CreateGEP(typEl, addrOperand, ArrayRef(std::vector{one})); llvm->builder.CreateStore(scope->process(*i), addrOperand) ; } return list; // Value* listDest = l.builder.CreateAlloca(typList, ConstantInt::get(typI32, __size), *hintRetVar); // l.buil1der.CreateMemCpy(listDest, listSource, __size, 16); } llvm::Value* Advanced::compileConstantStringAsPChar(const string& data, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(function); UNUSED(scope); Type* typPchar = PointerType::getUnqual(Type::getInt8Ty(llvm::getGlobalContext())); //ArrayType* typStr = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::I8, size+1)))); /* std::vector chars; chars.reserve(size+1); for (size_t i=0; i< size; ++i){ chars[i] = ConstantInt::get(typI8, (unsigned char) data[i]); } chars[size] = ConstantInt::get(typI8, 0); */ Value* rawData = ConstantDataArray::getString(llvm::getGlobalContext(), data); Value* rawPtrData = llvm->builder.CreateAlloca(rawData->getType(), ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), 1, false)); llvm->builder.CreateStore(rawData, rawPtrData); return llvm->builder.CreateCast(llvm::Instruction::BitCast, rawPtrData, typPchar, hintRetVar); } diff --git a/cpp/src/compilation/targetinterpretation.cpp b/cpp/src/compilation/targetinterpretation.cpp index b47498c..a424e37 100644 --- a/cpp/src/compilation/targetinterpretation.cpp +++ b/cpp/src/compilation/targetinterpretation.cpp @@ -1,441 +1,495 @@ /* * File: targetinterpretation.cpp * Author: pgess * * Created on June 29, 2016, 6:45 PM */ #include "compilation/targetinterpretation.h" #include "pass/interpretationpass.h" +#include "analysis/typeinference.h" #include "llvmlayer.h" #include "compilation/scopedecorators.h" #include #include #include using namespace std; using namespace xreate::compilation; namespace xreate{ namespace interpretation{ const Expression EXPRESSION_FALSE = Expression(Atom(0)); const Expression EXPRESSION_TRUE = Expression(Atom(1)); //Expression //InterpretationScope::compile(const Expression& expression){} CodeScope* InterpretationScope::processOperatorIf(const Expression& expression){ const Expression& exprCondition = process(expression.getOperands()[0]); if (exprCondition == EXPRESSION_TRUE){ return expression.blocks.front(); } return expression.blocks.back(); } CodeScope* InterpretationScope::processOperatorSwitch(const Expression& expression) { const Expression& exprCondition = process(expression.operands[0]); bool flagHasDefault = expression.operands[1].op == Operator::CASE_DEFAULT; //TODO check that one and only one case variant is appropriate for (size_t size = expression.operands.size(), i= flagHasDefault? 2: 1; igetScope(exprCase.blocks.front())->processScope() == exprCondition){ return exprCase.blocks.back(); } } if (flagHasDefault){ const Expression& exprCaseDefault = expression.operands[1]; return exprCaseDefault.blocks.front(); } assert(false && "Switch has no appropriate variant"); return nullptr; } +CodeScope* +InterpretationScope::processOperatorSwitchVariant(const Expression& expression){ + const Expression& condition = process(expression.operands.at(0)); + assert(condition.op == Operator::VARIANT); + const string identCondition = expression.operands.at(0).getValueString(); + + + Expression opExpected(Atom(condition.getValueDouble())); + auto itFoundValue = std::find(++expression.operands.begin(), expression.operands.end(), opExpected); + assert(itFoundValue != expression.operands.end()); + + int indexBlock = itFoundValue - expression.operands.begin() -1; + auto blockFound = expression.blocks.begin(); + std::advance(blockFound, indexBlock); + + InterpretationScope* scopeI12n = function->getScope(*blockFound); + + if (condition.operands.size()) { + const Expression& value = condition.operands.at(0); + scopeI12n->overrideBinding(value, identCondition); + } + + return *blockFound; +} + llvm::Value* InterpretationScope::compileHybrid(const InterpretationOperator& op, const Expression& expression, const Context& context){ switch(op){ case IF_INTERPRET_CONDITION: { CodeScope* scopeResult = processOperatorIf(expression); llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); return result; } case SWITCH_INTERPRET_CONDITION:{ CodeScope* scopeResult = processOperatorSwitch(expression); llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); return result; } + case SWITCH_VARIANT: { + CodeScope* scopeResult = processOperatorSwitchVariant(expression); + const Expression& condition = process(expression.operands.at(0)); + + const string identCondition = expression.operands.at(0).getValueString(); + auto scopeCompilation = Decorators::getInterface(context.function->getScopeUnit(scopeResult)); + + if(condition.operands.size()){ + //override value + Symbol symbCondition{ScopedSymbol{scopeResult->__identifiers.at(identCondition), versions::VERSION_NONE}, scopeResult}; + scopeCompilation->overrideDeclaration(symbCondition, Expression(condition.operands.at(0))); + + //set correct type for binding: + TypeAnnotation typeVariant = typeinference::getType(condition, *function->man->ast); + int conditionIndex = condition.getValueDouble(); + ScopedSymbol symbolInternal = scopeResult->getSymbol(identCondition); + scopeResult->__declarations[symbolInternal].bindType(typeVariant.__operands.at(conditionIndex)); + } + + llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); + return result; + } + case FOLD_INTERPRET_INPUT: { //initialization const Expression& exprInput = process(expression.getOperands()[0]); assert(exprInput.op == Operator::LIST); CodeScope* scopeBody = expression.blocks.front(); const string& nameEl = expression.bindings[0]; Symbol symbEl{ScopedSymbol{scopeBody->__identifiers.at(nameEl), versions::VERSION_NONE}, scopeBody}; const std::string& idAccum = expression.bindings[1]; llvm::Value* rawAccum = context.scope->process(expression.getOperands()[1]); InterpretationScope* intrBody = function->getScope(scopeBody); auto unitBody = Decorators::getInterface(context.function->getScopeUnit(scopeBody)); const std::vector elementsInput= exprInput.getOperands(); for (size_t i=0; ireset(); unitBody->reset(); Expression exprElement = elementsInput[i]; intrBody->overrideBinding(exprElement, nameEl); unitBody->overrideDeclaration(symbEl, move(exprElement)); unitBody->bindArg(rawAccum, string(idAccum)); rawAccum = unitBody->compile(); } return rawAccum; } /* case FOLD_INF_INTERPRET_INOUT{ } */ case CALL_INTERPRET_PARTIAL: { const std::string &calleeName = expression.getValueString(); ICodeScopeUnit* scopeUnitSelf = context.scope; ManagedFnPtr callee = this->function->man->ast->findFunction(calleeName); const FunctionInterpretationData& calleeData = FunctionInterpretationHelper::getSignature(callee); std::vector argsActual; PIFSignature sig; sig.declaration = callee; for(size_t no=0, size = expression.operands.size(); no < size; ++no){ const Expression& op = expression.operands[no]; if (calleeData.signature.at(no) == INTR_ONLY){ sig.bindings.push_back(process(op)); continue; } argsActual.push_back(scopeUnitSelf->process(op)); } TargetInterpretation* man = dynamic_cast(this->function->man); PIFunction* pifunction = man->getFunction(move(sig)); llvm::Function* raw = pifunction->compile(); boost::scoped_ptr statement(new CallStatementRaw(raw, man->pass->man->llvm)); return (*statement)(move(argsActual)); } default: break; } assert(false&& "Unknown hybrid operator"); return nullptr; } llvm::Value* InterpretationScope::compile(const Expression& expression, const Context& context){ const InterpretationData& data = Attachments::get(expression); if (data.op != InterpretationOperator::NONE){ return compileHybrid(data.op, expression, context); } Expression result = process(expression); return context.scope->process(result); } Expression InterpretationScope::process(const Expression& expression){ switch (expression.__state){ case Expression::INVALID: assert(false); case Expression::NUMBER: case Expression::STRING: return expression; case Expression::IDENT:{ Symbol s = Attachments::get(expression); return Parent::processSymbol(s); } case Expression::COMPOUND: break; default: assert(false); } switch (expression.op) { case Operator::EQU: { const Expression& left = process(expression.operands[0]); const Expression& right = process(expression.operands[1]); if (left == right) return EXPRESSION_TRUE; return EXPRESSION_FALSE; } case Operator::NE: { const Expression& left = process(expression.operands[0]); const Expression& right = process(expression.operands[1]); if (left == right) return EXPRESSION_FALSE; return EXPRESSION_TRUE; } case Operator::LOGIC_AND: { assert(expression.operands.size() == 1); return process (expression.operands[0]); } // case Operator::LOGIC_OR: case Operator::CALL: { const std::string &fnName = expression.getValueString(); ManagedFnPtr fnAst = this->function->man->ast->findFunction(fnName); InterpretationFunction* fnUnit = this->function->man->getFunction(fnAst); vector args; args.reserve(expression.getOperands().size()); for(size_t i=0, size = expression.getOperands().size(); iprocess(args); } case Operator::IF:{ CodeScope* scopeResult = processOperatorIf(expression); return function->getScope(scopeResult)->processScope(); } case Operator::SWITCH: { CodeScope* scopeResult = processOperatorSwitch(expression); return function->getScope(scopeResult)->processScope(); } + case Operator::SWITCH_VARIANT: { + CodeScope* scopeResult = processOperatorSwitchVariant(expression); + return function->getScope(scopeResult)->processScope(); + } + case Operator::INDEX: { const Expression& exprKey = process(expression.operands[1]); const Expression& exprData = process(expression.operands[0]); if (exprKey.__state == Expression::STRING){ const string& key = exprKey.getValueString(); assert(exprData.__indexBindings.count(key)); return exprData.operands[exprData.__indexBindings.at(key)]; } if (exprKey.__state == Expression::NUMBER){ int key = exprKey.getValueDouble(); return exprData.operands[key]; } assert(false); } case Operator::FOLD: { const Expression& exprInput = process(expression.getOperands()[0]); const Expression& exprInit = process(expression.getOperands()[1]); const std::string& argEl = expression.bindings[0]; const std::string& argAccum = expression.bindings[1]; InterpretationScope* body = function->getScope(expression.blocks.front()); Expression accum = exprInit; for(size_t size=exprInput.getOperands().size(), i=0; ioverrideBinding(exprInput.getOperands()[i], argEl); body->overrideBinding(accum, argAccum); accum = body->processScope(); } return accum; } // case Operator::MAP: { // break; // } default: break; } return expression; } InterpretationFunction* TargetInterpretation::getFunction(IFunctionUnit* unit){ if (__dictFunctionsByUnit.count(unit)) { return __dictFunctionsByUnit.at(unit); } InterpretationFunction* f = new InterpretationFunction(unit->function, this); __dictFunctionsByUnit.emplace(unit, f); assert(__functions.emplace(unit->function.id(), f).second); return f; } PIFunction* TargetInterpretation::getFunction(PIFSignature&& sig){ auto f = __pifunctions.find(sig); if (f != __pifunctions.end()){ return f->second; } PIFunction* result = new PIFunction(PIFSignature(sig), __pifunctions.size(), this); __pifunctions.emplace(move(sig), result); assert(__dictFunctionsByUnit.emplace(result->functionUnit, result).second); return result; } InterpretationScope* TargetInterpretation::transformContext(const Context& c){ return this->getFunction(c.function)->getScope(c.scope->scope); } llvm::Value* TargetInterpretation::compile(const Expression& expression, const Context& ctx){ return transformContext(ctx)->compile(expression, ctx); } InterpretationFunction::InterpretationFunction(const ManagedFnPtr& function, Target* target) : Function(function, target) {} Expression InterpretationFunction::process(const std::vector& args){ InterpretationScope* body = getScope(__function->__entry); for(size_t i=0, size = args.size(); ioverrideBinding(args.at(i), string(body->scope->__bindings.at(i))); } return body->processScope(); } // Partial function interpretation typedef BasicFunctionUnit PIFunctionUnitParent; class PIFunctionUnit: public PIFunctionUnitParent{ public: PIFunctionUnit(ManagedFnPtr f, std::set&& arguments, size_t id, CompilePass* p) : PIFunctionUnitParent(f, p), argumentsActual(move(arguments)), __id(id) {} protected: std::vector prepareArguments(){ LLVMLayer* llvm = PIFunctionUnitParent::pass->man->llvm; AST* ast = PIFunctionUnitParent::pass->man->root; CodeScope* entry = PIFunctionUnitParent::function->__entry; std::vector signature; for(size_t no: argumentsActual){ VNameId argId = entry->__identifiers.at(entry->__bindings.at(no)); ScopedSymbol arg{argId, versions::VERSION_NONE}; signature.push_back(llvm->toLLVMType(ast->expandType(entry->__declarations.at(arg).type))); } return signature; } llvm::Function::arg_iterator prepareBindings(){ CodeScope* entry = PIFunctionUnitParent::function->__entry; ICodeScopeUnit* entryCompilation = PIFunctionUnitParent::getScopeUnit(entry); llvm::Function::arg_iterator fargsI = PIFunctionUnitParent::raw->arg_begin(); for(size_t no: argumentsActual){ ScopedSymbol arg{entry->__identifiers.at(entry->__bindings.at(no)), versions::VERSION_NONE}; entryCompilation->bindArg(&*fargsI, arg); fargsI->setName(entry->__bindings.at(no)); ++fargsI; } return fargsI; } virtual std::string prepareName(){ return PIFunctionUnitParent::prepareName() + "_" + std::to_string(__id); } private: std::set argumentsActual; size_t __id; }; PIFunction::PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target) : InterpretationFunction(sig.declaration, target), signatureInstance(move(sig)) { const FunctionInterpretationData& functionData = FunctionInterpretationHelper::getSignature(signatureInstance.declaration); std::set argumentsActual; for (size_t no=0, size=functionData.signature.size(); no < size; ++no){ if (functionData.signature.at(no) != INTR_ONLY){ argumentsActual.insert(no); } } functionUnit = new PIFunctionUnit(signatureInstance.declaration, move(argumentsActual), id, target->pass); CodeScope* entry = signatureInstance.declaration->__entry; auto entryUnit = Decorators::getInterface<>(functionUnit->getEntry()); InterpretationScope* entryIntrp = InterpretationFunction::getScope(entry); for(size_t no=0, sigNo=0, size = entry->__bindings.size(); no < size; ++no){ if (functionData.signature.at(no) == INTR_ONLY){ entryIntrp->overrideBinding(signatureInstance.bindings[sigNo], entry->__bindings[no]); VNameId argId = entry->__identifiers.at(entry->__bindings[no]); Symbol argSymbol{ScopedSymbol{argId, versions::VERSION_NONE}, entry}; entryUnit->overrideDeclaration(argSymbol, Expression(signatureInstance.bindings[sigNo])); ++sigNo; } } } llvm::Function* PIFunction::compile(){ llvm::Function* raw = functionUnit->compile(); return raw; } bool operator<(const PIFSignature& lhs, const PIFSignature& rhs){ if (lhs.declaration.id() != rhs.declaration.id()) { return lhs.declaration.id() < rhs.declaration.id(); } return lhs.bindings < rhs.bindings; } bool operator<(const PIFSignature& lhs, PIFunction* const rhs){ return lhs < rhs->signatureInstance; } bool operator<(PIFunction* const lhs, const PIFSignature& rhs){ return lhs->signatureInstance < rhs; } }} diff --git a/cpp/src/compilation/targetinterpretation.h b/cpp/src/compilation/targetinterpretation.h index 3a47bdd..5223763 100644 --- a/cpp/src/compilation/targetinterpretation.h +++ b/cpp/src/compilation/targetinterpretation.h @@ -1,130 +1,131 @@ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: targetstatic.h * Author: pgess * * Created on July 2, 2016, 1:25 PM */ #ifndef TARGETSTATIC_H #define TARGETSTATIC_H #include "ast.h" #include "pass/compilepass.h" #include "compilation/targets.h" #include "pass/interpretationpass.h" namespace xreate{ namespace interpretation{ class TargetInterpretation; class InterpretationScope; class InterpretationFunction; }} namespace xreate{ namespace compilation{ template <> struct TargetInfo { typedef Expression Result; typedef interpretation::InterpretationScope Scope; typedef interpretation::InterpretationFunction Function; }; }} namespace xreate{ namespace interpretation{ class InterpretationScope: public compilation::Scope{ typedef Scope Parent; public: InterpretationScope(CodeScope* scope, compilation::Function* f): Parent(scope, f) {} Expression process(const Expression& expression) override; llvm::Value* compile(const Expression& expression, const compilation::Context& context); private: llvm::Value* compileHybrid(const InterpretationOperator& op, const Expression& expression, const compilation::Context& context); //llvm::Value* compilePartialFnCall(const Expression& expression, const Context& context); CodeScope* processOperatorIf(const Expression& expression); CodeScope* processOperatorSwitch(const Expression& expression); + CodeScope* processOperatorSwitchVariant(const Expression& expression); }; class InterpretationFunction: public compilation::Function{ public: InterpretationFunction(const ManagedFnPtr& function, compilation::Target* target); Expression process(const std::vector& args); }; /* * Partially interpreted function signature */ struct PIFSignature{ ManagedFnPtr declaration; std::vector bindings; }; class PIFunctionUnit; class PIFunction: public InterpretationFunction{ public: PIFunctionUnit* functionUnit; PIFSignature signatureInstance; PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target); llvm::Function* compile(); }; bool operator<(const PIFSignature& lhs, PIFunction* const rhs); bool operator<(PIFunction* const lhs, const PIFSignature& rhs); class TargetInterpretation: public compilation::Target{ public: TargetInterpretation(AST* root, CompilePass* passCompilation): Target(root), pass(passCompilation){} //target: public: InterpretationFunction* getFunction(compilation::IFunctionUnit* unit); PIFunction* getFunction(PIFSignature&& sig); private: std::map __pifunctions; std::map __dictFunctionsByUnit; //self: public: CompilePass* pass; llvm::Value* compile(const Expression& expression, const compilation::Context& ctx); private: InterpretationScope* transformContext(const compilation::Context& c); }; template class InterpretationScopeDecorator: public Parent{ public: InterpretationScopeDecorator(CodeScope* codeScope, compilation::IFunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} virtual llvm::Value* process(const Expression& expr, const std::string& hintVarDecl){ const InterpretationData& data = Attachments::get(expr, {ANY, NONE}); bool flagInterpretationEligible = (data.resolution == INTR_ONLY || data.op != InterpretationOperator::NONE); if (flagInterpretationEligible){ compilation::Context ctx{this, this->function, this->pass}; return Parent::pass->targetInterpretation->compile(expr, ctx); } return Parent::process(expr, hintVarDecl); } }; }} //end of xreate:: interpretation #endif /* TARGETSTATIC_H */ //transformers: // template<> // struct TransformerInfo { // static const int id = 1; // }; \ No newline at end of file diff --git a/cpp/src/pass/interpretationpass.cpp b/cpp/src/pass/interpretationpass.cpp index b1bc4d4..09e7ac4 100644 --- a/cpp/src/pass/interpretationpass.cpp +++ b/cpp/src/pass/interpretationpass.cpp @@ -1,413 +1,448 @@ /* * File: interpretationpass.cpp * Author: pgess * * Created on July 5, 2016, 5:21 PM */ #include "pass/interpretationpass.h" //#include "compilation/transformations.h" #include +#include #include "ast.h" //DEBT implement InterpretationPass purely in clasp //DEBT represent InterpretationPass as general type inference using namespace std; namespace xreate{ template<> interpretation::InterpretationResolution defaultValue(){ return interpretation::CMPL_ONLY; } namespace interpretation{ enum InterpretationQuery{QUERY_INTR_ONLY, QUERY_CMPL_ONLY}; namespace details { template bool checkConstraints(InterpretationResolution flag) { return ( (flag==INTR_ONLY && FLAG_REQUIRED == QUERY_INTR_ONLY) || (flag==CMPL_ONLY && FLAG_REQUIRED == QUERY_CMPL_ONLY)); } InterpretationResolution recognizeTags(const map& tags){ auto i = tags.find("interpretation"); if (i== tags.end()){ return ANY; } assert(i->second.op == Operator::CALL); const string& cmd = i->second.operands.at(0).getValueString(); //TODO make consistent names of annotation and resolution if (cmd == "force"){ return INTR_ONLY; } else if (cmd == "suppress"){ return CMPL_ONLY; } return ANY; } } InterpretationResolution unify(InterpretationResolution flag) { return flag; } template InterpretationResolution unify(FLAG_A flagA, FLAG_B flagB, FLAGS... flags) { if (flagA== ANY){ return unify(flagB, flags...); } if (flagB == ANY) { return unify(flagA, flags...); } assert(flagA == flagB); return flagA; } template bool checkConstraints(std::vector&& flags) { assert(flags.size()); InterpretationResolution flag = flags.front(); return details::checkConstraints(flag); } template bool checkConstraints(std::vector&& flags) { assert(flags.size()); InterpretationResolution flag = flags.front(); flags.pop_back(); if (details::checkConstraints(flag)){ return checkConstraints(move(flags)); } return false; } bool InterpretationData::isDefault() const{ return (resolution == ANY && op == NONE); } void recognizeTags(const Expression& e){ InterpretationData tag{details::recognizeTags(e.tags), NONE}; if (!tag.isDefault()) Attachments::put(e, tag); } InterpretationResolution recognizeTags(const ManagedFnPtr& f){ return details::recognizeTags(f->getTags()); } InterpretationPass::InterpretationPass(PassManager* manager) : AbstractPass(manager) { Attachments::init(); Attachments::init(); } void InterpretationPass::run(){ ManagedFnPtr f = man->root->begin(); auto& visitedSymbols = getSymbolCache(); while (f.isValid()) { const Symbol& symbolFunction{ScopedSymbol::RetSymbol, f->getEntryScope()}; if (!visitedSymbols.isCached(symbolFunction)){ visitedSymbols.setCachedValue(symbolFunction, process(f)); } ++f; } } InterpretationResolution InterpretationPass::process(const Expression& expression, PassContext context, const std::string& decl){ recognizeTags(expression); InterpretationResolution resolution = ANY; InterpretationOperator op = NONE; switch (expression.__state){ case Expression::NUMBER: case Expression::STRING: { break; } case Expression::IDENT: { resolution = Parent::processSymbol(Attachments::get(expression), context); break; } case Expression::COMPOUND: break; default: { resolution = CMPL_ONLY; break;} } if (expression.__state == Expression::COMPOUND) switch(expression.op){ case Operator::EQU: case Operator::NE: { InterpretationResolution left = process(expression.operands[0], context); InterpretationResolution right = process(expression.operands[1], context); resolution = unify(left, right); break; } case Operator::LOGIC_AND: { assert(expression.operands.size() == 1); resolution = process (expression.operands[0], context); break; } case Operator::CALL: { //TODO cope with static/dynamic context //TODO BUG here: if several variants they all are processed as CMPL careless of signature list callees = man->root->getFunctionVariants(expression.getValueString()); if (callees.size()!=1){ resolution = CMPL_ONLY; break; } ManagedFnPtr callee = callees.front(); const Symbol& symbCalleeFunc{ScopedSymbol::RetSymbol, callee->getEntryScope()}; //recursion-aware processing: // - skip self recursion const Symbol& symbSelfFunc{ScopedSymbol::RetSymbol, context.function->getEntryScope()}; if (!(symbSelfFunc == symbCalleeFunc)){ InterpretationResolution resCallee = processFnCall(callee, context); assert(resCallee != FUNC_POSTPONED && "Indirect recursion detected: can't decide on interpretation resolution"); resolution = unify(resolution, resCallee); } //check arguments compatibility const FunctionInterpretationData& calleeSignature = FunctionInterpretationHelper::getSignature(callee); for (size_t op=0, size = expression.operands.size(); op < size; ++op){ const Expression &operand = expression.operands[op]; InterpretationResolution argActual = process(operand, context); InterpretationResolution argExpected = calleeSignature.signature[op]; //TODO use args unification result to properly process function call unify(argActual, argExpected); } if (FunctionInterpretationHelper::needPartialInterpretation(callee)){ op= CALL_INTERPRET_PARTIAL; } break; } case Operator::IF:{ InterpretationResolution flagCondition = process(expression.getOperands()[0], context); InterpretationResolution flagScope1 = Parent::process(expression.blocks.front(), context); InterpretationResolution flagScope2 = Parent::process(expression.blocks.back(), context); //special case: IF_INTERPRET_CONDITION if (checkConstraints({flagCondition})){ op= IF_INTERPRET_CONDITION; flagCondition = ANY; } resolution = unify(flagCondition, flagScope1, flagScope2); break; } case Operator::FOLD: { InterpretationResolution flagInput = process(expression.getOperands()[0], context); InterpretationResolution flagAccumInit = process(expression.getOperands()[1], context); CodeScope* scopeBody = expression.blocks.front(); const std::string& nameEl = expression.bindings[0]; Symbol symbEl{ScopedSymbol{scopeBody->__identifiers.at(nameEl), versions::VERSION_NONE}, scopeBody}; getSymbolCache().setCachedValue(symbEl, InterpretationResolution(flagInput)); const std::string& nameAccum = expression.bindings[1]; Symbol symbAccum{ScopedSymbol{scopeBody->__identifiers.at(nameAccum), versions::VERSION_NONE}, scopeBody}; getSymbolCache().setCachedValue(symbAccum, InterpretationResolution(flagAccumInit)); InterpretationResolution flagBody = Parent::process(expression.blocks.front(), context); //special case: FOLD_INTERPRET_INPUT if (checkConstraints({flagInput})){ op= FOLD_INTERPRET_INPUT; flagInput = ANY; } resolution = unify(flagInput, flagAccumInit, flagBody); break; } case Operator::INDEX: { resolution = unify( process(expression.operands[0], context), process(expression.operands[1], context) ); break; } case Operator::SWITCH: { InterpretationResolution flagCondition = process(expression.operands[0], context); bool hasDefaultCase = expression.operands[1].op == Operator::CASE_DEFAULT; //determine conditions resolution InterpretationResolution flagHeaders = flagCondition; for (size_t size = expression.operands.size(), i= hasDefaultCase? 2: 1; i({flagHeaders})){ op= SWITCH_INTERPRET_CONDITION; flagHeaders = ANY; } //determine body resolutions resolution = flagHeaders; for (size_t size = expression.operands.size(), i= 1; i({resolution})){ + op= SWITCH_VARIANT; + resolution = ANY; + } + + const string identCondition = expression.operands.at(0).getValueString(); + for(auto scope: expression.blocks){ + //set binding resolution + ScopedSymbol symbolInternal = scope->getSymbol(identCondition); + getSymbolCache().setCachedValue(Symbol{symbolInternal, scope}, InterpretationResolution(resolutionCondition)); + + resolution = unify(resolution, Parent::process(scope, context)); + } + + for(auto scope: expression.blocks){ + resolution = unify(resolution, Parent::process(scope, context)); + } + break; + } + case Operator::LIST: case Operator::LIST_NAMED: { for (const Expression &op: expression.getOperands()) { resolution = unify(resolution, process(op, context)); } break; } + case Operator::VARIANT: { + if(expression.getOperands().size()){ + resolution = process(expression.getOperands().front(), context); + } else { + resolution = ANY; + } + + break; + } + default: { resolution = CMPL_ONLY; for (const Expression &op: expression.getOperands()) { process(op, context); } for (CodeScope* scope: expression.blocks) { Parent::process(scope, context); } break; } } InterpretationResolution resolutionExpected = Attachments::get(expression, {ANY, NONE}).resolution; resolution = unify(resolution, resolutionExpected); if (resolution != resolutionExpected && (op!=NONE || resolution == INTR_ONLY)){ Attachments::put(expression, {resolution, op}); } return resolution; } InterpretationResolution InterpretationPass::processFnCall(ManagedFnPtr function, PassContext context){ return process(function); } InterpretationResolution InterpretationPass::process(ManagedFnPtr function){ CodeScope* entry = function->getEntryScope(); std::vector arguments = entry->__bindings; const Symbol& symbSelfFunc{ScopedSymbol::RetSymbol, function->getEntryScope()}; auto& cache = getSymbolCache(); if (cache.isCached(symbSelfFunc)) return cache.getCachedValue(symbSelfFunc); const FunctionInterpretationData& fnSignature = FunctionInterpretationHelper::getSignature(function); InterpretationResolution fnResolutionExpected = details::recognizeTags(function->getTags()); //mark preliminary function resolution as expected if (fnResolutionExpected != ANY){ cache.setCachedValue(symbSelfFunc, move(fnResolutionExpected)); } else { // - in order to recognize indirect recursion mark this function resolution as POSTPONED cache.setCachedValue(symbSelfFunc, FUNC_POSTPONED); } //set resolution for function arguments as expected for (int argNo = 0, size = arguments.size(); argNo< size; ++argNo){ Symbol symbArg{ScopedSymbol{entry->__identifiers.at(arguments[argNo]), versions::VERSION_NONE}, entry}; cache.setCachedValue(symbArg, InterpretationResolution(fnSignature.signature[argNo])); } PassContext context; context.function = function; context.scope = entry; InterpretationResolution resActual = process(CodeScope::getDeclaration(symbSelfFunc), context); resActual = unify(resActual, fnResolutionExpected); return cache.setCachedValue(symbSelfFunc, move(resActual)); } const FunctionInterpretationData FunctionInterpretationHelper::getSignature(ManagedFnPtr function){ if (Attachments::exists(function)){ return Attachments::get(function); } FunctionInterpretationData&& data = recognizeSignature(function); Attachments::put(function, data); return data; } FunctionInterpretationData FunctionInterpretationHelper::recognizeSignature(ManagedFnPtr function){ CodeScope* entry = function->__entry; FunctionInterpretationData result; result.signature.reserve(entry->__bindings.size()); bool flagPartialInterpretation = false; for(size_t no=0, size=entry->__bindings.size(); no < size; ++no){ const std::string& argName = entry->__bindings[no]; Symbol symbArg{ScopedSymbol{entry->__identifiers.at(argName), versions::VERSION_NONE}, entry}; const Expression& arg = CodeScope::getDeclaration(symbArg); InterpretationResolution argResolution = details::recognizeTags(arg.tags); flagPartialInterpretation |= (argResolution == INTR_ONLY); result.signature.push_back(argResolution); } result.flagPartialInterpretation = flagPartialInterpretation; return result; } bool FunctionInterpretationHelper::needPartialInterpretation(ManagedFnPtr function){ const FunctionInterpretationData& data = getSignature(function); return data.flagPartialInterpretation; } }} //end of namespace xreate::interpretation diff --git a/cpp/src/pass/interpretationpass.h b/cpp/src/pass/interpretationpass.h index e418055..5a2b229 100644 --- a/cpp/src/pass/interpretationpass.h +++ b/cpp/src/pass/interpretationpass.h @@ -1,85 +1,87 @@ /* * File: interpretationpass.h * Author: pgess * * Created on July 5, 2016, 5:21 PM */ #ifndef INTERPRETATIONPASS_H #define INTERPRETATIONPASS_H #include "abstractpass.h" #include #ifndef FRIENDS_INTERPRETATION_TESTS #define FRIENDS_INTERPRETATION_TESTS #endif +//TODO refactor interpretation. Get rid of InterpretationOperator, put only one operator - Hybrid. + namespace xreate{ namespace interpretation{ enum InterpretationResolution{ANY, INTR_ONLY, CMPL_ONLY, FUNC_POSTPONED}; - enum InterpretationOperator{NONE, IF_INTERPRET_CONDITION, FOLD_INTERPRET_INPUT, SWITCH_INTERPRET_CONDITION, CALL_INTERPRET_PARTIAL}; + enum InterpretationOperator{NONE, IF_INTERPRET_CONDITION, FOLD_INTERPRET_INPUT, SWITCH_INTERPRET_CONDITION, SWITCH_VARIANT, CALL_INTERPRET_PARTIAL}; struct InterpretationData{ InterpretationResolution resolution; InterpretationOperator op; bool isDefault() const; }; struct FunctionInterpretationData{ typedef std::vector Signature; Signature signature; bool flagPartialInterpretation; }; class FunctionInterpretationHelper { public: static const FunctionInterpretationData getSignature(ManagedFnPtr function); static bool needPartialInterpretation(ManagedFnPtr function); private: static FunctionInterpretationData recognizeSignature(ManagedFnPtr function); }; class InterpretationPass: public AbstractPass { typedef AbstractPass Parent; public: InterpretationResolution process(const Expression& expression, PassContext context, const std::string& varDecl="") override; InterpretationResolution process(ManagedFnPtr function); InterpretationResolution processFnCall(ManagedFnPtr function, PassContext context); InterpretationPass(PassManager* manager); void run(); }; namespace details { InterpretationResolution recognizeTags(const std::map& tags); } } //end of namespace interpretation template<> interpretation::InterpretationResolution defaultValue(); template<> struct AttachmentsDict { typedef interpretation::FunctionInterpretationData Data; static const unsigned int key = 5; }; template<> struct AttachmentsDict { typedef interpretation::InterpretationData Data; static const unsigned int key = 3; }; } //end of namespace xreate #endif /* INTERPRETATIONPASS_H */ diff --git a/cpp/src/query/containers.cpp b/cpp/src/query/containers.cpp index 1243cff..62a108e 100644 --- a/cpp/src/query/containers.cpp +++ b/cpp/src/query/containers.cpp @@ -1,165 +1,167 @@ // // Created by pgess on 3/14/15. // #include #include "query/containers.h" using namespace std; using namespace xreate::containers; using namespace xreate; Implementation Query::queryImplementation(xreate::Symbol const &s) { if (Attachments::exists(s)) { return Attachments::get(s); } return Implementation::create(s); } Query::Query(){ Attachments::init(); } void Query::init(ClaspLayer* clasp) { if (flagIsDataLoaded) return; map prototypes; map roots; //read all proto data auto range = clasp->query(Config::get("containers.id.prototypes")); if (range) for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) { auto data = ClaspLayer::parse(atom->second); Symbol root = clasp->unpack(get<0> (data)); Symbol prototype = clasp->unpack(get<1> (data)); prototypes[root] = prototype; } // fill implementation data for a data sources: range = clasp->query(Config::get("containers.id.implementations")); if (range) for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) { auto data = ClaspLayer::parse(atom->second); Symbol var = clasp->unpack(get<0>(data)); string implSerialized = get<1>(data); //data source, has no prototypes: if (!prototypes.count(var)) { Implementation impl = Implementation::create(var); Attachments::put(var, move(impl)); continue; } roots.emplace(move(var), move(implSerialized)); } //fill implementation data for a cluster roots for (const pair & root: roots) { Symbol prototype = prototypes[root.first]; while (prototypes.count(prototype)) { prototype = prototypes.at(prototype); } Attachments::put(root.first, Implementation(Attachments::get(prototype))); } // read cluster data and fill implementation data for cluster members range = clasp->query(Config::get("containers.id.clusters")); if (range) for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) { auto info = ClaspLayer::parse(atom->second); Symbol root = clasp->unpack(get<0>(info)); Symbol child = clasp->unpack(get<1>(info)); if (!(child == root) && (Attachments::exists(root))) { Implementation rootImpl = Attachments::get(root); Attachments::put(child, move(rootImpl)); } } flagIsDataLoaded = true; } //static ImplementationData* create(Symbol var, std::string implSerialized, const ImplementationData* implPrototype); Implementation Implementation::create(const Symbol &var) { //TODO review implementation determination strategy Expression varDecl = CodeScope::getDeclaration(var); switch (varDecl.op) { case Operator::LIST_RANGE: { ImplementationRec rec{var}; return {ON_THE_FLY, rec}; } case Operator::LIST: { return {SOLID, ImplementationRec {varDecl.getOperands().size()}}; } default: break; }; ImplementationLinkedList ill(var); if (ill){ return ill.getImplementationData(); } assert(false && "Unable to determine proper implementation for the symbol"); + return Implementation(); } Implementation Implementation::create(const Symbol& var, const std::string& implSerialized) { Expression varDecl = CodeScope::getDeclaration(var); if (implSerialized == Config::get("containers.impl.solid")) { return {SOLID, ImplementationRec{varDecl.operands.size()}}; } else if (implSerialized == Config::get("containers.impl.onthefly")) { return {ON_THE_FLY, ImplementationRec{var}}; } assert(false && "unable to determine proper implementation for the symbol"); + return Implementation(); } ImplementationLinkedList::ImplementationLinkedList(const Symbol& source) : flagIsValid(false), s(source){ const Expression& sourceExpr = CodeScope::getDeclaration(source); if (sourceExpr.tags.count(Config::get("containers.id.linkedlist"))){ flagIsValid = true; Expression tagLinkedlist = sourceExpr.tags.at(Config::get("containers.id.linkedlist")); assert(tagLinkedlist.operands.size() == 2); fieldPointer = tagLinkedlist.operands.at(0).getValueString(); terminator = tagLinkedlist.operands.at(1); } } ImplementationLinkedList:: operator bool () const{ return flagIsValid; } Implementation ImplementationLinkedList::getImplementationData() const { return {ON_THE_FLY, ImplementationRec{s}}; } diff --git a/cpp/src/query/containers.h b/cpp/src/query/containers.h index 1991f66..b06b486 100644 --- a/cpp/src/query/containers.h +++ b/cpp/src/query/containers.h @@ -1,84 +1,84 @@ // // Created by pgess on 3/14/15. // #ifndef _XREATE_CONTAINERSQUERY_H_ #define _XREATE_CONTAINERSQUERY_H_ #include "xreatemanager.h" #include "clasplayer.h" #include namespace xreate { namespace containers { enum ImplementationType {SOLID, ON_THE_FLY, LINKED_LIST}; template struct ImplementationRec; template<> struct ImplementationRec { size_t size; }; template<> struct ImplementationRec{ Symbol source; }; struct Implementation; struct ImplementationLinkedList { bool flagIsValid; std::string fieldPointer; Expression terminator; ImplementationLinkedList(const Symbol& source); operator bool() const; Implementation getImplementationData() const; private: Symbol s; }; struct Implementation { typedef boost::variant, ImplementationRec> Variant; - const ImplementationType impl; + ImplementationType impl; Variant data; static Implementation create(const Symbol &var); static Implementation create(const Symbol& var, const std::string &implSerialized); static Implementation create(const Symbol& var, const Implementation& proto); template const ImplementationRec& extract() const{ const ImplementationRec& rec = boost::get>(data); return rec; } }; class Query : public xreate::IQuery { public: static Implementation queryImplementation(xreate::Symbol const &s); void init(ClaspLayer* clasp); Query(); ~Query(){} private: bool flagIsDataLoaded = false; PassManager *man; }; } template<> struct AttachmentsDict { typedef containers::Implementation Data; static const unsigned int key = 1; }; } #endif //_XREATE_CONTAINERSQUERY_H_ diff --git a/cpp/tests/ast.cpp b/cpp/tests/ast.cpp index 193b68a..b6f3514 100644 --- a/cpp/tests/ast.cpp +++ b/cpp/tests/ast.cpp @@ -1,69 +1,88 @@ /* * ast.cpp * * Created on: Jun 11, 2015 * Author: pgess */ #include "gtest/gtest.h" #include "xreatemanager.h" #include "main/Parser.h" using namespace std; using namespace xreate; using namespace xreate::grammar::main; TEST(AST, Containers1){ FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r"); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); assert(!parser.errors->count && "Parser errors"); fclose(input); } TEST(AST, InterfacesDataCFA) { XreateManager* man = XreateManager::prepare ("interface(cfa){\n" " operator map :: annotation1.\n" "}"); auto answer = man->root->__interfacesData.equal_range(CFA); EXPECT_EQ(1, std::distance(answer.first, answer.second)); Expression&& scheme = move(answer.first->second); EXPECT_EQ(Operator::MAP, scheme.op); EXPECT_EQ("annotation1", scheme.getOperands().at(0).getValueString()); } TEST(AST, syntax_recognizeIdentifiers){ XreateManager* man = XreateManager::prepare(R"Code( test= function(a:: num):: num; entry { a = b:: int. b = 8:: int. a } )Code"); } TEST(AST, syntax_operatorIndex){ XreateManager* man = XreateManager::prepare(R"Code( test= function(a:: num):: num; entry { b = a[1]. b } )Code"); } +TEST(AST, Variants_switch){ +XreateManager* man = XreateManager::prepare(R"Code( + Color = type variant{Blue, White, Green}. + + main = function:: int { + x = White()::Color. + + switch variant(x)::int + case (Green) {0} + case (White) {1} + case (Blue){2} + } +)Code"); + + Expression e= man->root->findFunction("main")->getEntryScope()->getBody(); + ASSERT_EQ(4, e.getOperands().size()); + ASSERT_EQ(3, e.blocks.size()); +} + TEST(AST, DISABLED_InterfacesDataDFA){ } TEST(AST, DISABLED_InterfacesDataExtern){ } //TODO xreate.atg: replace all Type<> as ExprAnnotations<> diff --git a/cpp/tests/compilation.cpp b/cpp/tests/compilation.cpp index 18b8705..607e408 100644 --- a/cpp/tests/compilation.cpp +++ b/cpp/tests/compilation.cpp @@ -1,95 +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" + "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" + " 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 { + Rec = type { 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/interpretation.cpp b/cpp/tests/interpretation.cpp index 1eb60fc..5cc7e99 100644 --- a/cpp/tests/interpretation.cpp +++ b/cpp/tests/interpretation.cpp @@ -1,384 +1,411 @@ #include "attachments.h" using namespace xreate; #include "xreatemanager.h" #include "compilation/targetinterpretation.h" #include "gtest/gtest.h" #include "boost/scoped_ptr.hpp" //#define FRIENDS_INTERPRETATION_TESTS \ // friend class ::Modules_AST2_Test; \ // friend class ::Modules_Discovery1_Test; \ // friend class ::Modules_Solve1_Test; #include "pass/interpretationpass.h" using namespace xreate::grammar::main; using namespace xreate::interpretation; TEST(Interpretation, Analysis_StatementIF_1){ XreateManager* man = XreateManager::prepare( R"Code( main = function::bool { x = "a":: string. y = if (x=="b"):: bool; interpretation(force) { true } else { false }. y } )Code" ); InterpretationPass* pass = new InterpretationPass(man); pass->run(); CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope(); Symbol symbolY{scopeEntry->getSymbol("y"), scopeEntry}; InterpretationData& dataSymbolY = Attachments::get(symbolY); ASSERT_EQ(INTR_ONLY, dataSymbolY.resolution); } TEST(Interpretation, Compilation_StatementIF_1){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( main = function::int; entry { x = "a":: string. y = if (x=="b"):: string; interpretation(force) { 1 } else { 0 }. y } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(0, result); } TEST(Interpretation, Analysis_StatementIF_InterpretCondition_1){ XreateManager* man = XreateManager::prepare( R"Code( main = function(x:: int):: int { comm= "inc":: string; interpretation(force). y = if (comm == "inc")::int {x+1} else {x}. y } )Code" ); InterpretationPass* pass = new InterpretationPass(man); pass->run(); CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope(); Symbol symbolY{scopeEntry->getSymbol("y"), scopeEntry}; InterpretationData& dataSymbolY = Attachments::get(symbolY); ASSERT_EQ(CMPL_ONLY, dataSymbolY.resolution); ASSERT_EQ(IF_INTERPRET_CONDITION, dataSymbolY.op); } TEST(Interpretation, Compilation_StatementIF_InterpretCondition_1){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( main = function(x:: int):: int; entry { comm= "inc":: string; interpretation(force). y = if (comm == "inc")::int {x+1} else {x}. y } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } int (*main)(int) = (int (*)(int))man->run(); int result = main(1); ASSERT_EQ(2, result); } TEST(Interpretation, Compilation_StatementFOLD_INTERPRET_INPUT_1){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( main = function(x:: int):: int; entry { commands = ["inc", "double", "dec"]:: [string]; interpretation(force). loop fold(commands->comm::string, x->operand):: int{ switch(comm)::int case ("inc"){ operand + 1 } case ("dec"){ operand - 1 } case ("double"){ operand * 2 } } } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } const ManagedFnPtr& funcMain = man->root->findFunction("main"); InterpretationData& dataBody = Attachments::get(funcMain); ASSERT_EQ(FOLD_INTERPRET_INPUT, dataBody.op); int (*main)(int) = (int (*)(int))man->run(); int result = main(10); ASSERT_EQ(21, result); } TEST(Interpretation, StatementCall_RecursionNo_1){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( unwrap = function(data::undef, keys::undef):: undef; interpretation(force){ loop fold(keys->key::string, data->a):: undef { a[key] } } start = function::num; entry{ result = unwrap( { a = { b = { c = "core" } } }, ["a", "b", "c"])::undef. result == "core" } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(1, result); } TEST(Interpretation, StatementCall_RecursionDirect_1){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( unwrap = function(data:: X):: Y { if (data[0] == "a")::Y {0} else {unwrap(data[0])} } entry = function:: i8; entry { unwrap([[[["a"]]]]):: i8; interpretation(force) } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } InterpretationResolution resolutionActual = pass->process(man->root->findFunction("unwrap")); ASSERT_EQ(ANY, resolutionActual); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(0, result); } TEST(Interpretation, StatementCall_RecursionIndirect_1){ XreateManager* man = XreateManager::prepare( R"Code( funcA = function(data:: X):: Y { if (data == "a")::Y {0} else {funcB(data)} } funcB = function(data:: X):: Y { if (data == "b")::Y {1} else {funcA(data)} } entry = function:: i8; entry { funcA(""):: i8; interpretation(force) } )Code" ); InterpretationPass* pass = new InterpretationPass(man); ASSERT_DEATH(pass->run(), "Indirect recursion detected"); } TEST(Interpretation, PartialIntr_1){ XreateManager* man = XreateManager::prepare( R"Code( evaluate= function(argument:: num, code:: string; interpretation(force)):: num { switch(code)::int case ("inc") {argument + 1} case ("dec") {argument - 1} case ("double") {argument * 2} } main = function::int; entry { commands= ["inc", "double", "dec"]:: [string]; interpretation(force). loop fold(commands->comm::string, 10->operand):: int{ evaluate(operand, comm) } } )Code" ); InterpretationPass* pass = new InterpretationPass(man); pass->run(); ManagedFnPtr fnEvaluate = man->root->findFunction("evaluate"); InterpretationResolution resFnEvaluate= pass->process(fnEvaluate); ASSERT_EQ(CMPL_ONLY, resFnEvaluate); ASSERT_TRUE(FunctionInterpretationHelper::needPartialInterpretation(fnEvaluate)); const Expression& exprLoop = man->root->findFunction("main")->__entry->getBody(); Symbol symbCallEv{{0, versions::VERSION_NONE}, exprLoop.blocks.front()}; InterpretationData dataCallEv = Attachments::get(symbCallEv); ASSERT_EQ(CMPL_ONLY, dataCallEv.resolution); ASSERT_EQ(CALL_INTERPRET_PARTIAL, dataCallEv.op); } TEST(Interpretation, Compilation_PartialIntr_2){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( evaluate= function(argument:: num, code:: string; interpretation(force)):: num { switch(code)::int case ("inc") {argument + 1} case ("dec") {argument - 1} case ("double") {argument * 2} case default {argument} } main = function::int; entry { commands= ["inc", "double", "dec"]:: [string]; interpretation(force). loop fold(commands->comm::string, 10->operand):: int{ evaluate(operand, comm) } } )Code" ); man->analyse(); if (!man->isPassRegistered(PassId::InterpretationPass)){ InterpretationPass* pass = new InterpretationPass(man); pass->run(); } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(21, result); } TEST(Interpretation, PartialIntr_3){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( - Command= type variant (INC, DEC, DOUBLE). + Command= type variant {INC, DEC, DOUBLE}. evaluate= function(argument:: num, code:: Command; interpretation(force)):: num { - switch(code)::int + switch variant(code)::int case (INC) {argument + 1} case (DEC) {argument - 1} case (DOUBLE) {argument * 2} - case default {argument} } main = function::int; entry { - commands= [INC, DOUBLE, DEC]:: [Command]; interpretation(force). + commands= [INC(), DOUBLE(), DEC()]:: [Command]; interpretation(force). loop fold(commands->comm::Command, 10->operand):: int{ evaluate(operand, comm) } } )Code" ); man->analyse(); if (!man->isPassRegistered(PassId::InterpretationPass)){ InterpretationPass* pass = new InterpretationPass(man); pass->run(); } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(21, result); } +TEST(Interpretation, SwitchVariant){ + xreate::XreateManager* man = xreate::XreateManager::prepare( +R"Code( +OneArgument = type{x::int}. +TWoArgument = type {x::int, y::int}. + +Command= type variant { + ADD::TwoArguments, + DEC:: OneArgument, + DOUBLE::OneArgument +}. + +main = function::int; entry{ + program = ADD({x=2, y=3})::Command; interpretation(force). + + switch variant(program)::int + case (ADD) {program["x"]+program["y"]} + case (DEC) {1} + case (DOUBLE) {2} +} +)Code" ); + + int (*main)() = (int (*)())man->run(); + int result = main(); + ASSERT_EQ(5, result); + +} + TEST(InterpretationExamples, Regexp1){ FILE* input = fopen("scripts/dsl/regexp.xreate","r"); assert(input != nullptr); std::unique_ptr man(XreateManager::prepare(input)); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(4, result); } //TOTEST call indirect recursion(w/o tags) //TASk implement and test Loop Inf (fix acc types in coco grammar) diff --git a/grammar/xreate.ATG b/grammar/xreate.ATG index bdd885d..11b2fa1 100644 --- a/grammar/xreate.ATG +++ b/grammar/xreate.ATG @@ -1,626 +1,639 @@ //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)){ 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 ] . + ) 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 | TVariant | TypeTerm (. typ = typ3; .) | IF (checkIndex()) Ident lbrack Ident (. typ = TypeAnnotation(TypeOperator::ACCESS, {}); typ.__valueCustom = Atom(tid).get(); typ.fields.push_back(Atom(field).get()); .) {',' Ident (. typ.fields.push_back(Atom(field).get()); .) } rbrack | Ident (. typ = TypeAnnotation(TypeOperator::CUSTOM, {}); typ.__valueCustom = Atom(tid).get(); .) ['(' Type (. typ.__operator = TypeOperator::CALL; typ.__operands.push_back(typ2); .) {',' Type (. typ.__operands.push_back(typ2); .) } ')'] ) . TList = (. TypeAnnotation ty; .) '[' Type ']' (. typ = TypeAnnotation(TypeOperator::ARRAY, {ty}); .) . TStruct = (. TypeAnnotation t; std::wstring key; size_t keyCounter=0; .) lcurbrack ( IF(checkTokenAfterIdent(_tagcolon)) Ident tagcolon Type | Type (. key = to_wstring(keyCounter++); .) ) (. typ = TypeAnnotation(TypeOperator::STRUCT, {t}); typ.fields.push_back(Atom(key).get()); .) {',' ( IF(checkTokenAfterIdent(_tagcolon)) Ident tagcolon Type | Type (. key = to_wstring(keyCounter++); .) ) (. typ.__operands.push_back(t); typ.fields.push_back(Atom(key).get()); .) } rcurbrack. TVariant= (. TypeAnnotation t, typVoid(TypeOperator::STRUCT, {}); std::vector operands; std::vector> keys; std::wstring variant; .) "variant" lcurbrack Ident (. t=typVoid; .) [tagcolon Type] (. keys.push_back(Atom(variant)); operands.push_back(t); .) {',' Ident (. t=typVoid; .) [tagcolon Type] (. keys.push_back(Atom(variant)); operands.push_back(t); .) } rcurbrack (. typ = TypeAnnotation(TypeOperator::VARIANT, {}); typ.__operands = operands; typ.addFields(std::move(keys)); .) . TDecl = (. TypeAnnotation t; std::wstring tname, arg; std::vector> args; .) Ident assign "type" ['(' Ident (. args.push_back(Atom(arg)); .) {',' Ident (. args.push_back(Atom(arg)); .) } ')'] Type'.' (. t.addBindings(move(args)); root->add(move(t), Atom(tname)); .) . 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)); .) . BDecl = lcurbrack (. Expression body; pushContextScope(scope); .) {(IF(checkAssignment()) VDecl '.' | RuleContextDecl | ContextDecl'.' | ExprTyped (. scope->setBody(body); .) )} rcurbrack (. popContextScope(); .) . IfDecl = (. Expression cond; ManagedScpPtr blockTrue = root->add(new CodeScope(context.scope)); ManagedScpPtr blockFalse = root->add(new CodeScope(context.scope)); .) "if" '(' Expr ')' (. e = Expression(Operator::IF, {cond}); .) tagcolon ExprAnnotations BDecl<&*blockTrue> "else" BDecl<&*blockFalse> (. e.addBlock(blockTrue); e.addBlock(blockFalse); .) . LoopDecl = (. Expression eIn, eAcc, eFilters; std::wstring varEl, varAcc, contextClass; Expression tagsEl; ManagedScpPtr block = root->add(new CodeScope(context.scope)); .) "loop" ("map" '(' Expr implic Ident (. e = Expression(Operator::MAP, {eIn}); .) tagcolon ExprAnnotations ')' tagcolon ExprAnnotations BDecl<&*block> (. e.addBindings({Atom(varEl)}); block->addBinding(Atom(varEl), move(tagsEl)); e.addBlock(block); .) |"fold" ("inf" '(' Expr implic Ident ')' (. e = Expression(Operator::FOLD_INF, {eAcc}); e.addBindings({Atom(varAcc)}); .) tagcolon ExprAnnotations BDecl<&*block> (. block->addBinding(Atom(varAcc), Expression()); e.addBlock(block); .) | '(' Expr implic Ident tagcolon ExprAnnotations ['|' Expr ] ',' Expr implic Ident')' (. e = Expression(Operator::FOLD, {eIn, eAcc}); e.addBindings({Atom(varEl), Atom(varAcc)}); .) - tagcolon ExprAnnotations BDecl<&*block> + tagcolon ExprAnnotations (. - block->addBinding(Atom(varEl), move(tagsEl)); block->addBinding(Atom(varAcc), Expression()); - e.addBlock(block); .) + BDecl<&*block> + (. e.addBlock(block); .) ) | "context" '(' string (. contextClass = t->val; .) ')' BDecl<&*block> (. e = Expression(Operator::LOOP_CONTEXT, {Expression(Atom(std::move(contextClass)))}); e.addBlock(block); .) ). +// Switches 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; .) +"switch" + ( + SwitchVariantDecl | lparen Expr rparen tagcolon ExprAnnotations (. eSwitch.operands.push_back(eCondition);.) - ) -] - CaseDecl {CaseDecl} + 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(); .) . +SwitchVariantDecl = + (. Expression varTested; expr = Expression(Operator::SWITCH_VARIANT, {}); .) + + "variant" lparen VarIdent rparen tagcolon ExprAnnotations + (. recognizeIdentifier(varTested); expr.addArg(std::move(varTested)); .) + + CaseVariantDecl {CaseVariantDecl} +. + +CaseVariantDecl = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); std::wstring key; scope->addBinding(Expression(expr.operands.at(0)), Expression()); .) + "case" lparen Ident rparen (. expr.addArg(root->recognizeVariantConstructor(Atom(std::move(key)))); .) + BDecl<&*scope> (. expr.addBlock(scope); .) +. + IntrinsicDecl= (. std::wstring name; .) "intrinsic" Ident< name> (. outer = Expression(Operator::CALL_INTRINSIC, {}); outer.setValue(Atom(name)); .) lparen [CalleeParams] rparen . /*============================ 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(Operator::CALL, {Atom(i1)}); .) ). MetaCalleeParams = (. Expression e2; .) MetaSimpExpr (. e.addArg(Expression(e2)); .) {',' MetaSimpExpr (. e.addArg(Expression(e2)); .) }. RBody = (. Expression e; std::wstring msg; .) "warning" MetaExpr ["message" string (. msg = t->val; .) ] (. root->add(new RuleWarning(RuleArguments(args), RuleGuards(guards), std::move(e), Atom(msg))); .) . MetaOp< Operator& op> = implic (. op = Operator::IMPL; .) . /*============================ Expressions ===============================*/ ExprAnnotations = (. TypeAnnotation typ; std::list tags; Expression tag; e.tags.clear();.) Type (. e.bindType(move(typ)); .) {';' MetaSimpExpr (. tags.push_back(tag); .) } (. e.addTags(tags); .) . ExprTyped = Expr [tagcolon ExprAnnotations]. Expr< Expression& e> (. Operator op; Expression e2; .) = ExprArithmAdd [ RelOp ExprArithmAdd (. e = Expression(op, {e, e2}); .) ]. ExprArithmAdd< Expression& e>= (. Operator op; Expression e2; .) ExprArithmMul< e> [ AddOp< op> ExprArithmAdd< e2> (. e = Expression(op, {e, e2});.) ]. ExprArithmMul< Expression& e> (. Operator op; Expression e2; .) = ExprPostfix< e> [ MulOp< op> ExprArithmMul< e2> (. e = Expression(op, {e, e2}); .) ]. ExprPostfix = Term [lbrack (. e = Expression(Operator::INDEX, {e}); .) CalleeParams rbrack ]. Term< Expression& e> (. std::wstring name; e = Expression(); .) = (IF (checkParametersList()) Ident< name> (. e = Expression(Operator::CALL, {Atom(name)}); root->recognizeVariantConstructor(e); .) '(' [CalleeParams] ')' | VarIdent (. recognizeIdentifier(e); .) | ListLiteral (. /* tuple */.) | StructLiteral (. /* struct */.) | LoopDecl | IfDecl | SwitchDecl | AdhocDecl | IntrinsicDecl | number (. e = Expression(Atom(t->val)); .) | string (. e = Expression(Atom(t->val)); .) | "true" (. e = Expression(Atom(1)); e.bindType(TypePrimitive::Bool); .) | "false" (. e = Expression(Atom(0)); e.bindType(TypePrimitive::Bool); .) | '-' Term (. e = Expression(Operator::NEG, {e}); .) | '(' ExprTyped ')' ). StructLiteral = (. std::wstring key; Expression val; std::list> keys; size_t keyCounter=0; .) lcurbrack (IF(checkTokenAfterIdent(_assign)) Ident '=' Expr | Expr (. key = to_wstring(keyCounter++); .) ) (. keys.push_back(Atom(key)); e = Expression(Operator::LIST_NAMED, {val}); .) {',' (IF(checkTokenAfterIdent(_assign)) Ident '=' Expr | Expr (. key = to_wstring(keyCounter++); .) ) (. e.addArg(Expression(val)); keys.push_back(Atom(key)); .) } rcurbrack (. e.addBindings(keys.begin(), keys.end()); .) . ListLiteral = (. Expression eFrom, eTo; .) '[' [ Expr (. e.addArg(Expression(eFrom)); .) (".." Expr (. e.addArg(Expression(eTo)); e.setOp(Operator::LIST_RANGE); .) |{',' Expr (. e.addArg(Expression(eFrom)); .) } (. e.setOp(Operator::LIST); .) ) ] ']'. AdhocDecl = (. Expression command; .) "ad" "hoc" MetaSimpExpr (. adhoc::AdhocExpression exprAdhoc; exprAdhoc.setCommand(command); e = exprAdhoc; .). CalleeParams = (. Expression e2; .) ExprTyped (. e.addArg(Expression(e2)); .) {',' ExprTyped (. e.addArg(Expression(e2)); .) }. AddOp< Operator& op> = (. op = Operator::ADD; .) ( '+' | '-' (. op = Operator::SUB; .) ). MulOp< Operator& op> = (. op = Operator::MUL; .) ( '*' | '/' (. op = Operator::DIV; .) ). RelOp< Operator& op> = (. op = Operator::EQU; .) ( equal | (ne1 | ne2) (. op = Operator::NE; .) | lse (. op = Operator::LSE; .) | lss (. op = Operator::LSS; .) | gte (. op = Operator::GTE; .) | gtr (. op = Operator::GTR; .) ). SkipModulesSection = "module" '{' {ANY} '}'. END Xreate. diff --git a/scripts/dsl/regexp.xreate b/scripts/dsl/regexp.xreate index a313ccb..11d7299 100644 --- a/scripts/dsl/regexp.xreate +++ b/scripts/dsl/regexp.xreate @@ -1,72 +1,72 @@ interface(extern-c){ xml2 = library:: pkgconfig("libxml-2.0"). include { xml2 = ["string.h"] }. } -Matcher = type variant (Sequence, ZeroOrMore, Text). +Matcher = type variant {Sequence, ZeroOrMore, Text}. matchText = function(text::string, matcher::string, posStart::i64):: i64 { textLength = strlen(text):: i64. matcherLength = strlen(matcher):: i64. if(textLength >= posStart + matcherLength):: i64{ if(strncmp(text + posStart, matcher, matcherLength) == 0):: i64 { matcherLength } else {-1:: i64} } else {-2:: i64} } matchSequence = function(text::string, pattern::undef; interpretation(force), posStart::i64):: i64; interpretation(suppress){ textLength = length(text):: i64. loop fold(pattern-> matcher:: undef, posStart->pos):: i64{ recognizedSymbols = match(text, matcher, pos):: i64. if (recognizedSymbols > 0):: i64{ pos+recognizedSymbols } else { pos:: i64; break } } } matchZeroOrMore= function(text::string, matcher::undef; interpretation(force), posStart::i64):: i64; interpretation(suppress){ textLength = length(text):: i64. loop fold inf(posStart->pos):: i64{ recognizedSymbols = match(text, matcher, pos):: i64. if (recognizedSymbols > 0):: i64{ pos+recognizedSymbols } else { pos:: i64; break } } } match = function(text::string, pattern::undef; interpretation(force), posStart::i64)::i64; interpretation(suppress){ - switch (pattern[0]) :: int + key= pattern[0]::Matcher. + switch variant(key) :: int case (Sequence) {matchSequence(text, pattern[1], posStart)} case (ZeroOrMore) {matchZeroOrMore(text, pattern[1], posStart)} case (Text) {matchText(text, pattern[1], posStart)} - case default {-1} } main = function:: i64; entry { patternAB = - [Sequence, - [[ZeroOrMore, [Text, "a"]], - [Text, "b"]]] :: undef; interpretation(force). + [Sequence(), + [[ZeroOrMore(), [Text(), "a"]], + [Text(), "b"]]] :: undef; interpretation(force). // matchers = ["The ", "only ", "way "] :: [string]; interpretation(force). match("aaab", patternAB, 0):: i64 }