diff --git a/cpp/Configurations.cmake b/cpp/Configurations.cmake index be0d21d..34eec0c 100644 --- a/cpp/Configurations.cmake +++ b/cpp/Configurations.cmake @@ -1,158 +1,160 @@ cmake_minimum_required(VERSION 2.8.11) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -fprofile-arcs -ftest-coverage -O0") set(XREATE_DEFINITIONS_COMMON -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DWITH_THREADS=1 ) #------------------------------------------------------ # CONFIGURATION: Min set(XREATE_SOURCE_FILES_MIN + compilation/resources.cpp analysis/typeinference.cpp xreatemanager.cpp transcendlayer.cpp llvmlayer.cpp pass/compilepass.cpp analysis/utils.cpp ast.cpp aux/xreatemanager-decorators.cpp compilation/transformations.cpp compilation/transformersaturation.cpp attachments.cpp compilation/control.cpp utils.cpp pass/abstractpass.cpp aux/serialization/expressionserializer.cpp analysis/transcendtarget.cpp analysis/resources.cpp query/containers.cpp modules.cpp compilation/containers.cpp compilation/containers/arrays.cpp ) set(XREATE_TEST_FILES_MIN universal.cpp introduction.cpp unit-test-example.cpp supplemental/docutils transcend.cpp association.cpp main.cpp attachments.cpp ast.cpp compilation.cpp ExpressionSerializer.cpp types.cpp #vendorsAPI/clangAPI.cpp #vendorsAPI/xml2.cpp #vendorsAPI/json.cpp loops.cpp #supplemental/versions-algorithm-data_dependency.cpp supplemental/basics.cpp arithmetics.cpp ) IF(XREATE_CONFIG STREQUAL "Min") set(XREATE_SOURCE_FILES ${XREATE_SOURCE_FILES_MIN} ) set(XREATE_TEST_FILES ${XREATE_TEST_FILES_MIN}) set(XREATE_DEFINITIONS ${XREATE_DEFINITIONS_COMMON} -DXREATE_CONFIG_MIN ) ENDIF() #------------------------------------------------------ # CONFIGURATION: Default set(XREATE_SOURCE_FILES_DEFAULT ${XREATE_SOURCE_FILES_MIN} compilation/targetinterpretation.cpp analysis/temporalseqgraph.cpp pass/cfatemporalseqpass.cpp analysis/cfagraph.cpp pass/cfapass.cpp compilation/interpretation-instructions.cpp ExternLayer.cpp analysis/cfagraph.cpp compilation/latetranscend.cpp query/latex.cpp aux/latereasoning.cpp analysis/dfagraph.cpp pass/dfapass.cpp pass/interpretationpass.cpp pass/versionspass.cpp contextrule.cpp compilation/demand.cpp analysis/predefinedanns.cpp ) set(XREATE_TEST_FILES_DEFAULT ${XREATE_TEST_FILES_MIN} interpretation.cpp transcend-ast.cpp cfa.cpp latetranscend.cpp latex.cpp polymorph.cpp virtualization.cpp exploitation.cpp effects-communication.cpp modules.cpp dfa.cpp effects-versions.cpp containers.cpp externc.cpp aux/expressions.cpp polymorphism-dt.cpp ) IF(XREATE_CONFIG STREQUAL "Default") set(XREATE_SOURCE_FILES ${XREATE_SOURCE_FILES_DEFAULT} ) set(XREATE_TEST_FILES ${XREATE_TEST_FILES_DEFAULT}) set(XREATE_DEFINITIONS ${XREATE_DEFINITIONS_COMMON} XREATE_ENABLE_EXTERN ) ENDIF() #------------------------------------------------------ # CONFIGURATION: Dimensions IF(XREATE_CONFIG STREQUAL "Dimensions") set(XREATE_SOURCE_FILES ${XREATE_SOURCE_FILES_MIN} + compilation/lambdas.cpp query/demand.cpp compilation/demand.cpp query/polymorph.cpp compilation/polymorph.cpp aux/expressions.cpp pass/interpretationpass.cpp compilation/targetinterpretation.cpp compilation/intrinsics.cpp # compilation/containerinst.cpp analysis/predefinedanns.cpp analysis/typehints.cpp ) set(XREATE_TEST_FILES ${XREATE_TEST_FILES_MIN} interpretation.cpp dimensions.cpp polymorph.cpp polymorphism-dt.cpp containers.cpp problems.cpp ) set(XREATE_DEFINITIONS ${XREATE_DEFINITIONS_COMMON} -DXREATE_CONFIG_MIN ) ENDIF() diff --git a/cpp/src/analysis/predefinedanns.cpp b/cpp/src/analysis/predefinedanns.cpp index 59812a2..e9ffcbb 100644 --- a/cpp/src/analysis/predefinedanns.cpp +++ b/cpp/src/analysis/predefinedanns.cpp @@ -1,64 +1,75 @@ // // Created by pgess on 19/03/2020. // #include "analysis/predefinedanns.h" namespace xreate{ namespace analysis{ PredefinedAnns PredefinedAnns::__instance = PredefinedAnns(); PredefinedAnns::PredefinedAnns(){ fnAnnsT = TypeAnnotation(TypeOperator::VARIANT, {}); exprAnnsT = TypeAnnotation(TypeOperator::VARIANT, {}); //entry fnAnnsT.__operands.push_back(TypePrimitive::Invalid); fnAnnsT.fields.push_back("entry"); //interpretation i12nModeT = TypeAnnotation(TypeOperator::VARIANT, { TypePrimitive::Invalid, TypePrimitive::Invalid }); i12nModeT.fields.push_back("on"); i12nModeT.fields.push_back("off"); exprAnnsT.__operands.push_back(i12nModeT); exprAnnsT.fields.push_back("i12n"); //Int hintsIntT = TypeAnnotation(TypeOperator::VARIANT, { TypePrimitive ::Int }); hintsIntT.fields.push_back("size"); //Containers hintsContT = TypeAnnotation(TypeOperator::VARIANT, { - TypePrimitive::Int + TypePrimitive::Int, + TypeAnnotation::alias("hintsContT") }); hintsContT.fields.push_back("csize"); + hintsContT.fields.push_back("fly"); } void -PredefinedAnns::fillRegistry(std::map> &__registry) const{ +PredefinedAnns::registerVariants(std::map> &__registry) const{ + //annotation; type; variant id; __registry = { //Functions: {"entry", {fnAnnsT, (unsigned) FnAnnotations::ENTRY}}, //Expressions: {"i12n", {exprAnnsT, (unsigned) ExprAnnotations::I12N}}, //Interpretation: {"on", {i12nModeT, (unsigned) I12ModeTag::ON}}, {"off", {i12nModeT, (unsigned) I12ModeTag::OFF}}, //Int: {"size", {hintsIntT, (unsigned) IntHints::SIZE}}, //Containers {"csize", {hintsContT, (unsigned) ContHints::ARRAY}}, + {"fly", {hintsContT, (unsigned) ContHints::FLY}}, + }; +} + +void +PredefinedAnns::registerAliases(std::map &__registry) const{ + __registry = { + {"hintsContT", hintsContT} }; } }} \ No newline at end of file diff --git a/cpp/src/analysis/predefinedanns.h b/cpp/src/analysis/predefinedanns.h index 6d16e73..c860b32 100644 --- a/cpp/src/analysis/predefinedanns.h +++ b/cpp/src/analysis/predefinedanns.h @@ -1,48 +1,49 @@ // // Created by pgess on 19/03/2020. // #ifndef XREATE_PREDEFINEDANNS_H #define XREATE_PREDEFINEDANNS_H #include "ast.h" namespace xreate{ namespace analysis{ class PredefinedAnns{ public: enum class FnAnnotations{ ENTRY }; enum class ExprAnnotations{ I12N }; enum class I12ModeTag{ ON, OFF }; enum class IntHints{ SIZE }; enum class ContHints{ - ARRAY + ARRAY, FLY }; TypeAnnotation fnAnnsT; TypeAnnotation exprAnnsT; TypeAnnotation hintsIntT; TypeAnnotation hintsContT; //Interpretation TypeAnnotation i12nModeT; PredefinedAnns(); static const PredefinedAnns& instance(){ return __instance; } - void fillRegistry(std::map> &__registry) const; + void registerVariants(std::map> &__registry) const; + void registerAliases(std::map& __registry) const; private: static PredefinedAnns __instance; }; }} // end of xreate::analysis #endif //XREATE_PREDEFINEDANNS_H diff --git a/cpp/src/analysis/typehints.cpp b/cpp/src/analysis/typehints.cpp index a0a6603..5c9c1e7 100644 --- a/cpp/src/analysis/typehints.cpp +++ b/cpp/src/analysis/typehints.cpp @@ -1,52 +1,68 @@ // // Created by pgess on 24/03/2020. // #include "analysis/typehints.h" #include "analysis/predefinedanns.h" #include "analysis/utils.h" namespace xreate{namespace typehints{ namespace impl { template inline Hint getHint(const Expression& e, const Hint& def, unsigned annId, const ExpandedType& hintT){ std::list hintsL; auto predefined = analysis::PredefinedAnns::instance(); for(const auto& tag: e.tags){hintsL.push_back(tag.second);} const Expression& hintActual = analysis::findAnnById(annId, hintT, hintsL); if (!hintActual.isValid()){ return def; } return parse(hintActual); } } -template<> IntBits parse(const Expression& e){ +template<> IntBits +parse(const Expression& e){ return {(unsigned) e.operands.at(0).getValueDouble()}; } -template<> Array parse(const Expression& e){ +template<> ArrayHint +parse(const Expression& e){ return {(unsigned) e.operands.at(0).getValueDouble()}; } -template<> -IntBits getHint(const Expression& e, const IntBits& def){ +template<> FlyHint +parse(const Expression& e){ + return {e.operands.at(0)}; +} + +template<> IntBits +find(const Expression& e, const IntBits& def){ auto predefined = analysis::PredefinedAnns::instance(); return impl::getHint(e, def, - (unsigned) analysis::PredefinedAnns::IntHints::SIZE, - ExpandedType(predefined.hintsIntT) + (unsigned) analysis::PredefinedAnns::IntHints::SIZE, + ExpandedType(predefined.hintsIntT) ); } -template<> -Array getHint(const Expression& e, const Array& def){ +template<> ArrayHint +find(const Expression& e, const ArrayHint& def){ auto predefined = analysis::PredefinedAnns::instance(); - return impl::getHint(e, def, - (unsigned) analysis::PredefinedAnns::ContHints::ARRAY, - ExpandedType(predefined.hintsContT) + return impl::getHint(e, def, + (unsigned) analysis::PredefinedAnns::ContHints::ARRAY, + ExpandedType(predefined.hintsContT) ); } +template<> FlyHint +find(const Expression& e, const FlyHint& def){ + auto predefined = analysis::PredefinedAnns::instance(); + + return impl::getHint(e, def, + (unsigned) analysis::PredefinedAnns::ContHints::FLY, + ExpandedType(predefined.hintsContT)); +} + }} \ No newline at end of file diff --git a/cpp/src/analysis/typehints.h b/cpp/src/analysis/typehints.h index 67028cc..33a7880 100644 --- a/cpp/src/analysis/typehints.h +++ b/cpp/src/analysis/typehints.h @@ -1,46 +1,53 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * typehints.h * * Author: pgess */ /** * \file typehints.h * \brief Type inference hints */ #ifndef XREATE_TYPEHINTS_H #define XREATE_TYPEHINTS_H #include "ast.h" namespace xreate{namespace typehints{ struct IntBits{ unsigned int size; }; -struct Array{ +struct ArrayHint{ size_t size; }; +struct FlyHint{ + Expression hintSrc; +}; + template -Typ getHint(const Expression& e, const Typ& def); +Typ find(const Expression& e, const Typ& def); + +template<> +IntBits find(const Expression& e, const IntBits& def); template<> -IntBits getHint(const Expression& e, const IntBits& def); +ArrayHint find(const Expression& e, const ArrayHint& def); template<> -Array getHint(const Expression& e, const Array& def); +FlyHint find(const Expression& e, const FlyHint& def); template Typ parse(const Expression& e); template<> IntBits parse(const Expression& e); -template<> Array parse(const Expression& e); +template<> ArrayHint parse(const Expression& e); }} #endif //XREATE_TYPEHINTS_H diff --git a/cpp/src/analysis/utils.cpp b/cpp/src/analysis/utils.cpp index a7e13bd..f932768 100644 --- a/cpp/src/analysis/utils.cpp +++ b/cpp/src/analysis/utils.cpp @@ -1,425 +1,350 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * aux.cpp * * Author: pgess */ /** * \file src/analysis/utils.h * \brief Various reasoning related utilities */ #include "utils.h" #include "resources.h" #include using namespace std; namespace xreate { namespace analysis { -//std::list multiplyLists(std::list> &&lists){ -// assert(false); -//} -// -//std::list -//compile(const Expression &e){ -// list result; -// -// switch (e.op) { -// case Operator::CALL: { -// -// } -// -// case Operator::NEG: { -// assert(e.operands.size() == 1); -// -// const Expression &op = e.operands.at(0); -// list &&rawOp = compile(op); -// -// assert(rawOp.size() == 1); -// result.push_back((boost::format("not %1%")%(rawOp.front())).str()); -// break; -// }; -// -// case Operator::INVALID: { -// switch (e.__state) { -// case Expression::IDENT: -// result.push_back(e.getValueString()); -// break; -// -// case Expression::NUMBER: -// result.push_back(to_string(e.getValueDouble())); -// break; -// -// default: -// assert(true); -// } -// break; -// } -// -// default: break; -// } -// -// assert(result.size()); -// return result; -//} -// -//std::list -//compileNeg(const Expression &e){ -// list result; -// switch (e.op) { -// case Operator::IMPL: { -// assert(e.__state == Expression::COMPOUND); -// assert(e.operands.size() == 2); -// list operands1 = compile(e.operands.at(0)); -// list operands2 = compile(e.operands.at(1)); -// -// boost::format formatNeg("%1%, not %2%"); -// for (const auto &op1: operands1) -// for (const auto &op2: operands2) { -// result.push_back(boost::str(formatNeg %(op1) % (op2))); -// } -// break; -// } -// case Operator::NEG: { -// assert(e.operands.size() == 1); -// -// const Expression &op = e.operands.at(0); -// list &&rawOp = compile(op); -// -// assert(rawOp.size() == 1); -// result.push_back(rawOp.front()); -// break; -// }; -// -// default: -// assert(true); -// } -// -// return result; -//} -// -////NOTE: Any changes should be reflected in ParseImplAtom, -//// ParseImplAtom -//class VisitorFormatSymbol: public boost::static_visitor { -//public: -// -// boost::format operator()(const SymbolPacked& node) const { -// boost::format formatSymbNamed("s(%1%,%2%,%3%)"); -// return formatSymbNamed % node.identifier % node.version % node.scope ; -// } -// -// boost::format operator()(const SymbolAnonymous& node) const { -// boost::format formatSymbAnonymous("a(%1%)"); -// return formatSymbAnonymous % node.id; -// } -//}; -// -//boost::format writeSymbolNode(const SymbolNode& symbol){ -// return boost::apply_visitor(VisitorFormatSymbol(), symbol); -//} - typedef vector InstancePacked; std::list generateAllInstancesInDomain2(const ExpandedType& domainT) { if(!domainT->isValid()) { return {Expression()}; } assert(domainT->__operator == TypeOperator::VARIANT); std::list results; int variantId = -1; bool flagDomainStateless = std::all_of(domainT->__operands.begin(), domainT->__operands.end(), [](const TypeAnnotation & subdomainT) { return !subdomainT.isValid(); }); for(const TypeAnnotation& subdomainT : domainT->__operands) { ++variantId; if(flagDomainStateless) { Expression result(Operator::VARIANT,{}); result.setValueDouble(variantId); results.push_back(result); continue; } std::list subresults = generateAllInstancesInDomain2(ExpandedType(subdomainT)); for (const Expression& subresult : subresults) { Expression result(Operator::VARIANT,{}); result.setValueDouble(variantId); result.operands.push_back(subresult); results.push_back(result); } } return results; } TypeAnnotation collapseFnGroup(const std::list& symbols) { Gringo::Symbol symbolAny = symbols.front(); size_t operandsCount = symbolAny.args().size; TypeAnnotation resultT; resultT.__operands.reserve(operandsCount); for(size_t operandId = 0; operandId < operandsCount; ++operandId) { std::list column; for(const Gringo::Symbol& row : symbols) { column.push_back(row.args()[operandId]); } TypeAnnotation operandT = collapseColumn(column); resultT.__operands.push_back(operandT); } if(resultT.__operands.size() == 1) { return resultT.__operands.front(); } if(resultT.__operands.size() > 1) { resultT.__operator = TypeOperator::RECORD; return resultT; } return resultT; } TypeAnnotation collapseColumn(const std::list& symbols) { TypeAnnotation resultT; if(!symbols.size()) return resultT; Gringo::Symbol symbolAny = symbols.front(); switch(symbolAny.type()) { case Gringo::SymbolType::Num: { return TypeAnnotation(TypePrimitive::Int); } case Gringo::SymbolType::Str: { return TypeAnnotation(TypePrimitive::String); } case Gringo::SymbolType::Fun: { map> fnGroups; for(const Gringo::Symbol& row : symbols) { fnGroups[row.name().c_str()].push_back(row); } TypeAnnotation resultT; resultT.__operands.reserve(fnGroups.size()); resultT.bindings.reserve(fnGroups.size()); for(const auto& group : fnGroups) { if(!group.second.size()) continue; TypeAnnotation variantT = collapseFnGroup(group.second); Gringo::Symbol symbolAny = group.second.front(); string variantName = symbolAny.name().c_str(); resultT.fields.push_back(variantName); resultT.__operands.push_back(variantT); } resultT.__operator = TypeOperator::VARIANT; // if(resultT.__operands.size() == 1) { // return resultT.__operands.front(); // } return resultT; } case Gringo::SymbolType::Inf: case Gringo::SymbolType::Special: case Gringo::SymbolType::Sup: { break; } } assert(false); return TypeAnnotation(); } ExpandedType dereferenceSlaveType(ExpandedType t, const TranscendLayer* transcend) { assert(t->__operator == TypeOperator::SLAVE); const string& domain = t->__valueCustom; StaticModel model = transcend->query(domain); if(!model.size()) return ExpandedType(TypeAnnotation()); std::list symbols; for(auto row : model) { symbols.push_back(row.second); } return ExpandedType(collapseFnGroup(symbols)); } ASTSitePacked getSite(const Expression& e, TranscendLayer* transcend){ Attachments::put(e, e); return transcend->pack(ASTSite{e.id}); } Expression recognizeSite(const Gringo::Symbol& atom, const ExpandedType& schemaT, TranscendLayer* transcend) { if(atom.type()!=Gringo::SymbolType::Fun) return Expression(); string predicateName = atom.name().c_str(); if (predicateName != SITE_SYMBOL_PREDICATE && predicateName != SITE_ANON_PREDICATE) return Expression(); const ASTSitePacked& siteP = TranscendLayer::parseAtom(atom); const ASTSite& site = transcend->unpack(siteP); return site.getDefinition(); } Expression representTransExpression(const Gringo::Symbol& atom, ExpandedType schemaT, TranscendLayer* transcend) { const Expression siteExpr = recognizeSite(atom, schemaT, transcend); if (siteExpr.isValid()) return siteExpr; switch(schemaT->__operator) { case TypeOperator::NONE: { switch(schemaT->__value) { case TypePrimitive::I8: case TypePrimitive::I32: case TypePrimitive::I64: case TypePrimitive::Int: { return Expression(Atom(atom.num())); } case TypePrimitive::String: { return Expression(Atom(atom.string().c_str())); } case TypePrimitive::Invalid: case TypePrimitive::Bool: case TypePrimitive::Float: { assert(false); return Expression(); } } break; } case TypeOperator::SLAVE: { ExpandedType contentT = dereferenceSlaveType(schemaT, transcend); return representTransExpression(atom, contentT, transcend); } case TypeOperator::VARIANT: { map dictVariants; for(size_t variantId = 0; variantId < schemaT->fields.size(); ++variantId) { dictVariants.emplace(schemaT->fields.at(variantId), variantId); } string predicateName = atom.name().c_str(); assert(dictVariants.count(predicateName)); size_t predicateId = dictVariants.at(predicateName); Expression result(Operator::VARIANT,{}); result.op = Operator::VARIANT; result.setValueDouble(predicateId); if(!schemaT->__operands.size()) return result; ExpandedType schemeOperands = schemaT->__operands.at(predicateId).__operator == TypeOperator::SLAVE ? dereferenceSlaveType(ExpandedType(schemaT->__operands.at(predicateId)), transcend) : ExpandedType(schemaT->__operands.at(predicateId)); if (schemeOperands->__operator == TypeOperator::RECORD){ Expression operandsList = representTransExpression(atom, schemeOperands, transcend); result.operands = move(operandsList.operands); } else if(!schemeOperands->isValid()) { assert(atom.args().size == 0); return result; } else { assert(false); } return result; } case TypeOperator::RECORD: { const Gringo::SymSpan& operandsRaw = atom.args(); size_t opCount = operandsRaw.size; assert(opCount == schemaT->__operands.size()); size_t operandId = 0; std::vector operands; operands.reserve(opCount); for(const TypeAnnotation operandT : schemaT->__operands) { operands.push_back(representTransExpression(operandsRaw[operandId], ExpandedType(operandT), transcend)); ++operandId; } Expression result(Operator::LIST,{}); result.operands = operands; - result.type = schemaT; + result.type = schemaT.get(); return result; } case TypeOperator::ARRAY: case TypeOperator::ALIAS: case TypeOperator::ACCESS: case TypeOperator::REF: case TypeOperator::VOID: case TypeOperator::GUARD: { assert(false); return Expression(); } } assert(false); return Expression(); } Expression representVecStr(const std::vector& srcList){ Expression dstE(Operator::LIST, {}); for(const string op: srcList){ dstE.operands.push_back(Atom(string(op))); } return dstE; } Expression findAnnById(unsigned annId, const ExpandedType& annT, const std::list& annotations){ assert(annT->fields.size() > annId); const string& annExpectedS = annT->fields.at(annId); for(const Expression& e: annotations){ if (e.type.fields.size() <= annId) continue; const string& annTestS = e.type.fields.at(annId); if (annTestS == annExpectedS) return e; } return Expression(); } +Expression +findAnnByType(const Expression &expr, const ExpandedType &annExpectedT, AST *ast){ + std::list tagsL; + for(const auto& tag: expr.tags){tagsL.push_back(tag.second);} + + for (const Expression& annActualE: tagsL){ + if (isSameVariantType(ast->expandType(annActualE.type), annExpectedT)){ + return annActualE; + } + } + + return Expression(); +} + +bool +isSameVariantType(const ExpandedType& a, const ExpandedType& b){ + assert(a->__operator == TypeOperator::VARIANT); + assert(b->__operator == TypeOperator::VARIANT); + + if (a->fields.size()!= b->fields.size()) return false; + for (size_t idx = 0; idx < a->fields.size(); ++idx){ + if (a->fields.at(idx) != b->fields.at(idx)) return false; + } + + return true; +} + }} //end of xreate::analysis diff --git a/cpp/src/analysis/utils.h b/cpp/src/analysis/utils.h index c47a0ee..584d3b8 100644 --- a/cpp/src/analysis/utils.h +++ b/cpp/src/analysis/utils.h @@ -1,59 +1,61 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: aux.h * Author: pgess * * Created on June 26, 2016, 6:49 PM */ #ifndef AUX_H #define AUX_H #include "ast.h" #include "transcendlayer.h" #include #include namespace xreate { namespace analysis { /** * \brief Compiles Xreate expression into ASP format recognizable by an external ASP solver. * @param e expression * @return textual expression's representation in an ASP format. */ std::list compile(const Expression &e); std::list compileNeg(const Expression &e); std::list multiplyLists(std::list> &&lists); ASTSitePacked getSite(const Expression& e, TranscendLayer* transcend); /** * \brief Converts a Transcend's fact to a Xreate's expression that can be interpreted further. Supports `query` keyword. * @param atom Transcend's fact * @param schemaT Type of the resulting expression * @param transcend Transcend's instance * @return converted Transcend' fact in form of Xreate's expression */ Expression representTransExpression(const Gringo::Symbol& atom, ExpandedType schemaT, TranscendLayer* transcend); /** * \brief Expands slave type. * @param t Slave type * @param transcend Instance of Transcend * @return The expanded slave type */ ExpandedType dereferenceSlaveType(ExpandedType t, const TranscendLayer* transcend); TypeAnnotation collapseColumn(const std::list& symbols); std::list generateAllInstancesInDomain2(const ExpandedType& domainT); Expression representVecStr(const std::vector& srcList); Expression findAnnById(unsigned annId, const ExpandedType& annT, const std::list& annotations); +Expression findAnnByType(const Expression &expr, const ExpandedType &annExpectedT, AST *ast); +bool isSameVariantType(const ExpandedType& a, const ExpandedType& b); }} //end of xreate::analysis #endif /* AUX_H */ diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp index fd5eaec..d53ea10 100644 --- a/cpp/src/ast.cpp +++ b/cpp/src/ast.cpp @@ -1,961 +1,964 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * File: ast.cpp */ #include "ast.h" #include "analysis/typeinference.h" #include "analysis/predefinedanns.h" #ifdef XREATE_ENABLE_EXTERN #include "ExternLayer.h" #endif #include #include //TODO BDecl. forbid multiple body declaration (ExprTyped) namespace std { std::size_t hash::operator()(xreate::ScopedSymbol const& s) const { return s.id ^ (s.version << 2); } bool equal_to::operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const { return __x.id == __y.id && __x.version == __y.version; } size_t hash::operator()(xreate::Symbol const& s) const { return hash()(s.identifier) ^ ((long int) s.scope << 1); } bool equal_to::operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const { return __x == __y; }; } using namespace std; namespace xreate { Atom::Atom(const std::wstring& value) { __value = wstring_to_utf8(value); } Atom::Atom(std::string && name) : __value(name) { } const std::string& Atom::get() const { return __value; } Atom::Atom(wchar_t* value) { //DEBT reconsider number literal recognition __value = wcstol(value, 0, 10); } Atom::Atom(int value) : __value(value) { } double Atom::get()const { return __value; } Atom::Atom(const std::wstring& value) { assert(value.size() >= 2); __value = wstring_to_utf8(value.substr(1, value.size() - 2)); } Atom::Atom(std::string && name) : __value(name) {} const std::string& Atom::get() const { return __value; } /** \brief xreate::Expression static information*/ class ExpressionHints { public: static bool isStringValueValid(const Expression& e) { switch (e.__state) { case Expression::INVALID: assert(false); case Expression::IDENT: case Expression::STRING: return true; case Expression::NUMBER: case Expression::BINDING: return false; case Expression::COMPOUND: { switch (e.op) { case Operator::CALL: return true; default: return false; } } } return false; } static bool isDoubleValueValid(const Expression& e) { switch (e.__state) { case Expression::NUMBER: return true; case Expression::INVALID: assert(false); case Expression::IDENT: case Expression::STRING: case Expression::BINDING: return false; case Expression::COMPOUND: { switch (e.op) { case Operator::VARIANT: return true; default: return false; } } } return false; } }; class TypeResolver { public: TypeResolver(const AST* ast, TypeResolver * parent, std::set trace, const std::map& scope = std::map()) : __ast(ast), __scope(scope), __trace(trace), __parent(parent) {} ExpandedType operator()(const TypeAnnotation &t, const std::vector &args = std::vector()) { - //assert(args.size() == t.bindings.size()); // invalid number of arguments + assert(args.size() == t.bindings.size()); // invalid number of arguments for (size_t i = 0; i < args.size(); ++i) { __scope[t.bindings.at(i)] = args.at(i); } switch (t.__operator) { case TypeOperator::ARRAY:{ assert(t.__operands.size() == 1); Expanded elTy = this->operator()(t.__operands.at(0)); - return ExpandedType(TypeAnnotation(TypeOperator::ARRAY, {elTy})); + return ExpandedType(TypeAnnotation(TypeOperator::ARRAY, {elTy.get()})); } case TypeOperator::RECORD: { std::vector&& packOperands = expandOperands(t.__operands); auto typNew = TypeAnnotation(TypeOperator::RECORD, move(packOperands)); typNew.fields = t.fields; return ExpandedType(move(typNew)); }; case TypeOperator::VARIANT: { std::vector&& packOperands = expandOperands(t.__operands); auto typNew = TypeAnnotation(TypeOperator::VARIANT, move(packOperands)); typNew.fields = t.fields; return ExpandedType(move(typNew)); }; case TypeOperator::ALIAS: { std::string alias = t.__valueCustom; if (__trace.count(alias)){ assert(false && "Recursive Type"); return ExpandedType(TypeAnnotation()); } const TypeAnnotation& tyAlias = findType(alias); std::vector&& operands = expandOperands(t.__operands); auto traceNew =__trace; traceNew.insert(alias); return TypeResolver(__ast, this, traceNew, __scope)(tyAlias, operands); }; case TypeOperator::ACCESS: { std::string alias = t.__valueCustom; const TypeAnnotation& ty = findType(alias); - TypeAnnotation tyAggr = this->operator()(ty); + TypeAnnotation tyAggr = this->operator()(ty).get(); for (const string& field : t.fields) { auto fieldIt = std::find(tyAggr.fields.begin(), tyAggr.fields.end(), field); assert(fieldIt != tyAggr.fields.end() && "unknown field"); int fieldId = fieldIt - tyAggr.fields.begin(); tyAggr = tyAggr.__operands.at(fieldId); } return ExpandedType(tyAggr); } case TypeOperator::NONE: case TypeOperator::VOID: case TypeOperator::SLAVE: case TypeOperator::REF: { return ExpandedType(t); } default: assert(false); } assert(false); return ExpandedType(TypeAnnotation()); } private: const AST* __ast; std::map __scope; std::set __trace; TypeResolver* __parent; std::vector expandOperands(const std::vector& operands) { std::vector pack; pack.reserve(operands.size()); std::transform(operands.begin(), operands.end(), std::inserter(pack, pack.end()), [this](const TypeAnnotation & t) { - return this->operator()(t); + return this->operator()(t).get(); }); return pack; } TypeAnnotation findType(const std::string& alias){ if (__scope.count(alias)) { return __scope.at(alias); } else if (__parent){ return __parent->findType(alias); } else if (__ast->__registryTypes.count(alias)){ return __ast->__registryTypes.at(alias); } assert(false && "Undefined or external type"); return TypeAnnotation(); } }; TypeAnnotation::TypeAnnotation() : __operator(TypeOperator::NONE), __value(TypePrimitive::Invalid) { } TypeAnnotation::TypeAnnotation(TypePrimitive typ) : __value(typ) {} TypeAnnotation::TypeAnnotation(TypeOperator op, std::initializer_list operands) : __operator(op), __operands(operands) { } TypeAnnotation::TypeAnnotation(TypeOperator op, std::vector&& operands) : __operator(op), __operands(operands) { } bool TypeAnnotation::isValid() const { return !(__value == TypePrimitive::Invalid && __operator == TypeOperator::NONE); } bool TypeAnnotation::operator<(const TypeAnnotation& t) const { if (__operator != t.__operator) return __operator < t.__operator; if (__operator == TypeOperator::NONE) return __value < t.__value; if (__operator == TypeOperator::ALIAS || __operator == TypeOperator::ACCESS) { if (__valueCustom != t.__valueCustom) return __valueCustom < t.__valueCustom; } return __operands < t.__operands; } -/* -TypeAnnotation (struct_tag, std::initializer_list) -{} - */ +TypeAnnotation +TypeAnnotation::alias(const std::string& alias) +{ + +} void TypeAnnotation::addBindings(std::vector>&& params) { bindings.reserve(bindings.size() + params.size()); std::transform(params.begin(), params.end(), std::inserter(bindings, bindings.end()), [](const Atom& ident) { return ident.get(); }); } void TypeAnnotation::addFields(std::vector>&& listFields) { fields.reserve(fields.size() + listFields.size()); std::transform(listFields.begin(), listFields.end(), std::inserter(fields, fields.end()), [](const Atom& ident) { return ident.get(); }); } unsigned int Expression::nextVacantId = 0; Expression::Expression(const Atom& number) : Expression() { __state = NUMBER; op = Operator::INVALID; __valueD = number.get(); } Expression::Expression(const Atom& a) : Expression() { __state = STRING; op = Operator::INVALID; __valueS = a.get(); } Expression::Expression(const Atom &ident) : Expression() { __state = IDENT; op = Operator::INVALID; __valueS = ident.get(); } Expression::Expression(const Operator &oprt, std::initializer_list params) : Expression() { __state = COMPOUND; op = oprt; if (op == Operator::CALL) { assert(params.size() > 0); Expression arg = *params.begin(); assert(arg.__state == Expression::IDENT); __valueS = std::move(arg.__valueS); operands.insert(operands.end(), params.begin() + 1, params.end()); return; } operands.insert(operands.end(), params.begin(), params.end()); } void Expression::setOp(Operator oprt) { op = oprt; switch (op) { case Operator::INVALID: __state = INVALID; break; default: __state = COMPOUND; break; } } void Expression::addArg(Expression &&arg) { operands.push_back(arg); } void Expression::addTags(const std::list tags) const { std::transform(tags.begin(), tags.end(), std::inserter(this->tags, this->tags.end()), [](const Expression & tag) { return make_pair(tag.getValueString(), tag); }); } void Expression::addBindings(std::initializer_list> params) { addBindings(params.begin(), params.end()); } void Expression::bindType(TypeAnnotation t) { type = move(t); } void Expression::addBlock(ManagedScpPtr scope) { blocks.push_back(scope.operator->()); } const std::vector& Expression::getOperands() const { return operands; } double Expression::getValueDouble() const { return __valueD; } const std::string& Expression::getValueString() const { return __valueS; } void Expression::setValue(const Atom&& v) { __valueS = v.get(); } void Expression::setValueDouble(double value) { __valueD = value; } bool Expression::isValid() const { return (__state != INVALID); } bool Expression::isDefined() const { return (__state != BINDING && __state != INVALID); } Expression::Expression() : __state(INVALID), op(Operator::INVALID), id(nextVacantId++) { } namespace details { namespace inconsistent { std::map AST::__registryIntrinsics = {}; AST::AST() { Attachments::init(); Attachments::init(); Attachments::init(); Attachments::init(); Attachments::init(); initIntrinsics(); - analysis::PredefinedAnns::instance().fillRegistry(__registryVariants); + analysis::PredefinedAnns man = analysis::PredefinedAnns::instance(); + man.registerVariants(__registryVariants); + man.registerAliases(__registryTypes); } 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 &&entry) { //__externdata.push_back(entry); } void AST::add(Function* f) { __functions.push_back(f); __dictFunctions.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) { __registryVariants.emplace(t.fields[i], make_pair(t, i)); } } __registryTypes.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"; + const std::string name = "main"; return name; } ManagedPtr AST::findFunction(const std::string& name) { int count = __dictFunctions.count(name); if (!count) { return ManagedFnPtr::Invalid(); } assert(count == 1); auto range = __dictFunctions.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::getFnSpecializations(const std::string& fnName) const { auto functions = __dictFunctions.equal_range(fnName); std::list result; std::transform(functions.first, functions.second, inserter(result, result.end()), [this](auto f) { return ManagedFnPtr(f.second, &this->__functions); }); return result; } template<> ManagedPtr AST::begin() { return ManagedPtr(0, &this->__functions); } template<> ManagedPtr AST::begin() { return ManagedPtr(0, &this->__scopes); } template<> ManagedPtr AST::begin() { return ManagedPtr(0, &this->__rules); } void AST::recognizeIntrinsic(Expression& fn) const { assert(fn.op == Operator::CALL_INTRINSIC); if (!__registryIntrinsics.count(fn.getValueString())){ assert(false); } IntrinsicFn fnCode = __registryIntrinsics.at(fn.getValueString()); fn.op = Operator::CALL_INTRINSIC; fn.setValueDouble((int) fnCode); } bool AST::recognizeVariantConstructor(Expression& function) { assert(function.op == Operator::CALL); std::string variant = function.getValueString(); if (!__registryVariants.count(variant)) { return false; } auto record = __registryVariants.at(variant); const TypeAnnotation& typ = record.first; function.op = Operator::VARIANT; function.setValueDouble(record.second); function.type = typ; return true; } Atom AST::recognizeVariantConstructor(Atom ident) { std::string variant = ident.get(); assert(__registryVariants.count(variant) && "Can't recognize variant constructor"); auto record = __registryVariants.at(variant); return Atom(record.second); } void AST::postponeIdentifier(CodeScope* scope, const Expression& id) { __bucketUnrecognizedIdentifiers.emplace(scope, id); } void AST::recognizePostponedIdentifiers() { for (const auto& identifier : __bucketUnrecognizedIdentifiers) { if (!identifier.first->recognizeIdentifier(identifier.second)) { //exception: Ident not found std::cout << "Unknown identifier: " << identifier.second.getValueString() << std::endl; assert(false && "Unknown identifier"); } } } xreate::AST* AST::finalize() { //all finalization steps: recognizePostponedIdentifiers(); return reinterpret_cast (this); } void AST::initIntrinsics(){ if (__registryIntrinsics.size()) return; __registryIntrinsics = { {"array_init", IntrinsicFn::ARR_INIT}, {"rec_fields", IntrinsicFn::REC_FIELDS} }; } } } //namespace details::incomplete Expanded AST::findType(const std::string& name) { // find in general scope: if (__registryTypes.count(name)) return expandType(__registryTypes.at(name)); //if type is unknown keep it as is. TypeAnnotation t(TypeOperator::ALIAS, {}); t.__valueCustom = name; return ExpandedType(move(t)); } Expanded AST::expandType(const TypeAnnotation &t) const { return TypeResolver(this, nullptr, {}, {})(t); } ExpandedType AST::getType(const Expression& e, const TypeAnnotation& expectedT) { return typeinference::getType(e, expectedT, *this); } Function::Function(const Atom& name) : __entry(new CodeScope(0)) { __name = name.get(); } void Function::addTag(Expression&& tag, const TagModifier mod) { string name = tag.getValueString(); __tags.emplace(move(name), move(tag)); } const std::map& Function::getTags() const { return __tags; } CodeScope* Function::getEntryScope() const { return __entry; } void Function::addBinding(Atom && name, Expression&& argument, const VNameId hintBindingId) { __entry->addBinding(move(name), move(argument), hintBindingId); } const std::string& Function::getName() const { return __name; } ScopedSymbol CodeScope::registerIdentifier(const Expression& identifier, const VNameId hintBindingId) { versions::VariableVersion version = Attachments::get(identifier, versions::VERSION_NONE); auto result = __identifiers.emplace(identifier.getValueString(), hintBindingId? hintBindingId: __identifiers.size() + 1); return { result.first->second, version }; } bool CodeScope::recognizeIdentifier(const Expression& identifier) const { versions::VariableVersion version = Attachments::get(identifier, versions::VERSION_NONE); const std::string& name = identifier.getValueString(); //search identifier in the current block if (__identifiers.count(name)) { VNameId id = __identifiers.at(name); Symbol s; s.identifier = ScopedSymbol{id, version}; s.scope = const_cast (this); Attachments::put(identifier, s); return true; } //search in the parent scope if (__parent) { return __parent->recognizeIdentifier(identifier); } return false; } ScopedSymbol CodeScope::getSymbol(const std::string& alias) { assert(__identifiers.count(alias)); VNameId id = __identifiers.at(alias); return {id, versions::VERSION_NONE }; } void CodeScope::addBinding(Expression&& var, Expression&& argument, const VNameId hintBindingId) { argument.__state = Expression::BINDING; __bindings.push_back(var.getValueString()); ScopedSymbol binding = registerIdentifier(var, hintBindingId); __declarations[binding] = move(argument); } Symbol CodeScope::addDefinition(Expression&& var, Expression&& body) { ScopedSymbol s = registerIdentifier(var); __declarations[s] = move(body); return Symbol{s, this}; } CodeScope::CodeScope(CodeScope* parent) : __parent(parent) { } CodeScope::~CodeScope() { } void CodeScope::setBody(const Expression &body) { assert(__declarations.count(ScopedSymbol::RetSymbol)==0 && "Attempt to reassign scope body"); __declarations[ScopedSymbol::RetSymbol] = body; } const Expression& CodeScope::getBody() const{ return __declarations.at(ScopedSymbol::RetSymbol); } const Expression& CodeScope::getDefinition(const Symbol& symbol, bool flagAllowUndefined){ const CodeScope* self = symbol.scope; return self->getDefinition(symbol.identifier, flagAllowUndefined); } const Expression& CodeScope::getDefinition(const ScopedSymbol& symbol, bool flagAllowUndefined) const{ static Expression expressionInvalid; if (!__declarations.count(symbol)){ if (flagAllowUndefined) return expressionInvalid; assert(false && "Symbol's declaration not found"); } return __declarations.at(symbol); } void RuleArguments::add(const Atom &arg, DomainAnnotation typ) { emplace_back(arg.get(), typ); } void RuleGuards::add(Expression&& e) { push_back(e); } MetaRuleAbstract:: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards) : __args(std::move(args)), __guards(std::move(guards)) { } MetaRuleAbstract::~MetaRuleAbstract() { } RuleWarning:: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message) : MetaRuleAbstract(std::move(args), std::move(guards)), __message(message.get()), __condition(condition) { } RuleWarning::~RuleWarning() { } void RuleWarning::compile(TranscendLayer& layer) { //TODO restore addRuleWarning //layer.addRuleWarning(*this); } bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2) { return (s1.id < s2.id) || (s1.id == s2.id && s1.version < s2.version); } bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2) { return (s1.id == s2.id) && (s1.version == s2.version); } bool operator<(const Symbol& s1, const Symbol& s2) { return (s1.scope < s2.scope) || (s1.scope == s2.scope && s1.identifier < s2.identifier); } bool operator==(const Symbol& s1, const Symbol& s2) { return (s1.scope == s2.scope) && (s1.identifier == s2.identifier); } bool operator< (const ASTSite& s1, const ASTSite& s2){ return s1.id < s2.id; } bool operator<(const Expression&a, const Expression&b) { if (a.__state != b.__state) return a.__state < b.__state; assert(a.__state != Expression::INVALID); switch (a.__state) { case Expression::IDENT: case Expression::STRING: return a.getValueString() < b.getValueString(); case Expression::NUMBER: return a.getValueDouble() < b.getValueDouble(); case Expression::COMPOUND: { assert(a.blocks.size() == 0); assert(b.blocks.size() == 0); if (a.op != b.op) { return a.op < b.op; } bool flagAValid = ExpressionHints::isStringValueValid(a); bool flagBValid = ExpressionHints::isStringValueValid(b); if (flagAValid != flagBValid) { return flagAValid < flagBValid; } if (flagAValid) { if (a.getValueString() != b.getValueString()) { return a.getValueString() < b.getValueString(); } } flagAValid = ExpressionHints::isDoubleValueValid(a); flagBValid = ExpressionHints::isDoubleValueValid(b); if (flagAValid != flagBValid) { return flagAValid < flagBValid; } if (flagAValid) { if (a.getValueDouble() != b.getValueDouble()) { return a.getValueDouble() < b.getValueDouble(); } } if (a.operands.size() != b.operands.size()) { return (a.operands.size() < b.operands.size()); } for (size_t i = 0; i < a.operands.size(); ++i) { bool result = a.operands[i] < b.operands[i]; if (result) return true; } return false; } case Expression::BINDING: case Expression::INVALID: assert(false); } return false; } bool Expression::operator==(const Expression& other) const { if (this->__state != other.__state) return false; if (ExpressionHints::isStringValueValid(*this)) { if (this->__valueS != other.__valueS) return false; } if (ExpressionHints::isDoubleValueValid(*this)) { if (this->__valueD != other.__valueD) return false; } if (this->__state != Expression::COMPOUND) { return true; } if (this->op != other.op) { return false; } if (this->operands.size() != other.operands.size()) { return false; } for (size_t i = 0; ioperands.size(); ++i) { if (!(this->operands[i] == other.operands[i])) return false; } assert(!this->blocks.size()); assert(!other.blocks.size()); return true; } const ScopedSymbol ScopedSymbol::RetSymbol = ScopedSymbol{0, versions::VERSION_NONE}; Expression ASTSite::getDefinition() const{ if (Attachments::exists(id)){ const Symbol& siteS = Attachments::get(id); return CodeScope::getDefinition(siteS, true); } return Attachments::get(id); } } //end of namespace xreate diff --git a/cpp/src/ast.h b/cpp/src/ast.h index 4334ca8..06517c4 100644 --- a/cpp/src/ast.h +++ b/cpp/src/ast.h @@ -1,750 +1,751 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * File: ast.h */ /** * \file ast.h * \brief A syntax tree representation and related code * * \sa xreate::AST */ #ifndef AST_H #define AST_H #include "attachments.h" #include "utils.h" #include #include #include #include #include #include #include #include #include namespace xreate { struct ScopedSymbol; struct Symbol; } namespace std { template<> struct hash { std::size_t operator()(xreate::ScopedSymbol const& s) const; }; template<> struct equal_to { bool operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const; }; template<> struct hash { size_t operator()(xreate::Symbol const& s) const; }; template<> struct equal_to { bool operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const; }; } namespace xreate { struct String_t { }; struct Identifier_t { }; struct Number_t { }; struct Type_t { }; template class Atom { }; //DEBT store line:col for all atoms/identifiers template<> class Atom { public: Atom(const std::wstring& value); Atom(std::string && name); const std::string& get() const; private: std::string __value; }; template<> class Atom { public: Atom(wchar_t* value); Atom(int value); double get()const; private: double __value; }; template<> class Atom { public: Atom(const std::wstring& value); Atom(std::string && name); const std::string& get() const; private: std::string __value; }; enum class TypePrimitive { Invalid, Bool, I8, I32, I64, Int, Float, String }; enum class TypeOperator { NONE, VOID, REF, ALIAS, VARIANT, ARRAY, RECORD, ACCESS, SLAVE, GUARD }; struct struct_tag { }; const struct_tag tag_struct = struct_tag(); /** * \brief A type representation to support type system * * The class represents type in a denormalized form, i.e. with no arguments and aliases substitution * \sa AST::expandType() */ class TypeAnnotation { public: TypeAnnotation(); TypeAnnotation(TypePrimitive typ); TypeAnnotation(TypeOperator op, std::initializer_list operands); TypeAnnotation(TypeOperator op, std::vector&& operands); + static TypeAnnotation alias(const std::string& alias); 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; std::vector fields; std::vector bindings; private: }; enum class Operator { INVALID, UNDEF, AND, OR, ADD, SUB, MUL, DIV, MOD, EQU, NE, NEG, LSS, LSE, GTR, GTE, LIST, LIST_INDEX, LIST_RANGE, CALL, CALL_INTRINSIC, QUERY, QUERY_LATE, IMPL/* implication */, MAP, FOLD, FOLD_INF, INDEX, IF, SWITCH, SWITCH_VARIANT, SWITCH_LATE, CASE, CASE_DEFAULT, LOGIC_AND, CONTEXT_RULE, VARIANT, SEQUENCE, UPDATE }; class Function; class AST; class CodeScope; class MetaRuleAbstract; typedef ManagedPtr ManagedFnPtr; typedef ManagedPtr ManagedScpPtr; typedef ManagedPtr ManagedRulePtr; const ManagedScpPtr NO_SCOPE = ManagedScpPtr(UINT_MAX, 0); /** * \brief AST node to represent a single instruction or an annotation * \attention In case of any changes update \ref xreate::ExpressionHints auxiliary helper as well * * %Expression is a generic building block of syntax tree which is able to hold node data * along with child nodes as operands. * * \note For types the %expression-like data structure \ref TypeAnnotation is used rather than Expression itself. * \sa xreate::AST, xreate::TypeAnnotation */ struct Expression { friend class CodeScope; friend class TranscendLayer; friend class CFAPass; friend class ExpressionHints; Expression(const Operator &oprt, std::initializer_list params); Expression(const Atom& ident); Expression(const Atom& number); Expression(const Atom& a); Expression(); void setOp(Operator oprt); void addArg(Expression&& arg); void addBindings(std::initializer_list> params); void bindType(TypeAnnotation t); template void addBindings(InputIt paramsBegin, InputIt paramsEnd); void addTags(const std::list tags) const; void addBlock(ManagedScpPtr scope); const std::vector& getOperands() const; double getValueDouble() const; void setValueDouble(double value); const std::string& getValueString() const; void setValue(const Atom&& v); bool isValid() const; bool isDefined() const; bool operator==(const Expression& other) const; /** * \brief is it string, number, compound operation and so on */ enum { INVALID, COMPOUND, IDENT, NUMBER, STRING, BINDING } __state = INVALID; /** * \brief Valid for compound State. Holds type of compound operator */ Operator op; /** * \brief Unique id to identify expression within syntax tree */ unsigned int id; /** * \brief Exact meaning depends on particular instruction * \details As an example, named lists/structs hold field names in bindings */ std::vector bindings; /** * \brief Holds child instructions as arguments */ std::vector operands; /** * \brief Holds type of instruction's result */ TypeAnnotation type; /** * \brief Holds additional annotations */ mutable std::map tags; /** * \brief Child code blocks * \details For example, If statement holds TRUE-branch as first and FALSE-branch as second block here */ std::list blocks; private: std::string __valueS; double __valueD; static unsigned int nextVacantId; }; bool operator<(const Expression&, const Expression&); template void Expression::addBindings(InputIt paramsBegin, InputIt paramsEnd) { size_t index = bindings.size(); std::transform(paramsBegin, paramsEnd, std::inserter(bindings, bindings.end()), [&index, this] (const Atom atom) { std::string key = atom.get(); return key; }); } typedef std::list ExpressionList; enum class TagModifier { NONE, ASSERT, REQUIRE }; enum class DomainAnnotation { FUNCTION, VARIABLE }; class RuleArguments : public std::vector> { public: void add(const Atom& name, DomainAnnotation typ); }; class RuleGuards : public std::vector { public: void add(Expression&& e); }; class TranscendLayer; class LLVMLayer; class MetaRuleAbstract { public: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards); virtual ~MetaRuleAbstract(); virtual void compile(TranscendLayer& layer) = 0; protected: RuleArguments __args; RuleGuards __guards; }; class RuleWarning : public MetaRuleAbstract { friend class TranscendLayer; public: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message); virtual void compile(TranscendLayer& layer); ~RuleWarning(); private: std::string __message; Expression __condition; }; typedef unsigned int VNameId; namespace versions { typedef int VariableVersion; const VariableVersion VERSION_NONE = -2; const VariableVersion VERSION_INIT = 0; } template<> struct AttachmentsDict { typedef versions::VariableVersion Data; static const unsigned int key = 6; }; struct ScopedSymbol { VNameId id; versions::VariableVersion version; static const ScopedSymbol RetSymbol; }; struct Symbol { ScopedSymbol identifier; const CodeScope * scope; }; struct ASTSite { unsigned int id; Expression getDefinition() const; //static Ast registerSite(const Expression& e); }; struct IdentifierSymbol{}; struct ExprAlias_A{}; struct ExprId_A{}; template<> struct AttachmentsDict { typedef Symbol Data; static const unsigned int key = 7; }; template<> struct AttachmentsDict { typedef Symbol Data; static const unsigned int key = 9; }; template<> struct AttachmentsDict{ typedef Expression Data; static const unsigned int key = 12; }; 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); bool operator< (const ASTSite& s1, const ASTSite& s2); /** * \brief AST node to represent a single code block/a scope of visibility * * Holds a single expression as a `body` along with set of variable assignments(declarations) used in body's expression. * \sa xreate::AST */ class CodeScope { friend class Function; friend class PassManager; public: CodeScope(CodeScope* parent = 0); ~CodeScope(); /** \brief Set expression as a body */ void setBody(const Expression& body); /** \brief Returns current code scope body */ const Expression& getBody() const; /** \brief Adds variable definition to be used in body as well as in other declarations */ Symbol addDefinition(Expression&& var, Expression&& body); /** \brief Returns symbols' definition */ static const Expression& getDefinition(const Symbol& symbol, bool flagAllowUndefined = false); const Expression& getDefinition(const ScopedSymbol& symbol, bool flagAllowUndefined = false) const; /** \brief Adds variable defined elsewhere */ void addBinding(Expression&& var, Expression&& argument, const VNameId hintBindingId = 0); std::vector __bindings; std::map __identifiers; CodeScope* __parent; //TODO move __definitions to SymbolsAttachments data //NOTE: definition of return type has index 0 std::unordered_map __declarations; std::vector tags; std::vector contextRules; private: ScopedSymbol registerIdentifier(const Expression& identifier, const VNameId hintBindingId = 0); public: bool recognizeIdentifier(const Expression& identifier) const; ScopedSymbol getSymbol(const std::string& alias); }; /** * \brief AST node to represent a single function * * Holds an `__entry` entry code scope along with `guard` to denote the different specializations. * \sa xreate::AST */ class Function { friend class Expression; friend class CodeScope; friend class AST; public: Function(const Atom& name); /** * \brief Adds function arguments */ void addBinding(Atom && name, Expression&& argument, const VNameId hintBindingId=0); /** * \brief Adds additional function annotations */ void addTag(Expression&& tag, const TagModifier mod); const std::string& getName() const; const std::map& getTags() const; CodeScope* getEntryScope() const; CodeScope* __entry; std::string __name; Expression guard; private: std::map __tags; }; class ExternData; typedef Expanded ExpandedType; struct TypeInferred{}; template<> struct AttachmentsDict { typedef ExpandedType Data; static const unsigned int key = 11; }; enum ASTInterface { CFA, DFA, Extern, Adhoc }; struct FunctionSpecialization { std::string guard; size_t id; }; struct FunctionSpecializationQuery { std::unordered_set context; }; template<> struct AttachmentsId{ static unsigned int getId(const Expression& expression){ return expression.id; } }; template<> struct AttachmentsId{ static unsigned int getId(const Symbol& s){ return s.scope->__declarations.at(s.identifier).id; } }; template<> struct AttachmentsId{ static unsigned int getId(const ManagedFnPtr& f){ const Symbol symbolFunction{ScopedSymbol::RetSymbol, f->getEntryScope()}; return AttachmentsId::getId(symbolFunction); } }; template<> struct AttachmentsId{ static unsigned int getId(const CodeScope* scope){ const Symbol symbolScope{ScopedSymbol::RetSymbol, scope}; return AttachmentsId::getId(symbolScope); } }; template<> struct AttachmentsId{ static unsigned int getId(const unsigned int id){ return id; } }; class TypeResolver; enum class IntrinsicFn { ARR_INIT, REC_FIELDS }; namespace details { namespace inconsistent { /** * \brief AST in an inconsistent form during construction * * Represents AST under construction(**inconsistent state**). * \attention Clients should use rather xreate::AST unless client's code explicitly works with Syntax Tree during construction. * * Typically an instance is created by xreate::XreateManager only and filled out by the parser * \sa xreate::XreateManager::prepare(std::string&&) */ class AST { friend class xreate::TypeResolver; public: AST(); /** * \brief Adds new function to AST * \param f Function to register */ void add(Function* f); /** * \brief Adds new declarative rule to AST * \param r Declarative Rule */ void add(MetaRuleAbstract* r); /** \brief Registers new code block */ ManagedScpPtr add(CodeScope* scope); /** * \brief Add new type to AST * @param t Type definition * @param alias Typer name */ void add(TypeAnnotation t, Atom alias); /** \brief Current module's name */ std::string getModuleName(); /** * \brief Looks for function with given name * \param name Function name to find * \note Requires that only one function exists under given name * \return Found function */ ManagedPtr findFunction(const std::string& name); /** \brief Returns all function in AST */ std::list getAllFunctions() const; /** * \brief Returns all specializations of a function with a given name * \param fnName function to find * \return list of found function specializations */ std::list getFnSpecializations(const std::string& fnName) const; /** * \return First element in Functions/Scopes/Rules list depending on template parameter * \tparam Target either Function or CodeScope or MetaRuleAbstract */ template ManagedPtr begin(); /** * \brief Performs all necessary steps after AST is built * * Performs all finalization steps and moves AST into consistent state represented by xreate::AST * \sa xreate::AST * \return AST in consistent state */ xreate::AST* finalize(); typedef std::multimap FUNCTIONS_REGISTRY; //std::list __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 __dictFunctions; protected: std::map __registryTypes; public: /** * \brief Stores DFA scheme for later use by DFA Pass * * Treats expression as a DFA scheme and feeds to the DFA Pass later * \param data DFA Scheme * \sa xreate::DFAPass */ void addDFAData(Expression&& data); /** \brief Stores data for later use by xreate::ExternLayer */ void addExternData(ExternData&& entry); /** * \brief Generalized function to store particular data for later use by particular pass * \param interface Particular Interface * \param data Particular data */ void addInterfaceData(const ASTInterface& interface, Expression&& data); /**\name Symbols Recognition */ ///@{ public: //TODO revisit enums/variants, move to codescope /** * \brief Tries to find out whether expression is Variant constructor */ bool recognizeVariantConstructor(Expression& function); Atom recognizeVariantConstructor(Atom ident); /** * \brief Postpones unrecognized identifier for future second round of recognition * \param scope Code block identifier is encountered * \param id Identifier */ void postponeIdentifier(CodeScope* scope, const Expression& id); /** \brief Second round of identifiers recognition done right after AST is fully constructed */ void recognizePostponedIdentifiers(); void recognizeIntrinsic(Expression& fn) const; private: std::map> __registryVariants; static std::map __registryIntrinsics; std::set> __bucketUnrecognizedIdentifiers; static void initIntrinsics(); public: ///@} }; template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); } } // namespace details::incomplete /** * \brief AST in a consistent state * * AST has two mutually exclusive possible states: * - an inconsistent state while AST is under construction. Represented by xreate::details::inconsistent::AST * - a consistent state when AST is built and finalize() is invoked. * * This class represents a consistent state and should be used by clients unless client's code explicitly works with AST under construction. * Consistent AST enables access to additional functions(such as type management). * \sa xreate::details::inconsistent::AST */ class AST : public details::inconsistent::AST { public: AST() : details::inconsistent::AST() {} /** * \brief Computes fully expanded form of type by substituting all arguments and aliases * \param t Type to expand * \return Expdanded or normal form of type * \sa TypeAnnotation */ ExpandedType expandType(const TypeAnnotation &t) const; /** * Searches type by given name * \param name Typename to search * \return Expanded or normal form of desired type * \note if type name is not found returns new undefined type with this name */ ExpandedType findType(const std::string& name); /** * Invokes Type Inference Analysis to find out expanded(normal) form expressions's type * \sa typeinference.h * \param e * \param expectedT expected type * \return Type of expression */ ExpandedType getType(const Expression& e, const TypeAnnotation& expectedT = TypeAnnotation()); }; } #endif // AST_H diff --git a/cpp/src/compilation/containers.cpp b/cpp/src/compilation/containers.cpp index 6a50ca4..c6e7140 100644 --- a/cpp/src/compilation/containers.cpp +++ b/cpp/src/compilation/containers.cpp @@ -1,262 +1,236 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: containers.cpp * Author: pgess */ /** * \file compilation/containers.h * \brief Containers compilation support. See [Containers](/d/concepts/containers/) in the Xreate's documentation. */ #include "compilation/containers.h" #include "compilation/targetinterpretation.h" #include "aux/expressions.h" #include "compilation/containers/arrays.h" +#include "compilation/lambdas.h" +#include "analysis/predefinedanns.h" +#include "analysis/utils.h" using namespace std; -using namespace llvm; -using namespace xreate; -using namespace xreate::containers; -using namespace xreate::interpretation; -using namespace xreate::typehints; namespace xreate { namespace containers{ +ImplementationType +IContainersIR::getImplementation(const Expression& aggrE, AST* ast){ + auto manPredefined = analysis::PredefinedAnns::instance(); + const Expression& hintE = analysis::findAnnByType(aggrE, ExpandedType(manPredefined.hintsContT), ast); + assert(hintE.isValid()); + + return (ImplementationType ) hintE.getValueDouble(); +} + IContainersIR * IContainersIR::create(const Expression &aggrE, const TypeAnnotation &expectedT, const compilation::Context &context){ ExpandedType aggrT = context.pass->man->root->getType(aggrE, expectedT); Expression aggr2E; if (aggrE.__state == Expression::IDENT && !aggrE.tags.size()){ Symbol aggrS = Attachments::get(aggrE); aggr2E = CodeScope::getDefinition(aggrS); } else { aggr2E = aggrE; } switch(aggr2E.op){ case Operator::LIST:{ - typehints::Array aggrHint = typehints::getHint( - aggr2E, typehints::Array{aggr2E.operands.size()} + typehints::ArrayHint aggrHint = typehints::find( + aggr2E, typehints::ArrayHint{aggr2E.operands.size()} ); - return new ArrayIR(context, aggrT, aggrHint); + return new ArrayIR(aggrT, aggrHint, context); } default: - typehints::Array aggrHint = typehints::getHint( - aggr2E, typehints::Array{0} + typehints::ArrayHint aggrHint = typehints::find( + aggr2E, typehints::ArrayHint{0} ); assert(aggrHint.size != 0); - return new ArrayIR(context, aggrT, aggrHint); + return new ArrayIR(aggrT, aggrHint, context); } assert(false); return nullptr; } llvm::Value * RecordIR::init(llvm::StructType *tyAggr){ return llvm::UndefValue::get(tyAggr); } +llvm::Value* +RecordIR::init(std::forward_list fields){ + std::vector fieldsVec(fields.begin(), fields.end()); + llvm::ArrayRef fieldsArr(fieldsVec); + llvm::StructType* resultTR = llvm::StructType::get(__context.pass->man->llvm->llvmContext, fieldsArr, false); + + return init(resultTR); +} + llvm::Value * RecordIR::update(llvm::Value *aggrRaw, const ExpandedType &aggrT, const Expression &updE){ - InterpretationScope *scopeI12n = __context.pass->targetInterpretation->transformContext(__context); + interpretation::InterpretationScope *scopeI12n = + __context.pass->targetInterpretation->transformContext(__context); TypesHelper helper(__context.pass->man->llvm); const auto &fields = helper.getRecordFields(aggrT); std::map indexFields; for(size_t i = 0, size = fields.size(); i < size; ++i){ indexFields.emplace(fields[i], i); } for(const auto &entry: reprListAsDict(updE)){ unsigned keyId; std::string keyHint; const Expression keyE = scopeI12n->process(entry.first); switch(keyE.__state){ case Expression::STRING: keyId = indexFields.at(keyE.getValueString()); keyHint = keyE.getValueString(); break; case Expression::NUMBER: keyId = keyE.getValueDouble(); keyHint = aggrT->fields.at(keyId); break; default: assert(false); break; } const TypeAnnotation &valueT = aggrT->__operands.at(keyId); llvm::Value *valueRaw = __context.scope->process(entry.second, keyHint, valueT); aggrRaw = __context.pass->man->llvm->irBuilder.CreateInsertValue( aggrRaw, valueRaw, keyId); } return aggrRaw; } -//IFwdIteratorIR* -//IFwdIteratorIR::create(xreate::compilation::Context context, const xreate::Symbol& var){ -// const Implementation& data = Query::queryImplementation(var); -// -// switch(data.impl){ -// case ON_THE_FLY: -// return new FwdIteratorIR(context, var, data.extract()); -// -// case SOLID: -// return new FwdIteratorIR(context, var, data.extract()); -// -// default: break; -//} -// -// assert(false && "Unknown declaration"); -// return nullptr; -//} -// -//llvm::Value* -//FwdIteratorIR::begin() { -// switch(sourceDecl.op) { -// case xreate::Operator::LIST: -// { -// sourceRawType = llvm::Type::getInt32Ty(llvm->llvmContext); -// return llvm::ConstantInt::get(Type::getInt32Ty(llvm->llvmContext), 0); -// }; -// -// case xreate::Operator::LIST_RANGE:{ -// assert(sourceDecl.operands.size()==2); -// -// llvm::Value* result = sourceUnit->process(sourceDecl.operands.at(0)); -// sourceRawType = result->getType(); -// -// return result; -// }; -// -// default: break; -// } -// -// if (linkedlist){ -// llvm::Value* result = sourceUnit->process(sourceDecl); -// sourceRawType = result->getType(); -// return result; -// } -// -// assert(false); -//} -// -//llvm::Value* -//FwdIteratorIR::end(){ -// switch(sourceDecl.op) { -// case xreate::Operator::LIST: { -// size_t idLast = sourceDecl.operands.size() - 1; -// return ConstantInt::get(sourceRawType, idLast); -// } -// -// case xreate::Operator::LIST_RANGE: { -// assert(sourceDecl.operands.size() == 2); -// llvm::Value* valueEndOfRange = sourceUnit->process(sourceDecl.operands.at(1)); -// llvm::Value* valueConstOne = llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm->llvmContext), 1); -// -// return llvm->irBuilder.CreateAdd(valueEndOfRange, valueConstOne); -// }; -// -// default: break; -// } -// -// //return null pointer -// if (linkedlist){ -// return ConstantPointerNull::getNullValue(sourceRawType); -// } -// -// assert(false && "Unknown declaration"); -// return nullptr; -//} -// -//llvm::Value* -//FwdIteratorIR::get(Value* index, const std::string& hintRetVar){ -// const Expression& currentDecl = CodeScope::getDefinition(current); -// -// switch (currentDecl.op) { -// case xreate::Operator::LIST: { -// //TODO re check is it right scope(source) to compile currentDecl. Provide unittests. -// llvm::Value* currentValue = sourceUnit->processSymbol(current); -// return xreate::compilation::ControlIR(context).compileArrayIndex(currentValue, std::vector{index}); -// }; -// -// case xreate::Operator::LIST_RANGE: { -// return index; -// }; -// -// case xreate::Operator::MAP: { -// assert(currentDecl.getOperands().size()==1); -// assert(currentDecl.bindings.size()); -// assert(currentDecl.blocks.size()); -// -// CodeScope* scopeLoop = currentDecl.blocks.front(); -// std::string varEl = currentDecl.bindings[0]; -// -// const Symbol& symbIn = Attachments::get(currentDecl.getOperands()[0]); -// auto it = std::unique_ptr(IFwdIteratorIR::create(context, symbIn)); -// -// Value* elIn = it->get(index, varEl); -// compilation::IBruteScope* unitLoop = function->getScopeUnit(scopeLoop); -// unitLoop->bindArg(elIn, std::move(varEl)); -// return unitLoop->compile(); -// } -// -// case xreate::Operator::INVALID: { -// //TODO review iterator determination strategy for case of Expression::BINDING -// assert(currentDecl.__state==Expression::IDENT); -// -// const Symbol& symbIn = Attachments::get(currentDecl); -// auto it = std::unique_ptr(IFwdIteratorIR::create(context, symbIn)); -// return it->get(index); -// }; -// -// default: break; -// } -// -// if (linkedlist){ -// return index; -// } -// -// assert(false && "Unknown declaration"); -// return nullptr; -//} -// -//llvm::Value* -//FwdIteratorIR::advance(Value* index, const std::string& hintRetVar){ -// switch(sourceDecl.op) -// { -// case xreate::Operator::LIST: -// case xreate::Operator::LIST_RANGE: -// return llvm->irBuilder.CreateAdd(index, llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm->llvmContext), 1), hintRetVar); -// -// default: break; -// } -// -// if (linkedlist){ -// ExpandedType tySource = llvm->ast->getType(CodeScope::getDefinition(source)); -// assert(tySource->__operator == TypeOperator::ARRAY && "Linked list implementation has to have ARRAY type"); -// assert(tySource->__operands.size()); -// -// return xreate::compilation::ControlIR(context).compileStructIndex(index, ExpandedType(TypeAnnotation(tySource->__operands.at(0))), {linkedlist.fieldPointer}); -// } -// -// assert(false && "Unknown declaration"); -// return nullptr; -//} - -//const ImplementationRec& implementation +llvm::Value* +FlyIR::create(llvm::Value* sourceRaw, CodeScope* body, const std::string& hintAlias){ + RecordIR recordIR(__context); + compilation::LambdaIR lambdaIR(__context.pass); + llvm::Function* fnTransform = lambdaIR.compile(body, hintAlias); + + llvm::Value* resultRaw = recordIR.init({ + sourceRaw->getType(), + fnTransform->getFunctionType()->getPointerTo() + }); + + resultRaw = __context.pass->man->llvm->irBuilder.CreateInsertValue( + resultRaw, sourceRaw, 0); + resultRaw = __context.pass->man->llvm->irBuilder.CreateInsertValue( + resultRaw, fnTransform, 1); + + return resultRaw; +} + +llvm::Value* +FlyIR::getTransformFn(llvm::Value* aggrRaw){ + LLVMLayer* llvm = __context.pass->man->llvm; + llvm::Value* fnRaw = llvm->irBuilder.CreateExtractValue(aggrRaw, llvm::ArrayRef{1}); + + return fnRaw; +} + +llvm::Value* FlyIR::getSourceAggr(llvm::Value* aggrRaw){ + LLVMLayer* llvm = __context.pass->man->llvm; + return llvm->irBuilder.CreateExtractValue(aggrRaw, llvm::ArrayRef{0}); +} + +llvm::Value* +FlyIR::operatorMap(const Expression& expr, const std::string& hintAlias){ + const Expression& sourceE = expr.getOperands().at(0); + llvm::Value* sourceRaw = __context.scope->process(sourceE); + CodeScope* loopS = expr.blocks.front(); + + return create(sourceRaw, loopS, hintAlias); +} + +FlyIR::FlyIR(typehints::FlyHint hint, compilation::Context context) + : __hint(hint), __context(context){} + +IFwdIteratorIR* +IFwdIteratorIR::createByHint(const Expression& hintE, const ExpandedType& aggrT, const compilation::Context& context){ + ImplementationType hintType = (ImplementationType) hintE.getValueDouble(); + + switch(hintType){ + case SOLID:{ + ArrayIR compiler(aggrT, typehints::parse(hintE), context); + return new FwdIteratorIR(compiler); + } + + case ON_THE_FLY:{ + return new FwdIteratorIR(typehints::parse(hintE), aggrT, context); + } + + default: break; + } + + assert(false); + return nullptr; +} + +IFwdIteratorIR* +IFwdIteratorIR::create(const Expression& aggrE, const ExpandedType& aggrT, const compilation::Context& context){ + auto manPredefined = analysis::PredefinedAnns::instance(); + const Expression& hintE = analysis::findAnnByType( + aggrE, + ExpandedType(manPredefined.hintsContT), + context.pass->man->root + ); + assert(hintE.isValid()); + + return createByHint(hintE, aggrT, context); +} + +llvm::Value* +FwdIteratorIR::begin() { + std::unique_ptr itSrcIR(IFwdIteratorIR::createByHint(__hint.hintSrc, __aggrT, __context)); + return itSrcIR->begin(); +} + +llvm::Value* +FwdIteratorIR::end() { + std::unique_ptr itSrcIR(IFwdIteratorIR::createByHint(__hint.hintSrc, __aggrT, __context)); + return itSrcIR->end(); +} + +llvm::Value* +FwdIteratorIR::advance(llvm::Value* idxRaw, const std::string& hintAlias){ + std::unique_ptr itSrcIR(IFwdIteratorIR::createByHint(__hint.hintSrc, __aggrT, __context)); + return itSrcIR->advance(idxRaw, hintAlias); +} + +llvm::Value* +FwdIteratorIR::get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintAlias){ + std::unique_ptr srcIterIR(IFwdIteratorIR::createByHint(__hint.hintSrc, __aggrT, __context)); + FlyIR compilerFly(__hint, __context); + llvm::Value* aggrSrcRaw = compilerFly.getSourceAggr(aggrRaw); + llvm::Value* valueSrcRaw = srcIterIR->get(aggrSrcRaw, idxRaw); + FlyIR flyIR(__hint, __context); + llvm::Value* fnTnsfRaw = flyIR.getTransformFn(aggrRaw); + llvm::Type* fnTnsfTRawRaw = llvm::cast(fnTnsfRaw->getType())->getElementType(); + llvm::FunctionType* fnTnsfTRaw = llvm::cast(fnTnsfTRawRaw); + compilation::BruteFnInvocation fnTnsfInvoc(fnTnsfRaw, fnTnsfTRaw, __context.pass->man->llvm); + return fnTnsfInvoc({valueSrcRaw}, hintAlias); +} }} //end of xreate::containers diff --git a/cpp/src/compilation/containers.h b/cpp/src/compilation/containers.h index 4e830e8..8c953f3 100644 --- a/cpp/src/compilation/containers.h +++ b/cpp/src/compilation/containers.h @@ -1,103 +1,108 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: containers.h * Author: pgess */ #ifndef CODEINSTRUCTIONS_H #define CODEINSTRUCTIONS_H #include "ast.h" #include "llvmlayer.h" #include "pass/compilepass.h" #include "compilation/control.h" #include "query/containers.h" #include "analysis/typehints.h" namespace xreate { namespace containers { class IFwdIteratorIR; class IContainersIR{ public: static IContainersIR *create( const Expression &aggrE, const TypeAnnotation &expectedT, const compilation::Context &context); + static ImplementationType getImplementation(const Expression& aggrE, AST* ast); + virtual llvm::Value *init(const std::string &hintAlias = "") = 0; virtual llvm::Value *update(llvm::Value *aggrRaw, const Expression &updE, const std::string &hintAlias) = 0; virtual IFwdIteratorIR* getFwdIterator() = 0; virtual ~IContainersIR(){} }; class RecordIR{ public: RecordIR(const compilation::Context& context): __context(context){} llvm::Value* init(llvm::StructType* tyAggr); + llvm::Value* init(std::forward_list fields); llvm::Value* update(llvm::Value* aggrRaw, const ExpandedType& aggrT, const Expression& updE); private: compilation::Context __context; }; +class FlyIR{ +public: + FlyIR(typehints::FlyHint hint, compilation::Context context); + + llvm::Value* create(llvm::Value* sourceRaw, CodeScope* body, const std::string& hintAlias); + llvm::Value* getSourceAggr(llvm::Value* aggrRaw); + llvm::Value* getTransformFn(llvm::Value* aggrRaw); + llvm::Value* operatorMap(const Expression& expr, const std::string& hintAlias); + +private: + typehints::FlyHint __hint; + compilation::Context __context; +}; + /** * \brief A factory to create a concrete iterator based on the solution provided by xreate::containers::Query * \sa xreate::containers::Query */ class IFwdIteratorIR{ public : virtual ~IFwdIteratorIR(){}; virtual llvm::Value* begin() = 0; virtual llvm::Value* end() = 0; - virtual llvm::Value* get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintRetVar="") = 0; + virtual llvm::Value* get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintAlias="") = 0; virtual llvm::Value* advance(llvm::Value* idxRaw, const std::string& hintAlias="") = 0; + + static IFwdIteratorIR* create(const Expression& aggrE, const ExpandedType& aggrT, const compilation::Context& context); + static IFwdIteratorIR* createByHint(const Expression& hintE, const ExpandedType& aggrT, const compilation::Context& context); }; template class FwdIteratorIR; + /** \brief The lazy container implementation. * * Represents computation on the fly. * \sa xreate::containers::IFwdIteratorIR, \sa xreate::containers::Query */ -//template<> -//class FwdIteratorIR : public IFwdIteratorIR { -//private: -// LLVMLayer* llvm; -// const xreate::Symbol current; -// const Symbol source; -// const ImplementationLinkedList linkedlist; -// const CodeScope* const sourceScope; -// //TODO initialize and mark as const (three fields) -// compilation::IBruteScope* sourceUnit; -// compilation::IBruteFunction* function; //TODO is used somewhere? -// const Expression& sourceDecl; -// compilation::Context context; -// llvm::Type* sourceRawType =nullptr; -// -//public: -// FwdIteratorIR(const compilation::Context& ctx, const xreate::Symbol& s, const ImplementationRec& implementation) -// : llvm(ctx.pass->man->llvm), -// current(s), -// source(implementation.source), -// linkedlist(source), -// sourceScope(source.scope), -// sourceUnit(ctx.function->getScopeUnit(source.scope)), -// sourceDecl(CodeScope::getDefinition(source)), -// context(ctx) -// {} -// -// llvm::Value* begin() override; -// llvm::Value* end() override; -// llvm::Value* get(llvm::Value* index,const std::string& hintRetVar="") override; -// llvm::Value* advance(llvm::Value* idxRaw, const std::string& hintAlias="") override; -//}; +template<> +class FwdIteratorIR : public IFwdIteratorIR { +public: + FwdIteratorIR(typehints::FlyHint hint, const ExpandedType &aggrT, compilation::Context context) + : __aggrT(aggrT), __hint(hint), __context(context){} + + virtual llvm::Value* begin() override; + virtual llvm::Value* end() override; + virtual llvm::Value* get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintAlias="") override; + virtual llvm::Value* advance(llvm::Value* idxRaw, const std::string& hintAlias="") override; + +private: + ExpandedType __aggrT; + typehints::FlyHint __hint; + compilation::Context __context; +}; }} #endif //CODEINSTRUCTIONS_H diff --git a/cpp/src/compilation/containers/arrays.cpp b/cpp/src/compilation/containers/arrays.cpp index ea287bd..d57ff02 100644 --- a/cpp/src/compilation/containers/arrays.cpp +++ b/cpp/src/compilation/containers/arrays.cpp @@ -1,106 +1,169 @@ -// -// Created by pgess on 27/03/2020. -// +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: arrays.cpp + * Author: pgess + * + * Created in March 2020. + */ #include "compilation/containers/arrays.h" #include "aux/expressions.h" using namespace std; using namespace llvm; namespace xreate { namespace containers{ llvm::ArrayType* ArrayIR::getRawT(){ assert(__aggrT->__operator == TypeOperator::ARRAY); assert(__aggrT->__operands.size() == 1); LLVMLayer* llvm = __context.pass->man->llvm; llvm::Type* elRawT = llvm->toLLVMType(ExpandedType(__aggrT->__operands.at(0))); return llvm::ArrayType::get(elRawT, __hints.size); } llvm::Value* ArrayIR::init(const string& hintAlias){ LLVMLayer* llvm = __context.pass->man->llvm; TypesHelper helper(llvm); llvm::ArrayType* aggrRawT = getRawT(); //llvm::Value* aggrLengthRaw = ConstantInt::get(helper.getPreferredIntTy(), aggrInfo.size); llvm::Value* aggrRaw = llvm->irBuilder.CreateAlloca(aggrRawT, nullptr, hintAlias); return aggrRaw; } llvm::Value* ArrayIR::update(llvm::Value* aggrRaw, const Expression& updE, const std::string& hintAlias) { LLVMLayer* llvm = __context.pass->man->llvm; TypesHelper helper(llvm); llvm::IntegerType* intT = helper.getPreferredIntTy(); llvm::Value* idxZeroRaw = ConstantInt::get(intT, 0); llvm::ArrayType* aggrRawT = getRawT(); const TypeAnnotation& elT = __aggrT->__operands.at(0); //llvm::Type* elTRaw = llvm->toLLVMType(ExpandedType(aggrT->__operands.at(0))); for (const auto& entry: reprListAsDict(updE)){ llvm::Value* keyRaw = __context.scope->process(entry.first); llvm::Value* elRaw = __context.scope->process(entry.second, "", elT); llvm::Value* elLoc = llvm->irBuilder.CreateGEP( aggrRawT, aggrRaw, ArrayRef(std::vector{idxZeroRaw, keyRaw})); llvm->irBuilder.CreateStore(elRaw, elLoc) ; } return aggrRaw; } llvm::Value* ArrayIR::get(llvm::Value* aggrRaw, std::vector idxL, const std::string& hintAlias) { LLVMLayer* llvm = __context.pass->man->llvm; TypesHelper helper(llvm); llvm::IntegerType* intT = helper.getPreferredIntTy(); llvm::Value* zeroRaw = ConstantInt::get(intT, 0); idxL.insert(idxL.begin(), zeroRaw); llvm::Value *pEl = llvm->irBuilder.CreateGEP(aggrRaw, llvm::ArrayRef(idxL)); return llvm->irBuilder.CreateLoad(pEl, hintAlias); } +llvm::Value* +ArrayIR::operatorMap(const Expression& expr, const std::string& hintAlias) { + assert(false); return nullptr; + //EXPAND_CONTEXT UNUSED(scope); + +// //initializationcompileListAsSolidArray +// 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]; +// +// IFwdIteratorIR* it = IFwdIteratorIR::create(context, symbolIn); +// llvm::Value *rangeFrom = it->begin(); +// llvm::Value *rangeTo = it->end(); +// +// //definitions +// ArrayType* tyNumArray = nullptr; //(ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::Int, size)))); +// llvm::IRBuilder<> &builder = llvm->irBuilder; +// +// llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm->llvmContext, "loop", function->raw); +// llvm::BasicBlock *blockBeforeLoop = builder.GetInsertBlock(); +// llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm->llvmContext, "postloop", function->raw); +// Value* dataOut = llvm->irBuilder.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::IBruteScope* 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; +} + IFwdIteratorIR* ArrayIR::getFwdIterator(){ - return new FwdIteratorIR(this); + return new FwdIteratorIR(*this); } llvm::Value * FwdIteratorIR::begin(){ - TypesHelper helper(__arraysIR->__context.pass->man->llvm); + TypesHelper helper(__compiler.__context.pass->man->llvm); llvm::IntegerType* intT = helper.getPreferredIntTy(); return llvm::ConstantInt::get(intT, 0); } llvm::Value * FwdIteratorIR::end(){ - TypesHelper helper(__arraysIR->__context.pass->man->llvm); + TypesHelper helper(__compiler.__context.pass->man->llvm); llvm::IntegerType* intT = helper.getPreferredIntTy(); - size_t size = __arraysIR->__hints.size; + size_t size = __compiler.__hints.size; return llvm::ConstantInt::get(intT, size); } llvm::Value * FwdIteratorIR::get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintAlias){ - return __arraysIR->get(aggrRaw, {idxRaw}, hintAlias); + return __compiler.get(aggrRaw, {idxRaw}, hintAlias); } llvm::Value * FwdIteratorIR::advance(llvm::Value *idxRaw, const std::string &hintAlias){ - LLVMLayer* llvm = __arraysIR->__context.pass->man->llvm; + LLVMLayer* llvm = __compiler.__context.pass->man->llvm; TypesHelper helper(llvm); llvm::IntegerType* intT = helper.getPreferredIntTy(); llvm::Value* cnstOneRaw = llvm::ConstantInt::get(intT, 1); return llvm->irBuilder.CreateAdd(idxRaw, cnstOneRaw, hintAlias); } }} //xreate::containers \ No newline at end of file diff --git a/cpp/src/compilation/containers/arrays.h b/cpp/src/compilation/containers/arrays.h index 3401940..8951d9d 100644 --- a/cpp/src/compilation/containers/arrays.h +++ b/cpp/src/compilation/containers/arrays.h @@ -1,53 +1,63 @@ -// -// Created by pgess on 27/03/2020. -// +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: arrays.h + * Author: pgess + * + * Created in March 2020. + */ -#ifndef XREATE_ARRAYSIR_H +ifndef XREATE_ARRAYSIR_H #define XREATE_ARRAYSIR_H #include "compilation/containers.h" namespace xreate { namespace containers{ -class ArrayIR; +class IFwdIteratorIR; /** \brief The contiguous container implementation. * * Represents contiguous in memory(array) implementation. * \sa xreate::containers::IFwdIteratorIR, \sa xreate::containers::Query */ -template<> -class FwdIteratorIR: public IFwdIteratorIR { - ArrayIR* __arraysIR; - -public: - FwdIteratorIR(ArrayIR* arraysIR): __arraysIR(arraysIR) {}; - - virtual llvm::Value* begin() override; - virtual llvm::Value* end() override; - virtual llvm::Value* get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintRetVar="") override; - virtual llvm::Value* advance(llvm::Value* idxRaw, const std::string& hintAlias="") override; -}; - class ArrayIR : public IContainersIR{ friend class FwdIteratorIR; public: - ArrayIR(const compilation::Context &context, const ExpandedType &aggrT, const typehints::Array &hints) + ArrayIR(const ExpandedType &aggrT, const typehints::ArrayHint &hints, const compilation::Context &context) : __context(context), __aggrT(aggrT), __hints(hints){} virtual llvm::Value *init(const std::string &hintAlias = "") override; virtual llvm::Value *update(llvm::Value *aggrRaw, const Expression &updE, const std::string &hintAlias) override; virtual IFwdIteratorIR* getFwdIterator() override; llvm::Value *get(llvm::Value *aggrRaw, std::vector idxL, const std::string &hintAlias); llvm::ArrayType *getRawT(); + /** \brief `loop map` statement compilation*/ + llvm::Value* operatorMap(const Expression& expr, const std::string& hintAlias); + private: compilation::Context __context; ExpandedType __aggrT; - typehints::Array __hints; + typehints::ArrayHint __hints; +}; + +template<> +class FwdIteratorIR: public IFwdIteratorIR { +public: + FwdIteratorIR(const ArrayIR& arraysIR): __compiler(arraysIR) {}; + + virtual llvm::Value* begin() override; + virtual llvm::Value* end() override; + virtual llvm::Value* get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintAlias="") override; + virtual llvm::Value* advance(llvm::Value* idxRaw, const std::string& hintAlias="") override; + +private: + ArrayIR __compiler; }; }} // xreate::containers #endif //XREATE_ARRAYSIR_H diff --git a/cpp/src/compilation/control.cpp b/cpp/src/compilation/control.cpp index c300b7e..3c55f04 100644 --- a/cpp/src/compilation/control.cpp +++ b/cpp/src/compilation/control.cpp @@ -1,441 +1,393 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: InstructionsAdvanced.cpp * Author: pgess * * Created on June 26, 2016, 6:00 PM */ #include "analysis/typeinference.h" #include "compilation/control.h" #include "compilation/containers.h" #include "compilation/transformersaturation.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::IBruteScope* scope = context.scope; \ compilation::IBruteFunction* function = context.function; ControlIR::ControlIR(compilation::Context ctx) : context(ctx), tyNum(static_cast (ctx.pass->man->llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::Int))))) { } -llvm::Value* -ControlIR::compileMapSolidOutput(const Expression &expr, const std::string hintRetVar) { - assert(false); return nullptr; - EXPAND_CONTEXT UNUSED(scope); - -// //initializationcompileListAsSolidArray -// 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]; -// -// IFwdIteratorIR* it = IFwdIteratorIR::create(context, symbolIn); -// llvm::Value *rangeFrom = it->begin(); -// llvm::Value *rangeTo = it->end(); -// -// //definitions -// ArrayType* tyNumArray = nullptr; //(ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::Int, size)))); -// llvm::IRBuilder<> &builder = llvm->irBuilder; -// -// llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm->llvmContext, "loop", function->raw); -// llvm::BasicBlock *blockBeforeLoop = builder.GetInsertBlock(); -// llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm->llvmContext, "postloop", function->raw); -// Value* dataOut = llvm->irBuilder.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::IBruteScope* 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* ControlIR::compileStructIndex(llvm::Value* aggregate, ExpandedType aggrT, const list& indices) { EXPAND_CONTEXT UNUSED(scope); UNUSED(function); TypesHelper types(llvm); llvm::Value* result = aggregate; assert(indices.size()); for (const string& indexField: indices){ const std::vector& tyfields = types.getRecordFields(aggrT); unsigned idx = -1; bool flagFound = false; for (unsigned i = 0, size = tyfields.size(); i < size; ++i) { if (tyfields.at(i) == indexField) { idx = i; flagFound = true; break; } } if (flagFound){ result = llvm->irBuilder.CreateExtractValue(result, llvm::ArrayRef{idx}); aggrT = typeinference::getSubtype(aggrT, indexField); } else { assert(false && "not found required struct field"); } } return result; //dereference pointer //if (types.isPointerT(t)) { // llvm::Value* addr = llvm->irBuilder.CreateConstGEP2_32(nullptr, aggregate, 0, i); // return llvm->irBuilder.CreateLoad(addr); //} } llvm::Value* ControlIR::compileFold(const Expression& loopE, const std::string& hintAlias) { EXPAND_CONTEXT assert(loopE.op == Operator::FOLD); AST* ast = context.pass->man->root; + //initialization: const Expression aggrE = loopE.getOperands().at(0); + const ExpandedType& aggrT = ast->getType(aggrE); llvm::Value* aggrRaw = context.scope->process(aggrE); - std::unique_ptr containerIR(IContainersIR::create(aggrE, TypeAnnotation(), context)); - IFwdIteratorIR* aggrItIR = containerIR->getFwdIterator(); + + IFwdIteratorIR* aggrItIR = IFwdIteratorIR::create(aggrE, aggrT, context); llvm::Value* idxBeginRaw = aggrItIR->begin(); llvm::Value* idxEndRaw = aggrItIR->end(); ExpandedType loopT = ast->getType(loopE); std::string elAlias = loopE.bindings[0]; std::string accumAlias = loopE.bindings[1]; const Expression& accumE = loopE.getOperands().at(1); ExpandedType accumT = ast->getType(accumE, loopT.get()); llvm::Type* accumRawT = llvm->toLLVMType(accumT); llvm::Value* accumInitRaw = scope->process(accumE, accumAlias, accumT.get()); - llvm::BasicBlock *blockBeforeLoop = llvm->irBuilder.GetInsertBlock(); - std::unique_ptr transformerSaturation(new TransformerSaturation(blockBeforeLoop, context.pass->managerTransformations)); - - llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm->llvmContext, "fold", function->raw); - llvm::BasicBlock *blockLoopBody = llvm::BasicBlock::Create(llvm->llvmContext, "fold_body", function->raw); - llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm->llvmContext, "fold_after", function->raw); - llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm->llvmContext, "fold_next", function->raw); + llvm::BasicBlock *blockProlog = llvm::BasicBlock::Create(llvm->llvmContext, "fold_prlg", function->raw); + llvm::BasicBlock *blockHeader = llvm::BasicBlock::Create(llvm->llvmContext, "fold_hdr", function->raw); + llvm::BasicBlock *blockBody = llvm::BasicBlock::Create(llvm->llvmContext, "fold", function->raw); + llvm::BasicBlock *blockFooter = llvm::BasicBlock::Create(llvm->llvmContext, "fold_ftr", function->raw); + llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "fold_eplg", function->raw); - llvm->irBuilder.CreateBr(blockLoop); + std::unique_ptr transformerSaturation(new TransformerSaturation(blockProlog, context.pass->managerTransformations)); + //Header: // * create phi - llvm->irBuilder.SetInsertPoint(blockLoop); + llvm->irBuilder.SetInsertPoint(blockHeader); llvm::PHINode *accum = llvm->irBuilder.CreatePHI(accumRawT, 2, accumAlias); - accum->addIncoming(accumInitRaw, blockBeforeLoop); + accum->addIncoming(accumInitRaw, blockProlog); llvm::PHINode *idxCurrentRaw = llvm->irBuilder.CreatePHI(idxBeginRaw->getType(), 2, "foldIt"); - idxCurrentRaw->addIncoming(idxBeginRaw, blockBeforeLoop); + idxCurrentRaw->addIncoming(idxBeginRaw, blockProlog); // * loop checks Value* condRange = llvm->irBuilder.CreateICmpNE(idxCurrentRaw, idxEndRaw); - llvm->irBuilder.CreateCondBr(condRange, blockLoopBody, blockAfterLoop); + llvm->irBuilder.CreateCondBr(condRange, blockBody, blockEpilog); - // * loop body - llvm->irBuilder.SetInsertPoint(blockLoopBody); + //Body: + llvm->irBuilder.SetInsertPoint(blockBody); CodeScope* scopeLoop = loopE.blocks.front(); compilation::IBruteScope* loopUnit = function->getScopeUnit(scopeLoop); Value* elIn = aggrItIR->get(aggrRaw, idxCurrentRaw); loopUnit->bindArg(accum, move(accumAlias)); loopUnit->bindArg(elIn, move(elAlias)); Value* accumNext = loopUnit->compile(); // * Loop saturation checks - bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockNext, blockAfterLoop, context); + bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockFooter, blockEpilog, context); llvm::BasicBlock* blockSaturation = llvm->irBuilder.GetInsertBlock(); if (!flagSaturationTriggered){ - llvm->irBuilder.CreateBr(blockNext); + llvm->irBuilder.CreateBr(blockFooter); } + //Footer: // * computing next iteration state - llvm->irBuilder.SetInsertPoint(blockNext); + llvm->irBuilder.SetInsertPoint(blockFooter); Value *itLoopNext = aggrItIR->advance(idxCurrentRaw); accum->addIncoming(accumNext, llvm->irBuilder.GetInsertBlock()); idxCurrentRaw->addIncoming(itLoopNext, llvm->irBuilder.GetInsertBlock()); - llvm->irBuilder.CreateBr(blockLoop); + llvm->irBuilder.CreateBr(blockHeader); + + //Prolog: + llvm->irBuilder.SetInsertPoint(context.scope->lastBlockRaw); + llvm->irBuilder.CreateBr(blockProlog); + + llvm->irBuilder.SetInsertPoint(blockProlog); + llvm->irBuilder.CreateBr(blockHeader); - // * finalization: - llvm->irBuilder.SetInsertPoint(blockAfterLoop); + // Epilog: + llvm->irBuilder.SetInsertPoint(blockEpilog); if (!flagSaturationTriggered){ return accum; } llvm::PHINode* result = llvm->irBuilder.CreatePHI(accumRawT, 2, hintAlias); - result->addIncoming(accum, blockLoop); + result->addIncoming(accum, blockHeader); result->addIncoming(accumNext, blockSaturation); return result; } llvm::Value* ControlIR::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->irBuilder.GetInsertBlock(); llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm->llvmContext, "foldinf", function->raw); llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm->llvmContext, "foldinf_next", function->raw); llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm->llvmContext, "foldinf_post", function->raw); std::unique_ptr transformerSaturation(new TransformerSaturation(blockBeforeLoop, context.pass->managerTransformations)); llvm->irBuilder.CreateBr(blockLoop); // * create phi llvm->irBuilder.SetInsertPoint(blockLoop); llvm::PHINode *accum = llvm->irBuilder.CreatePHI(accumInit->getType(), 2, accumName); accum->addIncoming(accumInit, blockBeforeLoop); // * loop body CodeScope* scopeLoop = fold.blocks.front(); compilation::IBruteScope* 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->irBuilder.SetInsertPoint(blockNext); accum->addIncoming(accumNext, llvm->irBuilder.GetInsertBlock()); llvm->irBuilder.CreateBr(blockLoop); // finalization: llvm->irBuilder.SetInsertPoint(blockAfterLoop); return accumNext; } llvm::Value* ControlIR::compileIf(const Expression& exprIf, const std::string& hintRetVar) { EXPAND_CONTEXT const Expression& condExpr = exprIf.getOperands()[0]; llvm::IRBuilder<>& builder = llvm->irBuilder; - assert(builder.GetInsertBlock() == scope->currentBlockRaw); + assert(builder.GetInsertBlock() == scope->lastBlockRaw); //initialization: llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "ifAfter", function->raw); llvm::BasicBlock *blockTrue = llvm::BasicBlock::Create(llvm->llvmContext, "ifTrue", function->raw); llvm::BasicBlock *blockFalse = llvm::BasicBlock::Create(llvm->llvmContext, "ifFalse", function->raw); llvm::Value* cond = scope->process(condExpr); builder.SetInsertPoint(blockTrue); CodeScope* scopeTrue = exprIf.blocks.front(); llvm::Value* resultTrue = function->getScopeUnit(scopeTrue)->compile(); llvm::BasicBlock * blockTrueEnd = builder.GetInsertBlock(); builder.CreateBr(blockEpilog); builder.SetInsertPoint(blockFalse); CodeScope* scopeFalse = exprIf.blocks.back(); llvm::Value* resultFalse = function->getScopeUnit(scopeFalse)->compile(); llvm::BasicBlock * blockFalseEnd = builder.GetInsertBlock(); builder.CreateBr(blockEpilog); - builder.SetInsertPoint(scope->currentBlockRaw); + builder.SetInsertPoint(scope->lastBlockRaw); llvm->irBuilder.CreateCondBr(cond, blockTrue, blockFalse); builder.SetInsertPoint(blockEpilog); llvm::PHINode *ret = builder.CreatePHI(resultTrue->getType(), 2, NAME("if")); ret->addIncoming(resultTrue, blockTrueEnd); ret->addIncoming(resultFalse, blockFalseEnd); return ret; } //TODO Switch: default variant no needed when all possible conditions are considered llvm::Value* ControlIR::compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(function); AST* root = context.pass->man->root; llvm::IRBuilder<>& builder = llvm->irBuilder; 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::BasicBlock* blockProlog = builder.GetInsertBlock(); llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "switchAfter", function->raw); builder.SetInsertPoint(blockEpilog); llvm::Type* exprSwitchType = llvm->toLLVMType(root->getType(exprSwitch)); llvm::PHINode *ret = builder.CreatePHI(exprSwitchType, countCases, NAME("switch")); llvm::Type* typI8 = llvm::Type::getInt8Ty(llvm->llvmContext); builder.SetInsertPoint(blockProlog); llvm::Value * conditionSwitch = scope->process(exprSwitch.operands[0]); llvm::BasicBlock *blockDefault = llvm::BasicBlock::Create(llvm->llvmContext, "caseDefault", function->raw); llvm::SwitchInst * instructionSwitch = builder.CreateSwitch( typeinference::doAutomaticTypeConversion(conditionSwitch, typI8, builder), blockDefault, countCases); for (int size = exprSwitch.operands.size(), i = 2; i < size; ++i) { llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm->llvmContext, "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( typeinference::doAutomaticTypeConversion(condCase, typI8, builder)), 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; } llvm::Value* ControlIR::compileSwitchVariant(const Expression& exprSwitch, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(function); AST* root = context.pass->man->root; llvm::IRBuilder<>& builder = llvm->irBuilder; llvm::Type* typI8= llvm::Type::getInt8Ty(llvm->llvmContext); const ExpandedType& typVariant = root->getType(exprSwitch.operands.at(0)); llvm::Type* typVariantRaw = llvm->toLLVMType(typVariant); assert(typVariant->__operands.size() == exprSwitch.operands.size() - 1 && "Ill-formed Switch Variant"); int casesCount = exprSwitch.operands.size(); llvm::BasicBlock* blockProlog = builder.GetInsertBlock(); llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "switchAfter", function->raw); builder.SetInsertPoint(blockEpilog); llvm::Type* resultType = llvm->toLLVMType(root->getType(exprSwitch)); llvm::PHINode *ret = builder.CreatePHI(resultType, casesCount, NAME("switch")); builder.SetInsertPoint(blockProlog); llvm::Value * conditionSwitchRaw = scope->process(exprSwitch.operands.at(0)); llvm::Value* idRaw = builder.CreateExtractValue(conditionSwitchRaw, llvm::ArrayRef({0})); //Dereference preparation const bool flagPrepareDerefence = std::any_of(typVariant->__operands.begin(), typVariant->__operands.end(), [](const TypeAnnotation& op){ return op.isValid(); }); llvm::Value* addrAsStorage = nullptr; if (flagPrepareDerefence){ assert(exprSwitch.bindings.size() && "Switch condition alias not found"); llvm::Type* typStorageRaw = llvm::cast(typVariantRaw)->getElementType(1); llvm::Value* storageRaw = builder.CreateExtractValue(conditionSwitchRaw, llvm::ArrayRef({1})); addrAsStorage = llvm->irBuilder.CreateAlloca(typStorageRaw); llvm->irBuilder.CreateStore(storageRaw, addrAsStorage); } llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(idRaw, nullptr, casesCount); llvm::BasicBlock* blockDefaultUndefined; std::list::const_iterator scopeCaseIt = exprSwitch.blocks.begin(); for (int instancesSize = exprSwitch.operands.size()-1, instId = 0; instId < instancesSize; ++instId) { llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm->llvmContext, "case" + std::to_string(instId), function->raw); builder.SetInsertPoint(blockCase); IBruteScope* unitCase = function->getScopeUnit(*scopeCaseIt); const ExpandedType& instType = ExpandedType(typVariant->__operands.at(instId)); //Actual variant derefence if (instType->isValid()) { string identCondition = exprSwitch.bindings.front(); llvm::Type* instTypeRaw = llvm->toLLVMType(instType); llvm::Value* addrAsInst = llvm->irBuilder.CreateBitOrPointerCast(addrAsStorage, instTypeRaw->getPointerTo()); llvm::Value* instRaw = llvm->irBuilder.CreateLoad(instTypeRaw, addrAsInst); const Symbol& identSymb = unitCase->bindArg(instRaw, move(identCondition)); Attachments::put(identSymb, instType); } llvm::Value* resultCase = function->getScopeUnit(*scopeCaseIt)->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultCase, blockDefaultUndefined = builder.GetInsertBlock()); builder.SetInsertPoint(blockProlog); instructionSwitch->addCase(dyn_cast(llvm::ConstantInt::get(typI8, exprSwitch.operands.at(instId+1).getValueDouble())), blockCase); ++scopeCaseIt; } instructionSwitch->setDefaultDest(blockDefaultUndefined); builder.SetInsertPoint(blockEpilog); return ret; } llvm::Value* ControlIR::compileConstantStringAsPChar(const string& data, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(function); UNUSED(scope); Type* typPchar = PointerType::getUnqual(Type::getInt8Ty(llvm->llvmContext)); //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->llvmContext, data); Value* rawPtrData = llvm->irBuilder.CreateAlloca(rawData->getType(), ConstantInt::get(Type::getInt32Ty(llvm->llvmContext), 1, false)); llvm->irBuilder.CreateStore(rawData, rawPtrData); return llvm->irBuilder.CreateCast(llvm::Instruction::BitCast, rawPtrData, typPchar, hintRetVar); } llvm::Value* ControlIR::compileSequence(const Expression &expr){ EXPAND_CONTEXT UNUSED(scope); UNUSED(llvm); llvm::Value* result; for(CodeScope* scope: expr.blocks){ result = function->getScopeUnit(scope)->compile(); } return result; } diff --git a/cpp/src/compilation/demand.h b/cpp/src/compilation/demand.h index 9a9e64b..44e6f0c 100644 --- a/cpp/src/compilation/demand.h +++ b/cpp/src/compilation/demand.h @@ -1,101 +1,101 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* * Author: pgess * Created on June 23, 2018, 2:51 PM * */ #ifndef LATEX_H #define LATEX_H #include "query/demand.h" #include "analysis/utils.h" #include "pass/compilepass.h" namespace xreate{namespace demand{ template class DemandBruteFnDecorator : public Parent{ public: DemandBruteFnDecorator(ManagedFnPtr f, CompilePass *p): Parent(f, p){} protected: std::vector prepareSignature() override{ std::vector &&signature = Parent::prepareSignature(); DemandQuery* query = reinterpret_cast (Parent::pass->man->transcend->getQuery(QueryId::DemandQuery)); - const Demand& demand = query->getFnDemand(Parent::function->getName()); + const Demand& demand = query->getFnDemand(Parent::__function->getName()); signature.reserve(signature.size() + demand.size()); unsigned int argOffset = signature.size(); for(const auto &rec: demand){ TypeAnnotation argTCust(TypeOperator::ALIAS, {}); argTCust.__valueCustom = rec.second; const ExpandedType &argT = Parent::pass->man->root->expandType(argTCust); Expression bindingE; - bindingE.type = argT; + bindingE.type = argT.get(); llvm::Type *argTRaw = Parent::pass->man->llvm->toLLVMType(argT); - Parent::function->addBinding( + Parent::__function->addBinding( Atom(std::string(rec.first)), std::move(bindingE), argOffset++ ); signature.push_back(argTRaw); } return signature; } }; /** * \brief Latex aware \ref xreate::compilation::IBruteScope decorator * \implements xreate::compilation::IBruteScope */ template class DemandBruteScopeDecorator : public Parent{ public: DemandBruteScopeDecorator(const CodeScope *const codeScope, compilation::IBruteFunction *f, CompilePass *compilePass) : Parent(codeScope, f, compilePass){} compilation::IFnInvocation * findFunction(const Expression& opCall){ DemandQuery* query = reinterpret_cast (Parent::pass->man->transcend->getQuery(QueryId::DemandQuery)); const std::string &calleeName = opCall.getValueString(); compilation::IFnInvocation *opInvocBase = Parent::findFunction(opCall); const Demand &demand = query->getFnDemand(calleeName); if(!demand.size()) return opInvocBase; //prepare additional arguments std::vector argsDemand; argsDemand.reserve(demand.size()); const Supply& argsActual = query->getFnSupply(ASTSite{opCall.id}); for(const auto& arg: demand){ TypeAnnotation argTCust(TypeOperator::ALIAS, {}); argTCust.__valueCustom = arg.second; const ExpandedType &argScheme = Parent::pass->man->root->expandType(argTCust); //llvm::Type* argSchemeRaw = Parent::pass->man->llvm->toLLVMType(argScheme); const Gringo::Symbol argTrAtom = argsActual.at(arg.first); Expression argE = analysis::representTransExpression(argTrAtom, argScheme, Parent::pass->man->transcend); - argE.type = argScheme; + argE.type = argScheme.get(); llvm::Value* argValueRaw = Parent::process(argE); argsDemand.push_back(argValueRaw); } return new compilation::HiddenArgsFnInvocation(std::move(argsDemand), opInvocBase); } }; }} //end of namespace xreate::demand #endif /* LATEX_H */ diff --git a/cpp/src/compilation/lambdas.cpp b/cpp/src/compilation/lambdas.cpp new file mode 100644 index 0000000..f2d6ce1 --- /dev/null +++ b/cpp/src/compilation/lambdas.cpp @@ -0,0 +1,65 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: lambdas.cpp + * Author: pgess + * + * Created in April, 2020 + */ + +#include "compilation/lambdas.h" +#include "llvmlayer.h" +#include "compilation/resources.h" + +using namespace xreate::compilation; +using namespace std; + +unsigned LambdaBruteFn::__counter = 0; + +std::string +LambdaBruteFn::prepareName(){ + return string(LAMBDA_PREFIX) + "_" + __hintAlias + "_" + to_string(__counter++); +} + +std::vector +LambdaBruteFn::prepareSignature(){ + return getScopeSignature(IBruteFunction::__entry); +} + +llvm::Type* +LambdaBruteFn::prepareResult(){ + LLVMLayer* llvm = IBruteFunction::pass->man->llvm; + AST* ast = IBruteFunction::pass->man->root; + + return llvm->toLLVMType(ast->getType(__entry->getBody())); +} + +llvm::Function::arg_iterator +LambdaBruteFn::prepareBindings(){ + CodeScope* entry = IBruteFunction::__entry; + IBruteScope* entryCompilation = IBruteFunction::getScopeUnit(entry); + llvm::Function::arg_iterator fargsI = IBruteFunction::raw->arg_begin(); + + for (std::string &arg : entry->__bindings) { + ScopedSymbol argid{entry->__identifiers[arg], versions::VERSION_NONE}; + + entryCompilation->bindArg(&*fargsI, argid); + fargsI->setName(arg); + ++fargsI; + } + + return fargsI; +} + +void +LambdaBruteFn::applyAttributes(){ + raw->addFnAttr(llvm::Attribute::AlwaysInline); +} + +llvm::Function* +LambdaIR::compile(CodeScope* body, const std::string& hintAlias){ + LambdaBruteFn fnLambda(body, __pass, hintAlias); + + return fnLambda.compile(); +} diff --git a/cpp/src/compilation/lambdas.h b/cpp/src/compilation/lambdas.h new file mode 100644 index 0000000..900b151 --- /dev/null +++ b/cpp/src/compilation/lambdas.h @@ -0,0 +1,52 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: lambdas.h + * Author: pgess + * + * Created in April, 2020 + */ + +#ifndef XREATE_LAMBDAS_H +#define XREATE_LAMBDAS_H + +#include "pass/compilepass.h" + +namespace llvm { + class Function; +} + +namespace xreate { namespace compilation { + +class LambdaBruteFn: public IBruteFunction { +public: + LambdaBruteFn(CodeScope* entry, CompilePass* p, const std::string& hintAlias) + : IBruteFunction(entry, p), __hintAlias(hintAlias) {} + +protected: + virtual std::string prepareName() override; + virtual std::vector prepareSignature() override; + virtual llvm::Function::arg_iterator prepareBindings() override; + virtual llvm::Type* prepareResult() override; + virtual void applyAttributes() override; + +private: + std::string __hintAlias; + static unsigned __counter; +}; + +class LambdaIR{ +public: + LambdaIR(CompilePass* p): __pass(p){} + llvm::Function* compile(CodeScope* body, const std::string& hintAlias); + +private: + compilation::Context __context; + CompilePass* __pass; + +}; + +}} + +#endif //XREATE_LAMBDAS_H diff --git a/cpp/src/compilation/resources.cpp b/cpp/src/compilation/resources.cpp new file mode 100644 index 0000000..f7c6b43 --- /dev/null +++ b/cpp/src/compilation/resources.cpp @@ -0,0 +1,15 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: pgess + * File: resources.h + * + * Created in April, 2020 + */ + +#include "compilation/resources.h" + +namespace xreate{namespace compilation { +const char *LAMBDA_PREFIX = ".lmd"; +}} // end of xreate::compilation \ No newline at end of file diff --git a/cpp/src/compilation/resources.h b/cpp/src/compilation/resources.h new file mode 100644 index 0000000..319714a --- /dev/null +++ b/cpp/src/compilation/resources.h @@ -0,0 +1,20 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: pgess + * File: resources.h + * + * Created in April, 2020 + */ + +#ifndef XREATE_RESOURCES_H +#define XREATE_RESOURCES_H + +#include + +namespace xreate{namespace compilation{ +extern const char *LAMBDA_PREFIX; +}} // end of xreate::compilation + +#endif //XREATE_RESOURCES_H diff --git a/cpp/src/compilation/targetinterpretation.cpp b/cpp/src/compilation/targetinterpretation.cpp index a41bac5..02d4b9d 100644 --- a/cpp/src/compilation/targetinterpretation.cpp +++ b/cpp/src/compilation/targetinterpretation.cpp @@ -1,648 +1,648 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: targetinterpretation.cpp * Author: pgess * * Created on June 29, 2016, 6:45 PM */ /** * \file targetinterpretation.h * \brief Interpretation support. See more details on [Interpretation](/d/concepts/interpretation/) */ #include "compilation/targetinterpretation.h" #include "pass/interpretationpass.h" #include "analysis/typeinference.h" #include "llvmlayer.h" #include "compilation/decorators.h" #include "compilation/i12ninst.h" #include "compilation/intrinsics.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)); 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; i < size; ++i) { const Expression& exprCase = process(expression.operands[i]); if (function->getScope((const CodeScope*) exprCase.blocks.front())->processScope() == exprCondition) { return exprCase.blocks.back(); } } if (flagHasDefault) { const Expression& exprCaseDefault = expression.operands[1]; return exprCaseDefault.blocks.front(); } assert(false && "Switch has no appropriate variant"); return nullptr; } CodeScope* InterpretationScope::processOperatorSwitchVariant(const Expression& expression) { const ExpandedType& conditionT = function->__pass->man->root->getType(expression.operands.at(0)); const Expression& conditionE = process(expression.operands.at(0)); assert(conditionE.op == Operator::VARIANT); const string& aliasS = expression.bindings.front(); unsigned caseExpectedId = (int) conditionE.getValueDouble(); auto itFoundValue = std::find_if(++expression.operands.begin(), expression.operands.end(), [caseExpectedId](const auto& caseActualE){ return (unsigned) caseActualE.getValueDouble() == caseExpectedId; }); assert(itFoundValue != expression.operands.end()); int caseScopeId = itFoundValue - expression.operands.begin() - 1; auto caseScopeRef = expression.blocks.begin(); std::advance(caseScopeRef, caseScopeId); InterpretationScope* scopeI12n = function->getScope(*caseScopeRef); if(conditionE.operands.size()) { Expression valueE(Operator::LIST, {}); valueE.operands = conditionE.operands; valueE.bindings = conditionT->__operands.at(caseExpectedId).fields; scopeI12n->overrideBindings({ {valueE, aliasS} }); }; return *caseScopeRef; } llvm::Value* InterpretationScope::processLate(const InterpretationOperator& op, const Expression& expression, const Context& context, const std::string& hintAlias) { 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& condCrudeE = expression.operands.at(0); const Expression& condE = process(condCrudeE); const string identCondition = expression.bindings.front(); auto scopeCompilation = Decorators::getInterface(context.function->getScopeUnit(scopeResult)); if(condE.operands.size()) { //override value Symbol symbCondition{ScopedSymbol{scopeResult->__identifiers.at(identCondition), versions::VERSION_NONE}, scopeResult}; scopeCompilation->overrideDeclarations({ {symbCondition, Expression(condE.operands.at(0))}} ); //set correct type for binding: - TypeAnnotation typeVariant = function->__pass->man->root->getType(condCrudeE); + const ExpandedType& typeVariant = function->__pass->man->root->getType(condCrudeE); int conditionIndex = condE.getValueDouble(); ScopedSymbol symbolInternal = scopeResult->getSymbol(identCondition); - scopeResult->__declarations[symbolInternal].bindType(typeVariant.__operands.at(conditionIndex)); + scopeResult->__declarations[symbolInternal].bindType(typeVariant->__operands.at(conditionIndex)); } llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); return result; } case SWITCH_LATE: { return nullptr; // latereasoning::LateReasoningCompiler compiler(dynamic_cast(this->function), context); // return compiler.processSwitchLateStatement(expression, ""); } case FOLD_INTERPRET_INPUT: { //initialization const Expression& containerE = process(expression.getOperands().at(0)); const TypeAnnotation& accumT = expression.type; assert(containerE.op == Operator::LIST); CodeScope* bodyScope = expression.blocks.front(); const string& elAlias = expression.bindings[0]; Symbol elS{ScopedSymbol{bodyScope->__identifiers.at(elAlias), versions::VERSION_NONE}, bodyScope}; const std::string& accumAlias = expression.bindings[1]; llvm::Value* accumRaw = context.scope->process(expression.getOperands().at(1), accumAlias, accumT); InterpretationScope* bodyI12n = function->getScope(bodyScope); auto bodyBrute = Decorators::getInterface(context.function->getScopeUnit(bodyScope)); const std::vector& containerVec = containerE.getOperands(); for(size_t i = 0; i < containerVec.size(); ++i) { const Expression& elE = containerVec[i]; bodyI12n->overrideBindings({ {elE, elAlias} }); bodyBrute->overrideDeclarations({ {elS, elE} }); //resets bodyBrute bodyBrute->bindArg(accumRaw, string(accumAlias)); accumRaw = bodyBrute->compile(); accumRaw->getType()->print(llvm::outs()); llvm::outs() << "\n\n"; } return accumRaw; } // case FOLD_INF_INTERPRET_INOUT: // { // } //TODO refactor as InterpretationCallStatement class case CALL_INTERPRET_PARTIAL: { const std::string &calleeName = expression.getValueString(); IBruteScope* scopeUnitSelf = context.scope; ManagedFnPtr callee = this->function->__pass->man->root->findFunction(calleeName); const I12nFunctionSpec& calleeData = FunctionInterpretationHelper::getSignature(callee); std::vector argsActual; PIFnSignature 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->__pass); PIFunction* pifunction = man->getFunction(move(sig)); llvm::Function* raw = pifunction->compile(); boost::scoped_ptr statement(new BruteFnInvocation(raw, man->pass->man->llvm)); return (*statement)(move(argsActual)); } case QUERY_LATE: { return nullptr; // return IntrinsicQueryInstruction( // dynamic_cast(this->function)) // .processLate(expression, context); } default: break; } assert(false && "Unknown late interpretation operator"); return nullptr; } llvm::Value* InterpretationScope::compile(const Expression& expression, const Context& context, const std::string& hintAlias) { const InterpretationData& data = Attachments::get(expression); if (data.op != InterpretationOperator::NONE) { return processLate(data.op, expression, context, hintAlias); } Expression result = process(expression); return context.scope->process(result, hintAlias); } Expression InterpretationScope::process(const Expression& expression) { #ifndef NDEBUG if (expression.tags.count("bpoint")) { std::raise(SIGINT); } #endif PassManager* man = function->__pass->man; switch (expression.__state) { case Expression::INVALID: assert(false); case Expression::NUMBER: case Expression::STRING: return expression; case Expression::IDENT: { Symbol s = Attachments::get(expression); return Parent::processSymbol(s); } case Expression::COMPOUND: break; default: assert(false); } switch (expression.op) { case Operator::EQU: { const Expression& left = process(expression.operands[0]); const Expression& right = process(expression.operands[1]); if (left == right) return EXPRESSION_TRUE; return EXPRESSION_FALSE; } case Operator::NE: { const Expression& left = process(expression.operands[0]); const Expression& right = process(expression.operands[1]); if (left == right) return EXPRESSION_FALSE; return EXPRESSION_TRUE; } case Operator::LOGIC_AND: { assert(expression.operands.size() == 1); return process (expression.operands[0]); } // case Operator::LOGIC_OR: case Operator::CALL: { const std::string &fnName = expression.getValueString(); ManagedFnPtr fnAst = man->root->findFunction(fnName); InterpretationFunction* fnUnit = this->function->__pass->getFunction(fnAst); vector args; args.reserve(expression.getOperands().size()); for(size_t i = 0, size = expression.getOperands().size(); i < size; ++i) { args.push_back(process(expression.getOperands()[i])); } return fnUnit->process(args); } case Operator::CALL_INTRINSIC: { const Expression& opCallIntrCrude = expression; vector argsActual; argsActual.reserve(opCallIntrCrude.getOperands().size()); for(const auto& op: opCallIntrCrude.getOperands()) { argsActual.push_back(process(op)); } Expression opCallIntr(Operator::CALL_INTRINSIC, {}); opCallIntr.setValueDouble(opCallIntrCrude.getValueDouble()); opCallIntr.operands = argsActual; compilation::IntrinsicCompiler compiler(man); return compiler.interpret(opCallIntr); } case Operator::QUERY: { return Expression(); // return IntrinsicQueryInstruction(dynamic_cast(this->function)) // .process(expression); } case Operator::QUERY_LATE: { assert(false && "Can't be interpretated"); return Expression(); } case Operator::IF: { CodeScope* scopeResult = processOperatorIf(expression); return function->getScope(scopeResult)->processScope(); } case Operator::SWITCH: { CodeScope* scopeResult = processOperatorSwitch(expression); return function->getScope(scopeResult)->processScope(); } case Operator::SWITCH_VARIANT: { CodeScope* scopeResult = processOperatorSwitchVariant(expression); return function->getScope(scopeResult)->processScope(); } case Operator::VARIANT: { Expression result{Operator::VARIANT, {}}; result.setValueDouble(expression.getValueDouble()); for(const Expression& op: expression.operands){ result.operands.push_back(process(op)); } return result; } case Operator::INDEX: { Expression aggrE = process(expression.operands[0]); for (size_t keyId = 1; keyId < expression.operands.size(); ++keyId) { const Expression& keyE = process(expression.operands[keyId]); if (keyE.__state == Expression::STRING) { const string& fieldExpectedS = keyE.getValueString(); unsigned fieldId; for(fieldId = 0; fieldId < aggrE.bindings.size(); ++fieldId){ if (aggrE.bindings.at(fieldId) == fieldExpectedS){break;} } assert(fieldId < aggrE.bindings.size()); aggrE = Expression(aggrE.operands.at(fieldId)); continue; } if (keyE.__state == Expression::NUMBER) { int opId = keyE.getValueDouble(); aggrE = Expression(aggrE.operands.at(opId)); continue; } assert(false && "Inappropriate key"); } return aggrE; } 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; i < size; ++i) { body->overrideBindings({ {exprInput.getOperands()[i], argEl}, {accum, argAccum} }); accum = body->processScope(); } return accum; } case Operator::LIST: case Operator::LIST_RANGE: { Expression result(expression.op,{}); result.operands.resize(expression.operands.size()); result.bindings = expression.bindings; int keyId = 0; for(const Expression& opCurrent : expression.operands) { result.operands[keyId++] = process(opCurrent); } return result; } // case Operator::MAP: { // break; // } default: break; } return expression; } InterpretationFunction* TargetInterpretation::getFunction(IBruteFunction* unit) { if (__dictFunctionsByUnit.count(unit)) { return __dictFunctionsByUnit.at(unit); } - InterpretationFunction* f = new InterpretationFunction(unit->function, this); + InterpretationFunction* f = new InterpretationFunction(unit->getASTFn(), this); __dictFunctionsByUnit.emplace(unit, f); - assert(__functions.emplace(unit->function.id(), f).second); + assert(__functions.emplace(unit->getASTFn().id(), f).second); return f; } PIFunction* TargetInterpretation::getFunction(PIFnSignature&& sig) { auto f = __pifunctions.find(sig); if (f != __pifunctions.end()) { return f->second; } PIFunction* result = new PIFunction(PIFnSignature(sig), __pifunctions.size(), this); __pifunctions.emplace(move(sig), result); assert(__dictFunctionsByUnit.emplace(result->fnRaw, 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, const std::string& hintAlias) { return transformContext(ctx)->compile(expression, ctx, hintAlias); } InterpretationFunction::InterpretationFunction(const ManagedFnPtr& function, Target* target) : Function(function, target) { } Expression InterpretationFunction::process(const std::vector& args) { InterpretationScope* body = getScope(__function->__entry); list> bindings; for(size_t i = 0, size = args.size(); i < size; ++i) { bindings.push_back(make_pair(args.at(i), body->scope->__bindings.at(i))); } body->overrideBindings(bindings); return body->processScope(); } // Partial function interpretation typedef BasicBruteFunction BruteFunction; class PIBruteFunction : public BruteFunction{ public: PIBruteFunction(ManagedFnPtr f, std::set&& arguments, size_t id, CompilePass* p) : BruteFunction(f, p), argumentsActual(move(arguments)), __id(id) { } protected: std::vector prepareSignature() override { LLVMLayer* llvm = BruteFunction::pass->man->llvm; AST* ast = BruteFunction::pass->man->root; - CodeScope* entry = BruteFunction::function->__entry; + CodeScope* entry = IBruteFunction::__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() override{ - CodeScope* entry = BruteFunction::function->__entry; + CodeScope* entry = IBruteFunction::__entry; IBruteScope* entryCompilation = BruteFunction::getScopeUnit(entry); llvm::Function::arg_iterator fargsI = BruteFunction::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() override { return BruteFunction::prepareName() + "_" + std::to_string(__id); } private: std::set argumentsActual; size_t __id; } ; PIFunction::PIFunction(PIFnSignature&& sig, size_t id, TargetInterpretation* target) : InterpretationFunction(sig.declaration, target), instance(move(sig)) { const I12nFunctionSpec& functionData = FunctionInterpretationHelper::getSignature(instance.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); } } fnRaw = new PIBruteFunction(instance.declaration, move(argumentsActual), id, target->pass); CodeScope* entry = instance.declaration->__entry; auto entryUnit = Decorators::getInterface<>(fnRaw->getEntry()); InterpretationScope* entryIntrp = InterpretationFunction::getScope(entry); list> bindingsPartial; list> declsPartial; for(size_t no = 0, sigNo = 0, size = entry->__bindings.size(); no < size; ++no) { if(functionData.signature.at(no) == INTR_ONLY) { bindingsPartial.push_back({instance.bindings[sigNo], entry->__bindings[no]}); VNameId argId = entry->__identifiers.at(entry->__bindings[no]); Symbol argSymbol{ScopedSymbol {argId, versions::VERSION_NONE}, entry}; declsPartial.push_back({argSymbol, instance.bindings[sigNo]}); ++sigNo; } } entryIntrp->overrideBindings(bindingsPartial); entryUnit->overrideDeclarations(declsPartial); } llvm::Function* PIFunction::compile() { llvm::Function* raw = fnRaw->compile(); return raw; } bool operator<(const PIFnSignature& lhs, const PIFnSignature& rhs) { if (lhs.declaration.id() != rhs.declaration.id()) { return lhs.declaration.id() < rhs.declaration.id(); } return lhs.bindings < rhs.bindings; } bool operator<(const PIFnSignature& lhs, PIFunction * const rhs) { return lhs < rhs->instance; } bool operator<(PIFunction * const lhs, const PIFnSignature& rhs) { return lhs->instance < rhs; } } } /** \class xreate::interpretation::InterpretationFunction * * Holds list of xreate::interpretation::InterpretationScope 's focused on interpretation of individual code scopes * * There is particulat subclass PIFunction intended to represent partially interpreted functions. *\sa TargetInterpretation, [Interpretation Concept](/d/concepts/interpretation/) */ /** \class xreate::interpretation::TargetInterpretation * * TargetInterpretation is executed during compilation and is intended to preprocess eligible for interpretation parts of a source code. * * Keeps a list of InterpretationFunction / PIFunction that represent interpretation for an individual functions. * * There is \ref InterpretationScopeDecorator that embeds interpretation to an overall compilation process. * \sa InterpretationPass, compilation::Target, [Interpretation Concept](/d/concepts/interpretation/) * */ diff --git a/cpp/src/compilation/transformersaturation.cpp b/cpp/src/compilation/transformersaturation.cpp index 7dfc263..4f52f59 100644 --- a/cpp/src/compilation/transformersaturation.cpp +++ b/cpp/src/compilation/transformersaturation.cpp @@ -1,84 +1,83 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * transformersaturation.cpp * * Author: pgess * Created on March 25, 2017, 10:06 PM */ /** * \file transformersaturation.h * \brief Loop saturation support */ #include "transformersaturation.h" #include "llvmlayer.h" using namespace llvm; namespace xreate { namespace compilation { TransformerSaturation::TransformerSaturation(llvm::BasicBlock* allocationBlock, TransformationsManager* manager) : man(manager), blockAllocation(allocationBlock){ if (man->exists()){ oldInstance = man->update(this); } else { man->registerTransformer("final", this); } } TransformerSaturation::~TransformerSaturation(){ if (oldInstance) { man->update(oldInstance); } else { man->unregisterTransformer("final", this); } } llvm::Value* TransformerSaturation::transform(const Expression& expression, llvm::Value* raw, const Context& ctx){ processBreak(ctx); return raw; } - void TransformerSaturation::processBreak(const Context& ctx){ allocateFlag(ctx); //show the saturation flag llvm::IRBuilder<>& builder = ctx.pass->man->llvm->irBuilder; llvm::Type* tyInt1 = llvm::Type::getInt1Ty(ctx.pass->man->llvm->llvmContext); llvm::Constant* constTrue = llvm::ConstantInt::get(tyInt1, 1); builder.CreateStore(constTrue, flagSaturation, true); } void TransformerSaturation::allocateFlag(const Context& ctx){ //allocation of saturation flag IRBuilder<> builder(blockAllocation, blockAllocation->getFirstInsertionPt()); llvm::Type* tyInt1 = llvm::Type::getInt1Ty(ctx.pass->man->llvm->llvmContext); llvm::Constant* constTrue = llvm::ConstantInt::get(tyInt1, 1); flagSaturation = builder.CreateAlloca(tyInt1, constTrue, "flagSaturation"); llvm::Constant* constFalse = llvm::ConstantInt::get(tyInt1, 0); builder.CreateStore(constFalse, flagSaturation, true); } bool TransformerSaturation::insertSaturationChecks(llvm::BasicBlock* blockContinue, llvm::BasicBlock* blockExit, const Context& ctx){ if (!flagSaturation) return false; llvm::IRBuilder<>& builder = ctx.pass->man->llvm->irBuilder; builder.CreateCondBr(builder.CreateLoad(flagSaturation), blockExit, blockContinue); return true; } } } diff --git a/cpp/src/llvmlayer.cpp b/cpp/src/llvmlayer.cpp index 930d6bf..ac179d8 100644 --- a/cpp/src/llvmlayer.cpp +++ b/cpp/src/llvmlayer.cpp @@ -1,284 +1,283 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * llvmlayer.cpp * * Author: pgess */ /** * \file llvmlayer.h * \brief Bytecode generation */ #include "ast.h" #include "llvmlayer.h" #include "analysis/typehints.h" #ifdef XREATE_ENABLE_EXTERN #include "ExternLayer.h" #endif #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/MCJIT.h" #include "llvm/Support/TargetSelect.h" #include #include using namespace llvm; using namespace xreate; using namespace xreate::typehints; using namespace std; LLVMLayer::LLVMLayer(AST *root) : llvmContext(), irBuilder(llvmContext), ast(root), module(new llvm::Module(root->getModuleName(), llvmContext)){ llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); llvm::EngineBuilder builder; TargetMachine *target = builder.selectTarget(); module->setDataLayout(target->createDataLayout()); #ifdef XREATE_ENABLE_EXTERN layerExtern = new ExternLayer(this); layerExtern->init(root); #endif } void * LLVMLayer::getFunctionPointer(llvm::Function *function){ uint64_t entryAddr = jit->getFunctionAddress(function->getName().str()); return (void *) entryAddr; } void LLVMLayer::initJit(){ std::string ErrStr; llvm::EngineBuilder builder(std::unique_ptr(module.release())); jit.reset(builder .setEngineKind(llvm::EngineKind::JIT) .setErrorStr(&ErrStr) .setVerifyModules(true) .create() ); } void LLVMLayer::print(){ llvm::PassManager PM; PM.addPass(llvm::PrintModulePass(llvm::outs(), "banner")); llvm::AnalysisManager aman; PM.run(*module.get(), aman); } void LLVMLayer::moveToGarbage(void *o){ __garbage.push_back(o); } llvm::Type* LLVMLayer::toLLVMType(const ExpandedType &ty) const{ - TypeAnnotation t = ty; + TypeAnnotation t = ty.get(); switch(t.__operator){ case TypeOperator::ARRAY:{ //see ArrayIR::getRawT() return nullptr; } case TypeOperator::RECORD:{ std::vector packVec; packVec.reserve(t.__operands.size()); std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(packVec, packVec.end()), [this](const TypeAnnotation &t){ return toLLVMType(ExpandedType(TypeAnnotation(t))); }); llvm::ArrayRef packArr(packVec); return llvm::StructType::get(llvmContext, packArr, false); }; case TypeOperator::REF:{ TypeAnnotation tyRef = t.__operands.at(0); assert(tyRef.__operator == TypeOperator::ALIAS); llvm::StructType *tyOpaqRaw = llvm::StructType::create(llvmContext, tyRef.__valueCustom); llvm::PointerType *tyRefRaw = llvm::PointerType::get(tyOpaqRaw, 0); return tyRefRaw; }; case TypeOperator::ALIAS:{ #ifdef XREATE_ENABLE_EXTERN //Look in extern types clang::QualType qt = layerExtern->lookupType(t.__valueCustom); return layerExtern->toLLVMType(qt); #else assert(false); #endif }; //DEBT omit ID field in case of single variant. case TypeOperator::VARIANT:{ /* Variant Type Layout: * { * id :: i8, Holds stored variant id * storage:: type of biggest variant * } */ uint64_t sizeStorage = 0; llvm::Type *typStorageRaw = llvm::Type::getVoidTy(llvmContext); for(const TypeAnnotation &subtype : t.__operands){ llvm::Type *subtypeRaw = toLLVMType(ExpandedType(subtype)); if(subtypeRaw->isVoidTy()) continue; uint64_t sizeSubtype = module->getDataLayout().getTypeStoreSize(subtypeRaw); if(sizeSubtype > sizeStorage){ sizeStorage = sizeSubtype; typStorageRaw = subtypeRaw; } } std::vector layout; layout.push_back(llvm::Type::getInt8Ty(llvmContext)); //id const bool flagHoldsData = sizeStorage > 0; if(flagHoldsData){ layout.push_back(typStorageRaw); //storage } return llvm::StructType::get(llvmContext, llvm::ArrayRef(layout)); } case TypeOperator::NONE:{ switch(t.__value){ case TypePrimitive::Bool: return llvm::Type::getInt1Ty(llvmContext); case TypePrimitive::I8: return llvm::Type::getInt8Ty(llvmContext); case TypePrimitive::I32: return llvm::Type::getInt32Ty(llvmContext); case TypePrimitive::I64: return llvm::Type::getInt64Ty(llvmContext); case TypePrimitive::Int: { // IntBits hintSize; // if (existsSize(hintSize)){ // return llvm::IntegerType::getIntNTy(llvmContext, hintSize.n); // } TypesHelper helper(this); return helper.getPreferredIntTy(); } case TypePrimitive::Float: return llvm::Type::getDoubleTy(llvmContext); case TypePrimitive::String: return llvm::Type::getInt8PtrTy(llvmContext); case TypePrimitive::Invalid: return llvm::Type::getVoidTy(llvmContext); default: assert(false); } } default: assert(false); } assert(false); return nullptr; } bool TypesHelper::isRecordT(const ExpandedType &ty){ const TypeAnnotation &t = ty.get(); if(t.__operator == TypeOperator::RECORD){ return true; } if(t.__operator != TypeOperator::ALIAS){ return false; } #ifdef XREATE_ENABLE_EXTERN clang::QualType tqual = llvm->layerExtern->lookupType(t.__valueCustom); const clang::Type * raw = tqual.getTypePtr(); // TODO skip ALL the pointers until non-pointer type found if (raw->isStructureType()) return true; if (!raw->isAnyPointerType()) return false; clang::QualType pointee = raw->getPointeeType(); return pointee->isStructureType(); #else assert(false); return false; #endif } bool TypesHelper::isArrayT(const Expanded& ty){ const TypeAnnotation &t = ty.get(); if(t.__operator == TypeOperator::ARRAY){ return true; } return false; } bool TypesHelper::isPointerT(const ExpandedType &ty){ if(ty.get().__operator != TypeOperator::ALIAS) return false; #ifdef XREATE_ENABLE_EXTERN clang::QualType qt = llvm->layerExtern->lookupType(ty.get().__valueCustom); return llvm->layerExtern->isPointer(qt); #else assert(false); return false; #endif } - bool TypesHelper::isIntegerT(const Expanded& ty){ return (ty->__operator == TypeOperator::NONE) && ((ty->__value == TypePrimitive::Bool) || (ty->__value == TypePrimitive::I8) || (ty->__value == TypePrimitive::I32) || (ty->__value == TypePrimitive::I64) || (ty->__value == TypePrimitive::Int)); } std::vector TypesHelper::getRecordFields(const ExpandedType &t){ #ifdef XREATE_ENABLE_EXTERN return (t.get().__operator == TypeOperator::RECORD) ? t.get().fields : llvm->layerExtern->getStructFields( llvm->layerExtern->lookupType(t.get().__valueCustom)); #else assert(t.get().__operator == TypeOperator::RECORD); return t.get().fields; #endif } llvm::IntegerType * TypesHelper::getPreferredIntTy() const{ unsigned sizePreferred = llvm->module->getDataLayout().getLargestLegalIntTypeSizeInBits(); return llvm::IntegerType::getIntNTy(llvm->llvmContext, sizePreferred); } \ No newline at end of file diff --git a/cpp/src/llvmlayer.h b/cpp/src/llvmlayer.h index c93fc53..410cb25 100644 --- a/cpp/src/llvmlayer.h +++ b/cpp/src/llvmlayer.h @@ -1,73 +1,71 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * llvmlayer.h * * Author: pgess */ #ifndef LLVMLAYER_H #define LLVMLAYER_H #include "llvm/IR/Module.h" #include "llvm/IR/Function.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/Verifier.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/IRBuilder.h" #include "llvm/Support/raw_ostream.h" #include "llvm/IR/LLVMContext.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "utils.h" namespace xreate { class AST; class ExternLayer; class TypeAnnotation; /** \brief A wrapper over LLVM toolchain to generate and execute bytecode */ class LLVMLayer { public: LLVMLayer(AST* rootAST); mutable llvm::LLVMContext llvmContext; llvm::IRBuilder<> irBuilder; AST *ast = 0; ExternLayer *layerExtern =0; std::unique_ptr module; std::unique_ptr jit; void moveToGarbage(void *o); llvm::Type* toLLVMType(const Expanded& ty) const; void print(); void* getFunctionPointer(llvm::Function* function); void initJit(); private: llvm::Type* toLLVMType(const Expanded& ty, std::map& conjunctions) const; std::vector __garbage; }; class TypesHelper { public: bool isArrayT(const Expanded& ty); bool isRecordT(const Expanded& ty); bool isPointerT(const Expanded& ty); - bool isIntegerT(const Expanded& ty); llvm::IntegerType* getPreferredIntTy() const; - std::vector getRecordFields(const Expanded& t); TypesHelper(const LLVMLayer* llvmlayer): llvm(llvmlayer){} private: const LLVMLayer* llvm; }; } #endif // LLVMLAYER_H diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp index 35c2355..e3a6fc4 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,850 +1,879 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * * compilepass.cpp */ /** * \file compilepass.h * \brief Main compilation routine. See \ref xreate::CompilePass */ #include "compilepass.h" #include "transcendlayer.h" #include "ast.h" #include "llvmlayer.h" #include "compilation/decorators.h" #include "compilation/pointers.h" #include "analysis/typeinference.h" #include "compilation/control.h" #include "compilation/demand.h" #include "analysis/resources.h" #ifdef XREATE_ENABLE_EXTERN #include "ExternLayer.h" #endif #include "compilation/containers.h" #include "compilation/containers/arrays.h" #ifndef XREATE_CONFIG_MIN #include "query/containers.h" #include "pass/versionspass.h" #include "compilation/targetinterpretation.h" #endif #include #include using namespace std; using namespace llvm; +using namespace xreate::typehints; +using namespace xreate::containers; namespace xreate{ namespace compilation{ - #define DEFAULT(x) (hintAlias.empty()? x: hintAlias) std::string BasicBruteFunction::prepareName() { AST* ast = IBruteFunction::pass->man->root; - string name = ast->getFnSpecializations(IBruteFunction::function->__name).size() > 1 ? - IBruteFunction::function->__name + std::to_string(IBruteFunction::function.id()) : - IBruteFunction::function->__name; + string name = ast->getFnSpecializations(__function->__name).size() > 1 ? + __function->__name + std::to_string(__function.id()) : + __function->__name; return name; } std::vector BasicBruteFunction::prepareSignature() { - LLVMLayer* llvm = IBruteFunction::pass->man->llvm; - AST* ast = IBruteFunction::pass->man->root; - CodeScope* entry = IBruteFunction::function->__entry; - std::vector signature; + CodeScope* entry = __function->__entry; - std::transform(entry->__bindings.begin(), entry->__bindings.end(), std::inserter(signature, signature.end()), - [llvm, ast, entry](const std::string & arg)->llvm::Type* { - assert(entry->__identifiers.count(arg)); - - ScopedSymbol argid{entry->__identifiers.at(arg), versions::VERSION_NONE}; - return llvm->toLLVMType(ast->expandType(entry->__declarations.at(argid).type)); - }); - - return signature; + return getScopeSignature(entry); } llvm::Type* BasicBruteFunction::prepareResult() { LLVMLayer* llvm = IBruteFunction::pass->man->llvm; AST* ast = IBruteFunction::pass->man->root; - CodeScope* entry = IBruteFunction::function->__entry; + CodeScope* entry = __function->__entry; return llvm->toLLVMType(ast->expandType(entry->__declarations.at(ScopedSymbol::RetSymbol).type)); } llvm::Function::arg_iterator BasicBruteFunction::prepareBindings() { - CodeScope* entry = IBruteFunction::function->__entry; + CodeScope* entry = __function->__entry; IBruteScope* entryCompilation = IBruteFunction::getScopeUnit(entry); llvm::Function::arg_iterator fargsI = IBruteFunction::raw->arg_begin(); for (std::string &arg : entry->__bindings) { ScopedSymbol argid{entry->__identifiers[arg], versions::VERSION_NONE}; entryCompilation->bindArg(&*fargsI, argid); fargsI->setName(arg); ++fargsI; } return fargsI; } +void +BasicBruteFunction::applyAttributes(){} + IBruteScope::IBruteScope(const CodeScope * const codeScope, IBruteFunction* f, CompilePass* compilePass) -: pass(compilePass), function(f), scope(codeScope), currentBlockRaw(nullptr) { } +: pass(compilePass), function(f), scope(codeScope), lastBlockRaw(nullptr) { } llvm::Value* BruteFnInvocation::operator()(std::vector&& args, const std::string& hintDecl) { - llvm::Function* calleeInfo = dyn_cast(__callee); - - if (calleeInfo) { - auto argsFormal = calleeInfo->args(); - size_t sizeArgsF = std::distance(argsFormal.begin(), argsFormal.end()); - assert(args.size() >= sizeArgsF); - assert(calleeInfo->isVarArg() || args.size() == sizeArgsF); - - auto argFormal = argsFormal.begin(); - for(size_t argId = 0; argId < args.size(); ++argId){ - if(argFormal != argsFormal.end()){ - args[argId] = typeinference::doAutomaticTypeConversion( - args.at(argId), argFormal->getType(), llvm->irBuilder); - ++argFormal; - } - } - } - - //Do not name function call that returns Void. - std::string nameStatement = hintDecl; - if (calleeInfo->getReturnType()->isVoidTy()) { - nameStatement.clear(); + if (__calleeTy) { + auto argsFormalT = __calleeTy->params(); + size_t sizeArgsF = __calleeTy->getNumParams(); + assert(args.size() >= sizeArgsF); + assert(__calleeTy->isVarArg() || args.size() == sizeArgsF); + + auto argFormalT = argsFormalT.begin(); + for(size_t argId = 0; argId < args.size(); ++argId){ + if(argFormalT != argsFormalT.end()){ + args[argId] = typeinference::doAutomaticTypeConversion( + args.at(argId), *argFormalT, llvm->irBuilder); + ++argFormalT; + } } + } - return llvm->irBuilder.CreateCall(__calleeTy, __callee, args, nameStatement); + //Do not name function call that returns Void. + std::string hintName = (!__calleeTy->getReturnType()->isVoidTy()) ? hintDecl : ""; + return llvm->irBuilder.CreateCall(__calleeTy, __callee, args, hintName); } llvm::Value* HiddenArgsFnInvocation::operator() (std::vector&& args, const std::string& hintDecl) { args.insert(args.end(), __args.begin(), __args.end()); return __parent->operator ()(std::move(args), hintDecl); } class CallStatementInline : public IFnInvocation{ public: CallStatementInline(IBruteFunction* caller, IBruteFunction* callee, LLVMLayer* l) : __caller(caller), __callee(callee), llvm(l) { } llvm::Value* operator()(std::vector&& args, const std::string& hintDecl) { return nullptr; } private: IBruteFunction* __caller; IBruteFunction* __callee; LLVMLayer* llvm; bool isInline() { // Symbol ret = Symbol{0, function->__entry}; // bool flagOnTheFly = SymbolAttachments::get(ret, false); //TODO consider inlining return false; } } ; BasicBruteScope::BasicBruteScope(const CodeScope * const codeScope, IBruteFunction* f, CompilePass* compilePass) : IBruteScope(codeScope, f, compilePass) { } llvm::Value* BasicBruteScope::processSymbol(const Symbol& s, std::string hintRetVar) { - Expression declaration = CodeScope::getDefinition(s); - const CodeScope* scopeExternal = s.scope; - IBruteScope* scopeBruteExternal = IBruteScope::function->getScopeUnit(scopeExternal); - assert(scopeBruteExternal->currentBlockRaw); - - llvm::Value* resultRaw; - llvm::BasicBlock* blockOwn = pass->man->llvm->irBuilder.GetInsertBlock(); - - if (scopeBruteExternal->currentBlockRaw == blockOwn) { - resultRaw = scopeBruteExternal->process(declaration, hintRetVar); - scopeBruteExternal->currentBlockRaw = currentBlockRaw = - pass->man->llvm->irBuilder.GetInsertBlock(); - - } else { - pass->man->llvm->irBuilder.SetInsertPoint(scopeBruteExternal->currentBlockRaw); - resultRaw = scopeBruteExternal->processSymbol(s, hintRetVar); - pass->man->llvm->irBuilder.SetInsertPoint(blockOwn); - } + Expression declaration = CodeScope::getDefinition(s); + const CodeScope* scopeExternal = s.scope; + IBruteScope* scopeBruteExternal = IBruteScope::function->getScopeUnit(scopeExternal); + assert(scopeBruteExternal->lastBlockRaw); + + llvm::Value* resultRaw; + llvm::BasicBlock* blockOwn = pass->man->llvm->irBuilder.GetInsertBlock(); + + if (scopeBruteExternal->lastBlockRaw == blockOwn) { + resultRaw = scopeBruteExternal->process(declaration, hintRetVar); + scopeBruteExternal->lastBlockRaw = lastBlockRaw = + pass->man->llvm->irBuilder.GetInsertBlock(); + + } else { + pass->man->llvm->irBuilder.SetInsertPoint(scopeBruteExternal->lastBlockRaw); + resultRaw = scopeBruteExternal->processSymbol(s, hintRetVar); + pass->man->llvm->irBuilder.SetInsertPoint(blockOwn); + } - return resultRaw; + return resultRaw; } IFnInvocation* BasicBruteScope::findFunction(const Expression& opCall) { const std::string& calleeName = opCall.getValueString(); LLVMLayer* llvm = pass->man->llvm; const std::list& specializations = pass->man->root->getFnSpecializations(calleeName); #ifdef XREATE_ENABLE_EXTERN //if no specializations registered - check external function if (specializations.size() == 0) { llvm::Function* external = llvm->layerExtern->lookupFunction(calleeName); llvm::outs() << "Debug/External function: " << calleeName; external->getType()->print(llvm::outs(), true); llvm::outs() << "\n"; return new BruteFnInvocation(external, llvm); } #endif //There should be only one specialization without any valid guards at this point return new BruteFnInvocation(pass->getFunctionUnit( pass->man->root->findFunction(calleeName))->compile(), llvm); } //DISABLEDFEATURE transformations // if (pass->transformations->isAcceptable(expr)){ // return pass->transformations->transform(expr, result, ctx); // } llvm::Value* BasicBruteScope::process(const Expression& expr, const std::string& hintAlias, const TypeAnnotation& expectedT) { - llvm::Value *leftRaw; - llvm::Value *rightRaw; - LLVMLayer& l = *pass->man->llvm; - Context ctx{this, function, pass}; - xreate::compilation::ControlIR controlIR = xreate::compilation::ControlIR({this, function, pass}); - - switch (expr.op) { - case Operator::ADD: - case Operator::SUB: case Operator::MUL: case Operator::MOD: - case Operator::DIV: case Operator::EQU: case Operator::LSS: - case Operator::GTR: case Operator::NE: case Operator::LSE: - case Operator::GTE: - assert(expr.__state == Expression::COMPOUND); - assert(expr.operands.size() == 2); - - leftRaw = process(expr.operands.at(0)); - rightRaw = process(expr.operands.at(1)); - - break; + llvm::Value *leftRaw; + llvm::Value *rightRaw; + LLVMLayer& l = *pass->man->llvm; + Context ctx{this, function, pass}; + xreate::compilation::ControlIR controlIR = xreate::compilation::ControlIR({this, function, pass}); + + switch (expr.op) { + case Operator::ADD: + case Operator::SUB: case Operator::MUL: case Operator::MOD: + case Operator::DIV: case Operator::EQU: case Operator::LSS: + case Operator::GTR: case Operator::NE: case Operator::LSE: + case Operator::GTE: + assert(expr.__state == Expression::COMPOUND); + assert(expr.operands.size() == 2); + + leftRaw = process(expr.operands.at(0)); + rightRaw = process(expr.operands.at(1)); + + break; + + default:; + } - default:; + switch (expr.op) { + case Operator::AND: + { + assert(expr.operands.size()); + llvm::Value* resultRaw = process(expr.operands[0]); + for(size_t i=1; i< expr.operands.size()-1; ++i){ + resultRaw = l.irBuilder.CreateAnd(resultRaw, process(expr.operands.at(i))); } + return l.irBuilder.CreateAnd(resultRaw, process(expr.operands.at(expr.operands.size()-1)), hintAlias); + } - switch (expr.op) { - case Operator::AND: - { - assert(expr.operands.size()); - llvm::Value* resultRaw = process(expr.operands[0]); - for(size_t i=1; i< expr.operands.size()-1; ++i){ - resultRaw = l.irBuilder.CreateAnd(resultRaw, process(expr.operands.at(i))); - } - return l.irBuilder.CreateAnd(resultRaw, process(expr.operands.at(expr.operands.size()-1)), hintAlias); + case Operator::OR: + { + assert(expr.operands.size()); + llvm::Value* resultRaw = process(expr.operands[0]); + for(size_t i=1; i< expr.operands.size()-1; ++i){ + resultRaw = l.irBuilder.CreateOr(resultRaw, process(expr.operands.at(i))); } + return l.irBuilder.CreateOr(resultRaw, process(expr.operands.at(expr.operands.size()-1)), hintAlias); + } - case Operator::OR: - { - assert(expr.operands.size()); - llvm::Value* resultRaw = process(expr.operands[0]); - for(size_t i=1; i< expr.operands.size()-1; ++i){ - resultRaw = l.irBuilder.CreateOr(resultRaw, process(expr.operands.at(i))); - } - return l.irBuilder.CreateOr(resultRaw, process(expr.operands.at(expr.operands.size()-1)), hintAlias); - } + case Operator::ADD: + { + return l.irBuilder.CreateAdd(leftRaw, rightRaw, DEFAULT("addv")); + } - case Operator::ADD: - { - return l.irBuilder.CreateAdd(leftRaw, rightRaw, DEFAULT("addv")); - } + case Operator::SUB: + return l.irBuilder.CreateSub(leftRaw, rightRaw, DEFAULT("tmp_sub")); + break; - case Operator::SUB: - return l.irBuilder.CreateSub(leftRaw, rightRaw, DEFAULT("tmp_sub")); - break; + case Operator::MUL: + return l.irBuilder.CreateMul(leftRaw, rightRaw, DEFAULT("tmp_mul")); + break; - case Operator::MUL: - return l.irBuilder.CreateMul(leftRaw, rightRaw, DEFAULT("tmp_mul")); - break; + case Operator::DIV: + if (leftRaw->getType()->isIntegerTy()) return l.irBuilder.CreateSDiv(leftRaw, rightRaw, DEFAULT("tmp_div")); + if (leftRaw->getType()->isFloatingPointTy()) return l.irBuilder.CreateFDiv(leftRaw, rightRaw, DEFAULT("tmp_div")); + break; - case Operator::DIV: - if (leftRaw->getType()->isIntegerTy()) return l.irBuilder.CreateSDiv(leftRaw, rightRaw, DEFAULT("tmp_div")); - if (leftRaw->getType()->isFloatingPointTy()) return l.irBuilder.CreateFDiv(leftRaw, rightRaw, DEFAULT("tmp_div")); - break; + case Operator::MOD:{ + return l.irBuilder.CreateSRem(leftRaw, rightRaw, hintAlias); + } + + case Operator::EQU: { + if (leftRaw->getType()->isIntegerTy()) return l.irBuilder.CreateICmpEQ(leftRaw, rightRaw, DEFAULT("tmp_equ")); + if (leftRaw->getType()->isFloatingPointTy()) return l.irBuilder.CreateFCmpOEQ(leftRaw, rightRaw, DEFAULT("tmp_equ")); + + const ExpandedType& leftT = pass->man->root->getType(expr.operands[0]); + const ExpandedType& rightT = pass->man->root->getType(expr.operands[1]); - case Operator::MOD:{ - return l.irBuilder.CreateSRem(leftRaw, rightRaw, hintAlias); + if(leftT->__operator == TypeOperator::VARIANT && rightT->__operator == TypeOperator::VARIANT){ + llvm::Type* selectorT = llvm::cast(leftRaw->getType())->getElementType(0); + llvm::Value* leftUnwapped = typeinference::doAutomaticTypeConversion(leftRaw, selectorT, l.irBuilder); + llvm::Value* rightUnwapped = typeinference::doAutomaticTypeConversion(rightRaw, selectorT, l.irBuilder); + return l.irBuilder.CreateICmpEQ(leftUnwapped, rightUnwapped, DEFAULT("tmp_equ")); } + break; + } - case Operator::EQU: { - if (leftRaw->getType()->isIntegerTy()) return l.irBuilder.CreateICmpEQ(leftRaw, rightRaw, DEFAULT("tmp_equ")); - if (leftRaw->getType()->isFloatingPointTy()) return l.irBuilder.CreateFCmpOEQ(leftRaw, rightRaw, DEFAULT("tmp_equ")); + case Operator::NE: + return l.irBuilder.CreateICmpNE(leftRaw, rightRaw, DEFAULT("tmp_ne")); + break; - const ExpandedType& leftT = pass->man->root->getType(expr.operands[0]); - const ExpandedType& rightT = pass->man->root->getType(expr.operands[1]); + case Operator::LSS: + return l.irBuilder.CreateICmpSLT(leftRaw, rightRaw, DEFAULT("tmp_lss")); + break; - if(leftT->__operator == TypeOperator::VARIANT && rightT->__operator == TypeOperator::VARIANT){ - llvm::Type* selectorT = llvm::cast(leftRaw->getType())->getElementType(0); - llvm::Value* leftUnwapped = typeinference::doAutomaticTypeConversion(leftRaw, selectorT, l.irBuilder); - llvm::Value* rightUnwapped = typeinference::doAutomaticTypeConversion(rightRaw, selectorT, l.irBuilder); - return l.irBuilder.CreateICmpEQ(leftUnwapped, rightUnwapped, DEFAULT("tmp_equ")); - } - break; - } + case Operator::LSE: + return l.irBuilder.CreateICmpSLE(leftRaw, rightRaw, DEFAULT("tmp_lse")); + break; - case Operator::NE: - return l.irBuilder.CreateICmpNE(leftRaw, rightRaw, DEFAULT("tmp_ne")); - break; + case Operator::GTR: + return l.irBuilder.CreateICmpSGT(leftRaw, rightRaw, DEFAULT("tmp_gtr")); + break; - case Operator::LSS: - return l.irBuilder.CreateICmpSLT(leftRaw, rightRaw, DEFAULT("tmp_lss")); - break; + case Operator::GTE: + return l.irBuilder.CreateICmpSGE(leftRaw, rightRaw, DEFAULT("tmp_gte")); + break; - case Operator::LSE: - return l.irBuilder.CreateICmpSLE(leftRaw, rightRaw, DEFAULT("tmp_lse")); - break; + case Operator::NEG: + { + leftRaw = process(expr.operands[0]); + ExpandedType leftTy = pass->man->root->getType(expr.operands[0]); - case Operator::GTR: - return l.irBuilder.CreateICmpSGT(leftRaw, rightRaw, DEFAULT("tmp_gtr")); - break; + if (leftTy->__value == TypePrimitive::Bool){ + return l.irBuilder.CreateNot(leftRaw, hintAlias); + } else { + return l.irBuilder.CreateNeg(leftRaw, hintAlias); + } + break; + } - case Operator::GTE: - return l.irBuilder.CreateICmpSGE(leftRaw, rightRaw, DEFAULT("tmp_gte")); - break; + case Operator::CALL: + { + assert(expr.__state == Expression::COMPOUND); + shared_ptr callee(findFunction(expr)); + const std::string& nameCallee = expr.getValueString(); - case Operator::NEG: - { - leftRaw = process(expr.operands[0]); - ExpandedType leftTy = pass->man->root->getType(expr.operands[0]); - - if (leftTy->__value == TypePrimitive::Bool){ - return l.irBuilder.CreateNot(leftRaw, hintAlias); - } else { - return l.irBuilder.CreateNeg(leftRaw, hintAlias); + //prepare arguments + std::vector args; + args.reserve(expr.operands.size()); + + std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()), + [this](const Expression & operand) { + return process(operand); } - break; - } + ); - case Operator::CALL: - { - assert(expr.__state == Expression::COMPOUND); - shared_ptr callee(findFunction(expr)); - const std::string& nameCallee = expr.getValueString(); + return (*callee)(move(args), DEFAULT("res_" + nameCallee)); + } - //prepare arguments - std::vector args; - args.reserve(expr.operands.size()); + case Operator::IF: + { + return controlIR.compileIf(expr, DEFAULT("tmp_if")); + } - std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()), - [this](const Expression & operand) { - return process(operand); - } - ); + case Operator::SWITCH: + { + return controlIR.compileSwitch(expr, DEFAULT("tmp_switch")); + } - return (*callee)(move(args), DEFAULT("res_" + nameCallee)); - } + case Operator::LOGIC_AND: + { + assert(expr.operands.size() == 1); + return process(expr.operands[0]); + } - case Operator::IF: - { - return controlIR.compileIf(expr, DEFAULT("tmp_if")); - } + case Operator::LIST: //init record or array + { + ExpandedType exprT = l.ast->getType(expr, expectedT); + TypesHelper helper(pass->man->llvm); - case Operator::SWITCH: - { - return controlIR.compileSwitch(expr, DEFAULT("tmp_switch")); - } + enum {RECORD, ARRAY} kind; + if (helper.isArrayT(exprT)){ + kind = ARRAY; - case Operator::LOGIC_AND: - { - assert(expr.operands.size() == 1); - return process(expr.operands[0]); + } else if (helper.isRecordT(exprT)){ + kind = RECORD; + } else { + assert(false && "Inapproriate type"); } - case Operator::LIST: //init record or array - { - ExpandedType exprT = l.ast->getType(expr, expectedT); - TypesHelper helper(pass->man->llvm); + #ifdef XREATE_ENABLE_EXTERN + if (exprT->__operator == TypeOperator::ALIAS){ + if (l.layerExtern->isArrayType(exprT->__valueCustom)){ + flagIsArray = true; + break; + } - enum {RECORD, ARRAY} kind; - if (helper.isArrayT(exprT)){ - kind = ARRAY; + if (l.layerExtern->isRecordType(exprT->__valueCustom)){ + flagIsArray = false; + break; + } - } else if (helper.isRecordT(exprT)){ - kind = RECORD; - } else { - assert(false && "Inapproriate type"); + assert(false && "Inapproriate external type"); + } + #endif + + switch(kind){ + case RECORD:{ + const std::vector fieldsFormal = helper.getRecordFields(exprT); + containers::RecordIR irRecords(ctx); + llvm::StructType *recordTRaw = llvm::cast(l.toLLVMType(exprT)); + llvm::Value *resultRaw = irRecords.init(recordTRaw); + return irRecords.update(resultRaw, exprT, expr); } - #ifdef XREATE_ENABLE_EXTERN - if (exprT->__operator == TypeOperator::ALIAS){ - if (l.layerExtern->isArrayType(exprT->__valueCustom)){ - flagIsArray = true; - break; - } + case ARRAY: { + std::unique_ptr containerIR( + containers::IContainersIR::create(expr, expectedT, ctx)); + llvm::Value* aggrRaw = containerIR->init(hintAlias); + return containerIR->update(aggrRaw, expr, hintAlias); + } + } + break; + }; - if (l.layerExtern->isRecordType(exprT->__valueCustom)){ - flagIsArray = false; - break; - } + case Operator::LIST_RANGE: + { + assert(false); //no compilation phase for a range list + // return InstructionList(this).compileConstantArray(expr, l, hintRetVar); + }; - assert(false && "Inapproriate external type"); - } - #endif - - switch(kind){ - case RECORD:{ - const std::vector fieldsFormal = helper.getRecordFields(exprT); - containers::RecordIR irRecords(ctx); - llvm::StructType *recordTRaw = llvm::cast(l.toLLVMType(exprT)); - llvm::Value *resultRaw = irRecords.init(recordTRaw); - return irRecords.update(resultRaw, exprT, expr); - } + case Operator::MAP: + { + assert(expr.blocks.size()); - case ARRAY: { - std::unique_ptr containerIR( - containers::IContainersIR::create(expr, expectedT, ctx)); - llvm::Value* aggrRaw = containerIR->init(hintAlias); - return containerIR->update(aggrRaw, expr, hintAlias); - } + containers::ImplementationType implType = containers::IContainersIR::getImplementation(expr, pass->man->root); + + switch(implType){ + case containers::ImplementationType::SOLID: { + ExpandedType exprT = pass->man->root->getType(expr, expectedT); + ArrayHint hint = find(expr, ArrayHint{}); + + containers::ArrayIR compiler(exprT, hint, ctx); + return compiler.operatorMap(expr, DEFAULT("map")); } - break; - }; - case Operator::LIST_RANGE: - { - assert(false); //no compilation phase for a range list - // return InstructionList(this).compileConstantArray(expr, l, hintRetVar); - }; + case containers::ImplementationType::ON_THE_FLY:{ + FlyHint hint = find(expr, {}); + containers::FlyIR compiler(hint, ctx); - case Operator::MAP: - { - assert(expr.blocks.size()); - return controlIR.compileMapSolidOutput(expr, DEFAULT("map")); - }; + return compiler.operatorMap(expr, DEFAULT("map")); + } - case Operator::FOLD: + default: + break; + } + assert(false && "Operator MAP does not support this container impl"); + return nullptr; + }; + + case Operator::FOLD: + { + return controlIR.compileFold(expr, DEFAULT("fold")); + }; + + case Operator::FOLD_INF: + { + return controlIR.compileFoldInf(expr, DEFAULT("fold")); + }; + + case Operator::INDEX: + { + assert(expr.operands.size() > 1); + + const Expression& aggrE = expr.operands[0]; + const ExpandedType& aggrT = pass->man->root->getType(aggrE); + llvm::Value* aggrRaw = process(aggrE); + switch (aggrT->__operator) { + case TypeOperator::RECORD: { - return controlIR.compileFold(expr, DEFAULT("fold")); - }; + list fieldsList; + for(auto opIt = ++expr.operands.begin(); opIt!=expr.operands.end(); ++opIt){ + fieldsList.push_back(getIndexStr(*opIt)); + } - case Operator::FOLD_INF: - { - return controlIR.compileFoldInf(expr, DEFAULT("fold")); + return controlIR.compileStructIndex(aggrRaw, aggrT, fieldsList); }; - case Operator::INDEX: + case TypeOperator::ARRAY: { - assert(expr.operands.size() > 1); - - const Expression& aggrE = expr.operands[0]; - const ExpandedType& aggrT = pass->man->root->getType(aggrE); - llvm::Value* aggrRaw = process(aggrE); - switch (aggrT->__operator) { - case TypeOperator::RECORD: - { - list fieldsList; - for(auto opIt = ++expr.operands.begin(); opIt!=expr.operands.end(); ++opIt){ - fieldsList.push_back(getIndexStr(*opIt)); - } - - return controlIR.compileStructIndex(aggrRaw, aggrT, fieldsList); - }; - - case TypeOperator::ARRAY: - { - std::vector indexes; - std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()), - [this] (const Expression & op) { - return process(op); - } - ); - - std::unique_ptr containersIR( - containers::IContainersIR::create(aggrE, expectedT, ctx) - ); + std::vector indexes; + std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()), + [this] (const Expression & op) { + return process(op); + } + ); - containers::ArrayIR* arraysIR = static_cast(containersIR.get()); - return arraysIR->get(aggrRaw, indexes, hintAlias); - }; + std::unique_ptr containersIR( + containers::IContainersIR::create(aggrE, expectedT, ctx) + ); - default: - assert(false); - } + containers::ArrayIR* arraysIR = static_cast(containersIR.get()); + return arraysIR->get(aggrRaw, indexes, hintAlias); }; - case Operator::CALL_INTRINSIC: - { + default: + assert(false); + } + }; + + case Operator::CALL_INTRINSIC: + { // const std::string op = expr.getValueString(); // // if (op == "copy") { // llvm::Value* result = process(expr.getOperands().at(0)); // // auto decoratorVersions = Decorators::getInterface(this); // llvm::Value* storage = decoratorVersions->processIntrinsicInit(result->getType()); // decoratorVersions->processIntrinsicCopy(result, storage); // // return l.irBuilder.CreateLoad(storage, hintAlias); // } - assert(false && "undefined intrinsic"); - } + assert(false && "undefined intrinsic"); + } - case Operator::QUERY: - case Operator::QUERY_LATE: - { - assert(false && "Should be processed by interpretation"); - } + case Operator::QUERY: + case Operator::QUERY_LATE: + { + assert(false && "Should be processed by interpretation"); + } - case Operator::VARIANT: - { - const ExpandedType& typResult = pass->man->root->getType(expr); - llvm::Type* typResultRaw = l.toLLVMType(typResult); - llvm::Type* typIdRaw = llvm::cast(typResultRaw)->getElementType(0); - - uint64_t id = expr.getValueDouble(); - llvm::Value* resultRaw = llvm::UndefValue::get(typResultRaw); - resultRaw = l.irBuilder.CreateInsertValue(resultRaw, llvm::ConstantInt::get(typIdRaw, id), llvm::ArrayRef({0})); - - const ExpandedType& typVariant = ExpandedType(typResult->__operands.at(id)); - llvm::Type* typVariantRaw = l.toLLVMType(typVariant); - llvm::Value* variantRaw = llvm::UndefValue::get(typVariantRaw); - assert(expr.operands.size() == typVariant->__operands.size() && "Wrong variant arguments count"); - if (!typVariant->__operands.size()) return resultRaw; - - for (unsigned int fieldId = 0; fieldId < expr.operands.size(); ++fieldId) { - const ExpandedType& typField = ExpandedType(typVariant->__operands.at(fieldId)); - Attachments::put(expr.operands.at(fieldId), typField); - llvm::Value* fieldRaw = process(expr.operands.at(fieldId)); - assert(fieldRaw); - - variantRaw = l.irBuilder.CreateInsertValue(variantRaw, fieldRaw, llvm::ArrayRef({fieldId})); - } + case Operator::VARIANT: + { + const ExpandedType& typResult = pass->man->root->getType(expr); + llvm::Type* typResultRaw = l.toLLVMType(typResult); + llvm::Type* typIdRaw = llvm::cast(typResultRaw)->getElementType(0); - llvm::Type* typStorageRaw = llvm::cast(typResultRaw)->getElementType(1); - llvm::Value* addrAsStorage = l.irBuilder.CreateAlloca(typStorageRaw); - llvm::Value* addrAsVariant = l.irBuilder.CreateBitOrPointerCast(addrAsStorage, typVariantRaw->getPointerTo()); + uint64_t id = expr.getValueDouble(); + llvm::Value* resultRaw = llvm::UndefValue::get(typResultRaw); + resultRaw = l.irBuilder.CreateInsertValue(resultRaw, llvm::ConstantInt::get(typIdRaw, id), llvm::ArrayRef({0})); - l.irBuilder.CreateStore(variantRaw, addrAsVariant); - llvm::Value* storageRaw = l.irBuilder.CreateLoad(typStorageRaw, addrAsStorage); - resultRaw = l.irBuilder.CreateInsertValue(resultRaw, storageRaw, llvm::ArrayRef({1})); + const ExpandedType& typVariant = ExpandedType(typResult->__operands.at(id)); + llvm::Type* typVariantRaw = l.toLLVMType(typVariant); + llvm::Value* variantRaw = llvm::UndefValue::get(typVariantRaw); + assert(expr.operands.size() == typVariant->__operands.size() && "Wrong variant arguments count"); + if (!typVariant->__operands.size()) return resultRaw; - return resultRaw; - } + for (unsigned int fieldId = 0; fieldId < expr.operands.size(); ++fieldId) { + const ExpandedType& typField = ExpandedType(typVariant->__operands.at(fieldId)); + Attachments::put(expr.operands.at(fieldId), typField); + llvm::Value* fieldRaw = process(expr.operands.at(fieldId)); + assert(fieldRaw); - case Operator::SWITCH_VARIANT: - { - return controlIR.compileSwitchVariant(expr, DEFAULT("tmpswitch")); + variantRaw = l.irBuilder.CreateInsertValue(variantRaw, fieldRaw, llvm::ArrayRef({fieldId})); } - case Operator::SWITCH_LATE: - { - assert(false && "Instruction's compilation should've been redirected to interpretation"); - return nullptr; - } + llvm::Type* typStorageRaw = llvm::cast(typResultRaw)->getElementType(1); + llvm::Value* addrAsStorage = l.irBuilder.CreateAlloca(typStorageRaw); + llvm::Value* addrAsVariant = l.irBuilder.CreateBitOrPointerCast(addrAsStorage, typVariantRaw->getPointerTo()); - case Operator::SEQUENCE: - { - return controlIR.compileSequence(expr); - } + l.irBuilder.CreateStore(variantRaw, addrAsVariant); + llvm::Value* storageRaw = l.irBuilder.CreateLoad(typStorageRaw, addrAsStorage); + resultRaw = l.irBuilder.CreateInsertValue(resultRaw, storageRaw, llvm::ArrayRef({1})); - case Operator::UNDEF: - { - llvm::Type* typExprUndef = l.toLLVMType(pass->man->root->getType(expr, expectedT)); - return llvm::UndefValue::get(typExprUndef); - } + return resultRaw; + } - case Operator::UPDATE: - { - TypesHelper helper(pass->man->llvm); - containers::RecordIR irRecords(ctx); + case Operator::SWITCH_VARIANT: + { + return controlIR.compileSwitchVariant(expr, DEFAULT("tmpswitch")); + } - const Expression& aggrE = expr.operands.at(0); - const Expression& updE = expr.operands.at(1); - const ExpandedType& aggrT = pass->man->root->getType(aggrE); - llvm::Value* aggrRaw = process(aggrE); + case Operator::SWITCH_LATE: + { + assert(false && "Instruction's compilation should've been redirected to interpretation"); + return nullptr; + } - if (helper.isRecordT(aggrT)){ - return irRecords.update(aggrRaw, aggrT, updE); - } + case Operator::SEQUENCE: + { + return controlIR.compileSequence(expr); + } - if (helper.isArrayT(aggrT)){ - if (updE.op == Operator::LIST_INDEX){ + case Operator::UNDEF: + { + llvm::Type* typExprUndef = l.toLLVMType(pass->man->root->getType(expr, expectedT)); + return llvm::UndefValue::get(typExprUndef); + } - std::unique_ptr containersIR( - containers::IContainersIR::create(aggrE, TypeAnnotation(), ctx - )); + case Operator::UPDATE: + { + TypesHelper helper(pass->man->llvm); + containers::RecordIR irRecords(ctx); - return containersIR->update(aggrRaw, updE, hintAlias); - } - } + const Expression& aggrE = expr.operands.at(0); + const Expression& updE = expr.operands.at(1); + const ExpandedType& aggrT = pass->man->root->getType(aggrE); + llvm::Value* aggrRaw = process(aggrE); - assert(false); - return nullptr; + if (helper.isRecordT(aggrT)){ + return irRecords.update(aggrRaw, aggrT, updE); } - case Operator::INVALID: - assert(expr.__state != Expression::COMPOUND); + if (helper.isArrayT(aggrT)){ + if (updE.op == Operator::LIST_INDEX){ - switch (expr.__state) { - case Expression::IDENT: - { - Symbol s = Attachments::get(expr); - return processSymbol(s, expr.getValueString()); - } + std::unique_ptr containersIR( + containers::IContainersIR::create(aggrE, TypeAnnotation(), ctx + )); - case Expression::NUMBER: - { - llvm::Type* typConst = l.toLLVMType(pass->man->root->getType(expr, expectedT)); - int literal = expr.getValueDouble(); + return containersIR->update(aggrRaw, updE, hintAlias); + } + } - if (typConst->isFloatingPointTy()) return llvm::ConstantFP::get(typConst, literal); - if (typConst->isIntegerTy()) return llvm::ConstantInt::get(typConst, literal); - - assert(false && "Can't compile literal"); - } + assert(false); + return nullptr; + } - case Expression::STRING: - { - return controlIR.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str")); - }; + case Operator::INVALID: + assert(expr.__state != Expression::COMPOUND); - default: - { - break; - } - }; + switch (expr.__state) { + case Expression::IDENT: + { + Symbol s = Attachments::get(expr); + return processSymbol(s, expr.getValueString()); + } - break; + case Expression::NUMBER: + { + llvm::Type* typConst = l.toLLVMType(pass->man->root->getType(expr, expectedT)); + int literal = expr.getValueDouble(); + + if (typConst->isFloatingPointTy()) return llvm::ConstantFP::get(typConst, literal); + if (typConst->isIntegerTy()) return llvm::ConstantInt::get(typConst, literal); + + assert(false && "Can't compile literal"); + } - default: break; + case Expression::STRING: + { + return controlIR.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str")); + }; + default: + { + break; } + }; + + break; + + default: break; + + } - assert(false && "Can't compile expression"); - return 0; + assert(false && "Can't compile expression"); + return 0; } llvm::Value* BasicBruteScope::compile(const std::string& hintBlockDecl) { - LLVMLayer* llvm = pass->man->llvm; + LLVMLayer* llvm = pass->man->llvm; - if (!hintBlockDecl.empty()) { - llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm->llvmContext, hintBlockDecl, function->raw); - pass->man->llvm->irBuilder.SetInsertPoint(block); - } + if (!hintBlockDecl.empty()) { + llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm->llvmContext, hintBlockDecl, function->raw); + pass->man->llvm->irBuilder.SetInsertPoint(block); + } - currentBlockRaw = pass->man->llvm->irBuilder.GetInsertBlock(); - Symbol symbScope = Symbol{ScopedSymbol::RetSymbol, scope}; - return processSymbol(symbScope); + lastBlockRaw = pass->man->llvm->irBuilder.GetInsertBlock(); + Symbol symbScope = Symbol{ScopedSymbol::RetSymbol, scope}; + return processSymbol(symbScope); } IBruteScope::~IBruteScope() { } IBruteFunction::~IBruteFunction() { } llvm::Function* IBruteFunction::compile() { if (raw != nullptr) return raw; LLVMLayer* llvm = pass->man->llvm; llvm::IRBuilder<>& builder = llvm->irBuilder; string&& functionName = prepareName(); std::vector&& types = prepareSignature(); llvm::Type* expectedResultType = prepareResult(); llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false); raw = llvm::cast(llvm->module->getOrInsertFunction(functionName, ft)); prepareBindings(); + applyAttributes(); - const std::string&blockName = "entry"; + const std::string& blockName = "entry"; llvm::BasicBlock* blockCurrent = builder.GetInsertBlock(); - llvm::Value* result = getScopeUnit(function->__entry)->compile(blockName); + llvm::Value* result = getScopeUnit(__entry)->compile(blockName); assert(result); //SECTIONTAG types/convert function ret value builder.CreateRet(typeinference::doAutomaticTypeConversion(result, expectedResultType, llvm->irBuilder)); if (blockCurrent) { builder.SetInsertPoint(blockCurrent); } llvm->moveToGarbage(ft); return raw; } IBruteScope* IBruteFunction::getScopeUnit(const CodeScope * const scope) { if (__scopes.count(scope)) { auto result = __scopes.at(scope).lock(); if (result) { return result.get(); } } std::shared_ptr unit(pass->buildCodeScopeUnit(scope, this)); if (scope->__parent != nullptr) { auto parentUnit = Decorators::getInterface(getScopeUnit(scope->__parent)); parentUnit->registerChildScope(unit); } else { __orphanedScopes.push_back(unit); } if (!__scopes.emplace(scope, unit).second) { __scopes[scope] = unit; } return unit.get(); } IBruteScope* IBruteFunction::getScopeUnit(ManagedScpPtr scope) { return getScopeUnit(&*scope); } IBruteScope* IBruteFunction::getEntry() { - return getScopeUnit(function->getEntryScope()); + return getScopeUnit(__entry); +} + +std::vector +IBruteFunction::getScopeSignature(CodeScope* scope){ + LLVMLayer* llvm = IBruteFunction::pass->man->llvm; + AST* ast = IBruteFunction::pass->man->root; + std::vector result; + + std::transform(scope->__bindings.begin(), scope->__bindings.end(), std::inserter(result, result.end()), + [llvm, ast, scope](const std::string & arg)->llvm::Type* { + assert(scope->__identifiers.count(arg)); + + ScopedSymbol argid{scope->__identifiers.at(arg), versions::VERSION_NONE}; + return llvm->toLLVMType(ast->expandType(scope->__declarations.at(argid).type)); + }); + + return result; } template<> compilation::IBruteFunction* CompilePassCustomDecorators ::buildFunctionUnit(const ManagedFnPtr& function) { return new BruteFunctionDefault(function, this); + } template<> compilation::IBruteScope* CompilePassCustomDecorators ::buildCodeScopeUnit(const CodeScope * const scope, IBruteFunction* function) { return new DefaultCodeScopeUnit(scope, function, this); } std::string BasicBruteScope::getIndexStr(const Expression& index){ switch(index.__state){ //named struct field case Expression::STRING: return index.getValueString(); break; //anonymous struct field case Expression::NUMBER: return to_string((int) index.getValueDouble()); break; default: assert(false && "Wrong index for a struct"); } return ""; } } // end of compilation compilation::IBruteFunction* CompilePass::getFunctionUnit(const ManagedFnPtr& function) { unsigned int id = function.id(); if (!functions.count(id)) { compilation::IBruteFunction* unit = buildFunctionUnit(function); functions.emplace(id, unit); return unit; } return functions.at(id); } void CompilePass::prepare(){ //Initialization: #ifndef XREATE_CONFIG_MIN #endif managerTransformations = new xreate::compilation::TransformationsManager(); targetInterpretation = new interpretation::TargetInterpretation(man, this); } void CompilePass::run() { prepare(); //Determine entry function: StaticModel model = man->transcend->query(analysis::FN_ENTRY_PREDICATE); assert(model.size() && "Error: No entry function found"); assert(model.size() == 1 && "Error: Ambiguous entry function"); string nameMain = std::get<0>(TranscendLayer::parse(model.begin()->second)); compilation::IBruteFunction* unitMain = getFunctionUnit(man->root->findFunction(nameMain)); //Compilation itself: entry = unitMain->compile(); } llvm::Function* CompilePass::getEntryFunction() { assert(entry); return entry; } void CompilePass::prepareQueries(TranscendLayer* transcend) { #ifndef XREATE_CONFIG_MIN transcend->registerQuery(new latex::LatexQuery(), QueryId::LatexQuery); #endif transcend->registerQuery(new containers::Query(), QueryId::ContainersQuery); transcend->registerQuery(new demand::DemandQuery(), QueryId::DemandQuery); transcend->registerQuery(new polymorph::PolymorphQuery(), QueryId::PolymorphQuery); } } //end of namespace xreate /** * \class xreate::CompilePass * \brief The owner of the compilation process. Performs fundamental compilation activities along with the xreate::compilation's routines * * xreate::CompilePass traverses over xreate::AST tree and produces executable code. * The pass performs compilation using the following data sources: * - %Attachments: the data gathered by the previous passes. See \ref xreate::Attachments. * - Transcend solutions accessible via queries. See \ref xreate::IQuery, \ref xreate::TranscendLayer. * * The pass generates a bytecode by employing \ref xreate::LLVMLayer(wrapper over LLVM toolchain). * Many compilation activities are delegated to more specific routines. Most notable delegated compilation aspects are: * - Containers support. See \ref xreate::containers. * - Latex compilation. See \ref xreate::latex. * - Interpretation support. See \ref xreate::interpretation. * - Loop saturation support. See \ref xreate::compilation::TransformationsScopeDecorator. * - External code interaction support. See \ref xreate::ExternLayer (wrapper over Clang library). * * \section adaptability_sect Adaptability * xreate::CompilePass's behaviour can be adapted in several ways: * - %Function Decorators to alter function-level compilation. See \ref xreate::compilation::IBruteFunction * - Code Block Decorators to alter code block level compilation. See \ref xreate::compilation::ICodeScopeUnit. * Default functionality defined by \ref xreate::compilation::DefaultCodeScopeUnit * - Targets to allow more versitile extensions. * Currently only xreate::interpretation::TargetInterpretation use Targets infrastructure. See \ref xreate::compilation::Target. * - Altering %function invocation. See \ref xreate::compilation::IFnInvocation. * * Clients are free to construct a compiler instantiation with the desired decorators by using \ref xreate::compilation::CompilePassCustomDecorators. * As a handy alias, `CompilePassCustomDecorators` constructs the default compiler. * */ diff --git a/cpp/src/pass/compilepass.h b/cpp/src/pass/compilepass.h index bc503c1..3e3d247 100644 --- a/cpp/src/pass/compilepass.h +++ b/cpp/src/pass/compilepass.h @@ -1,225 +1,233 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * * compilepass.h */ #ifndef COMPILEPASS_H #define COMPILEPASS_H #include "abstractpass.h" - #include "llvm/IR/Function.h" namespace xreate { class TranscendLayer; class CompilePass; class LLVMLayer; namespace interpretation{ class TargetInterpretation; } } namespace xreate { namespace compilation { class IBruteScope; class IBruteFunction; class TransformationsManager; /** \brief Holds current position in %AST while traversing*/ struct Context{ IBruteScope* scope; IBruteFunction* function; CompilePass* pass; }; /** \brief Interface for custom function invocation operation compilation * \details Default implementation is xreate::compilation::BruteFnInvocation */ class IFnInvocation { public: /** \brief Returns result of custom function invocation for the given arguments*/ virtual llvm::Value* operator() (std::vector&& args, const std::string& hintDecl="") = 0; }; /** \brief Default IFnInvocation implementation */ class BruteFnInvocation: public IFnInvocation{ public: BruteFnInvocation(llvm::Function* callee, LLVMLayer* l) : __callee(callee), __calleeTy(callee->getFunctionType()), llvm(l) {} BruteFnInvocation(llvm::Value* callee, llvm::FunctionType* ty, LLVMLayer* l) : __callee(callee), __calleeTy(ty), llvm(l) {} /** \brief Makes type conversions and returns LLVM call statement with given arguments*/ llvm::Value* operator() (std::vector&& args, const std::string& hintDecl=""); protected: llvm::Value* __callee; llvm::FunctionType* __calleeTy; LLVMLayer* llvm; }; /** \brief %Function invocation operator decorator to handle latex enabled functions with hidden extra arguments */ class HiddenArgsFnInvocation : public compilation::IFnInvocation{ public: HiddenArgsFnInvocation(std::vector args, compilation::IFnInvocation *parent) : __args(args), __parent(parent){} llvm::Value *operator()(std::vector &&args, const std::string &hintDecl = ""); private: std::vector __args; compilation::IFnInvocation *__parent; }; /** \brief Interface to allow modification of CodeScope compilation * \details Default implementation defined in xreate::compilation::DefaultCodeScopeUnit */ class IBruteScope{ public: CompilePass* const pass; IBruteFunction* const function; const CodeScope* const scope; - llvm::BasicBlock* currentBlockRaw; + llvm::BasicBlock* lastBlockRaw; IBruteScope(const CodeScope* const codeScope, IBruteFunction* f, CompilePass* compilePass); virtual ~IBruteScope(); virtual llvm::Value* compile(const std::string& hintBlockDecl="")=0; virtual llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar="")=0; virtual llvm::Value* process(const Expression& expr, const std::string& hintVarDecl="", const TypeAnnotation& expectedT = TypeAnnotation())=0; virtual Symbol bindArg(llvm::Value* value, std::string&& alias)=0; virtual void bindArg(llvm::Value* value, const ScopedSymbol& s)=0; virtual void reset() = 0; protected: /** \brief For subclasses to implement this method to define a function name resolution*/ virtual IFnInvocation* findFunction(const Expression& opCall)=0; }; /** \brief Minimal useful IBruteScope implementation suited for inheritance */ class BasicBruteScope: public IBruteScope{ public: BasicBruteScope(const CodeScope* const codeScope, IBruteFunction* f, CompilePass* compilePass); llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar="") override; llvm::Value* process(const Expression& expr, const std::string& hintAlias="", const TypeAnnotation& expectedT = TypeAnnotation()) override; llvm::Value* compile(const std::string& hintBlockDecl="") override; protected: IFnInvocation* findFunction(const Expression& opCall) override; private: std::string getIndexStr(const Expression& index); }; /** \brief Interface to specify compilation of %Function */ class IBruteFunction{ public: - IBruteFunction(ManagedFnPtr f, CompilePass* p): function(f), pass(p) {} + IBruteFunction(CodeScope* entry, CompilePass* p): pass(p), __entry(entry){} virtual ~IBruteFunction(); llvm::Function* compile(); IBruteScope* getEntry(); + virtual ManagedFnPtr getASTFn() const {return ManagedFnPtr();}; IBruteScope* getScopeUnit(const CodeScope * const scope); IBruteScope* getScopeUnit(ManagedScpPtr scope); - virtual llvm::Type* prepareResult() = 0; - - ManagedFnPtr function; llvm::Function* raw = nullptr; protected: CompilePass* pass=nullptr; + CodeScope* __entry; virtual std::string prepareName() = 0; virtual std::vector prepareSignature() = 0; virtual llvm::Function::arg_iterator prepareBindings() = 0; - + virtual llvm::Type* prepareResult() = 0; + virtual void applyAttributes() = 0; + private: std::map> __scopes; std::list> __orphanedScopes; + +protected: + std::vector getScopeSignature(CodeScope* scope); }; /** \brief Minimal useful IBruteFunction implementation suited for inheritance */ class BasicBruteFunction: public IBruteFunction{ public: BasicBruteFunction(ManagedFnPtr f, CompilePass* p) - : IBruteFunction(f, p) {} + : IBruteFunction(f->getEntryScope(), p), __function(f) {} protected: std::string prepareName() override; virtual std::vector prepareSignature() override; virtual llvm::Type* prepareResult() override; virtual llvm::Function::arg_iterator prepareBindings() override; + virtual void applyAttributes() override; + virtual ManagedFnPtr getASTFn() const {return __function;}; + +protected: + ManagedFnPtr __function; }; } // end of namespace compilation class CompilePass : public AbstractPass { friend class compilation::BasicBruteScope; friend class compilation::IBruteFunction; public: compilation::TransformationsManager* managerTransformations; interpretation::TargetInterpretation* targetInterpretation; CompilePass(PassManager* manager): AbstractPass(manager) {} /** \brief Executes compilation process */ void run() override; /**\brief Returns compiled specified %Function * \details Executes function compilation or read cache if it's already done */ compilation::IBruteFunction* getFunctionUnit(const ManagedFnPtr& function); /**\brief Returns compiled main(entry) %Function in program */ llvm::Function* getEntryFunction(); /** \brief Initializes queries required by compiler. See xreate::IQuery, xreate::TranscendLayer */ static void prepareQueries(TranscendLayer* transcend); void prepare(); protected: virtual compilation::IBruteFunction* buildFunctionUnit(const ManagedFnPtr& function)=0; virtual compilation::IBruteScope* buildCodeScopeUnit(const CodeScope* const scope, compilation::IBruteFunction* function)=0; private: //TODO free `functions` in destructor std::map functions; llvm::Function* entry = 0; }; namespace compilation{ /** \brief Constructs compiler with desired %Function and %Code Scope decorators. See adaptability in xreate::CompilePass*/ template class CompilePassCustomDecorators: public ::xreate::CompilePass{ public: CompilePassCustomDecorators(PassManager* manager): ::xreate::CompilePass(manager) {} virtual compilation::IBruteFunction* buildFunctionUnit(const ManagedFnPtr& function) override{ return new FUNCTION_DECORATOR(function, this); } virtual compilation::IBruteScope* buildCodeScopeUnit(const CodeScope* const scope, IBruteFunction* function) override{ return new SCOPE_DECORATOR(scope, function, this); } }; template<> compilation::IBruteFunction* CompilePassCustomDecorators::buildFunctionUnit(const ManagedFnPtr& function); template<> compilation::IBruteScope* CompilePassCustomDecorators::buildCodeScopeUnit(const CodeScope* const scope, IBruteFunction* function); }} //end of namespace xreate::compilation #endif // COMPILEPASS_H diff --git a/cpp/src/utils.h b/cpp/src/utils.h index cd4ae1a..beb5d8d 100644 --- a/cpp/src/utils.h +++ b/cpp/src/utils.h @@ -1,160 +1,156 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * utils.cpp * * Author: pgess */ #ifndef UTILS_H #define UTILS_H #include #include namespace xreate { template struct AddTag { explicit AddTag(const Source &src) : __src(src) { } explicit AddTag(Source &&src) : __src(std::move(src)) { } - operator const Source&() const{ - return __src; - } - const Source& get() const{ return __src; } const Source* operator->() const { return &__src; } private: Source __src; }; struct Expand_t{}; template using Expanded = AddTag; /** \brief Decorators support */ template struct DecoratorsDict{ //typedef ConcreteDecoratorForTag result; }; template struct Decorators{ typedef typename DecoratorsDict::result Instance; template static Instance* getInterface(Base* obj){ Instance* result = dynamic_cast< Instance* > (obj); assert(result); return result; } }; 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; } bool operator< (const ManagedPtr& other) const{ if(__storage != other.__storage) return __storage < other.__storage; return __id < other.__id; } private: unsigned int __id = 0; const std::vector * __storage = 0; }; } std::wstring utf8_to_wstring(const std::string& str); std::string wstring_to_utf8(const std::wstring& str); #define RST "\x1B[0m" #define KRED "\x1B[31m" #define KGRN "\x1B[32m" #define KYEL "\x1B[33m" #define KBLU "\x1B[34m" #define KMAG "\x1B[35m" #define KCYN "\x1B[36m" #define KWHT "\x1B[37m" #define FRED(x) KRED << x << RST #define FGRN(x) KGRN < */ #include "xreatemanager.h" #include "supplemental/basics.h" #include "llvmlayer.h" +#include "pass/compilepass.h" +#include "compilation/lambdas.h" #include "gtest/gtest.h" using namespace xreate; +using namespace xreate::compilation; using namespace std; //DEBT implement no pkgconfig ways to link libs //TOTEST FunctionUnit::compileInline TEST(Compilation, functionEntry1){ std::unique_ptr program(XreateManager::prepare( "func1 = function(a:: int):: int {a+8} \ func2 = function::int; entry {12 + func1(4)} \ ")); void* entryPtr = program->run(); int (*entry)() = (int (*)())(intptr_t)entryPtr; int answer = entry(); ASSERT_EQ(24, answer); } TEST(Compilation, full_IFStatementWithVariantType){ XreateManager* man = XreateManager::prepare( "Color = type variant {RED, BLUE, GREEN}.\n" "\n" " main = function(x::int):: bool; entry {\n" " color = if (x == 0 )::Color {RED()} else {BLUE()}.\n" " if (color == BLUE())::bool {true} else {false}\n" " }" ); bool (*main)(int) = (bool (*)(int)) man->run(); ASSERT_FALSE(main(0)); ASSERT_TRUE(main(1)); } TEST(Compilation, full_Variant1){ XreateManager* man = XreateManager::prepare(R"Code( global = type predicate { entry } Command= type variant{ Add(x::int, y::int), Dec(x::int) }. main = function::Command; entry() { Dec(2) ::Command } )Code"); void (*main)() = (void (*)()) man->run(); } TEST(Compilation, full_SwitchVariant1){ XreateManager* man = XreateManager::prepare(R"Code( Command= type variant{ Add(x::int, y::int), Dec(x::int) }. main = function::int; entry { command = Add(3, 5):: Command. switch variant(command)::int case(Add){command["x"] + command["y"]} case(Dec){command["x"]} } )Code"); int (*mainFn)() = (int (*)()) man->run(); int result = mainFn(); ASSERT_EQ(8, result); } TEST(Compilation, full_SwitchVariantNoArguments2){ XreateManager* man = XreateManager::prepare(R"Code( Command= type variant{Add, Dec}. main = function::int; entry { command = Dec():: Command. switch variant(command)::int case(Add){0} case(Dec){1} } )Code"); int (*mainFn)() = (int (*)()) man->run(); int result = mainFn(); ASSERT_EQ(1, result); } TEST(Compilation, full_SwitchVariantMixedArguments3){ XreateManager* man = XreateManager::prepare(R"Code( Command= type variant{ Add(x::int, y::int), Dec }. main = function(arg::int):: int; entry { command = if (arg > 0)::Command {Dec()} else {Add(1, 2)}. switch variant(command)::int case(Add){0} case(Dec){1} } )Code"); int (*mainFn)(int) = (int (*)(int)) man->run(); int result = mainFn(5); ASSERT_EQ(1, result); } TEST(Compilation, full_StructUpdate){ XreateManager* man = XreateManager::prepare( R"Code( 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()); } TEST(Compilation, BugIncorrectScopes1){ std::string code = R"Code( init = function:: int {10} main = function(cmd:: int):: int; entry { x = init():: int. if(cmd > 0):: int { x + 1 } else { x } } )Code"; std::unique_ptr man(XreateManager::prepare(move(code))); int (*mainFn)(int) = (int (*)(int)) man->run(); EXPECT_EQ(11, mainFn(1)); } TEST(Compilation, Sequence1){ std::string code = R"Code( interface(extern-c){ libbsd = library:: pkgconfig("libbsd"). include { libbsd = {"bsd/stdlib.h", "string.h"} }. } start = function:: i32; entry { seq { nameNew = "TestingSequence":: string. setprogname(nameNew) } {strlen(getprogname())}::i32 } )Code"; std::unique_ptr man(XreateManager::prepare(move(code))); int (*startFn)() = (int (*)()) man->run(); int nameNewLen = startFn(); ASSERT_EQ(15, nameNewLen); } TEST(Compilation, BoolInstructions1){ std::string code = R"Code( test = function (a:: bool, b:: bool):: bool; entry { -a } )Code"; std::unique_ptr man(XreateManager::prepare(move(code))); Fn2Args startFn = (Fn2Args) man->run(); } TEST(Compilation, StructIndex1){ std::string code = R"Code( Anns = type predicate { entry() } test = function:: int; entry() { x = {a = ({b = 3}::{b:: int})}:: {a:: {b:: int}}. 2 + x["a", "b"] + x["a"]["b"] } )Code"; std::unique_ptr man(XreateManager::prepare(move(code))); FnNoArgs startFn = (FnNoArgs) man->run(); int result = startFn(); ASSERT_EQ(2, result); } TEST(Compilation, PreferredInt1){ std::unique_ptr man(XreateManager::prepare("")); TypesHelper utils(man->llvm); int bitwidth = utils.getPreferredIntTy()->getBitWidth(); ASSERT_EQ(64, bitwidth); } TEST(Compilation, PredPredicates1){ string code = R"( my-fn = function:: int; entry() {0} )"; auto man = XreateManager::prepare(move(code)); FnNoArgs startFn = (FnNoArgs) man->run(); int result = startFn(); ASSERT_EQ(0, result); +} + +typedef intmax_t (*FnI_I)(intmax_t); +TEST(Compilation, Lambda1){ + string code = R"( +myfn = function:: int { + a = [1..5]:: [int]. + loop map(a->x:: int):: [int] { x + 10:: int} +} +)"; + auto man = details::tier1::XreateManager::prepare(move(code)); + LLVMLayer* llvm = man->llvm; + man->analyse(); + + std::unique_ptr compiler(new compilation::CompilePassCustomDecorators<>(man)); + compiler->prepare(); + LambdaIR compilerLambda(compiler.get()); + CodeScope* scopeLoop = man->root->findFunction("myfn")->getEntryScope()->getBody().blocks.front(); + auto fnRaw = compilerLambda.compile(scopeLoop, "loop"); + llvm->initJit(); + + FnI_I fn = (FnI_I)llvm->getFunctionPointer(fnRaw); + ASSERT_EQ(20, fn(10)); } \ No newline at end of file diff --git a/cpp/tests/containers.cpp b/cpp/tests/containers.cpp index a7123c0..8f3074a 100644 --- a/cpp/tests/containers.cpp +++ b/cpp/tests/containers.cpp @@ -1,299 +1,321 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * containers.cpp * * Created on: Jun 9, 2015 * Author: pgess */ #include "xreatemanager.h" #include "query/containers.h" #include "main/Parser.h" #include "supplemental/docutils.h" #include "supplemental/basics.h" #include "gtest/gtest.h" using namespace std; using namespace xreate::grammar::main; using namespace xreate::containers; using namespace xreate; -TEST(Containers, AST_List1){ - string code = R"( - my-test = function:: int { - {month = 1, 2, #3 = 8} - } - )"; - - auto man = XreateManager::prepare(move(code)); - const Expression& listE = man->root->findFunction("my-test")->getEntryScope()->getBody(); - ASSERT_EQ(3, listE.bindings.size()); - ASSERT_EQ(3, listE.operands.size()); - set fields; - fields.insert(listE.bindings.begin(), listE.bindings.end()); - - ASSERT_TRUE(fields.count("month")); - ASSERT_TRUE(fields.count("0")); - ASSERT_TRUE(fields.count("3")); -} +struct Tuple2 {intmax_t a; intmax_t b;}; +typedef Tuple2 (*FnTuple2)(); -TEST(AST, AST_ListIndex1){ - string code = R"( - my-fn = function:: int; entry() - { - x = [1..2]:: [int]. - x + {[1] = 1} - } - )"; +struct Tuple3 {intmax_t a; intmax_t b; intmax_t c; }; +typedef Tuple3 (*FnTuple3)(); - auto man = XreateManager::prepare(move(code)); - const Expression& bodyE = man->root->findFunction("my-fn")->getEntryScope()->getBody(); +struct Tuple4 {intmax_t a; intmax_t b; intmax_t c; intmax_t d;}; +typedef Tuple4 (*FnTuple4)(); - ASSERT_EQ(2, bodyE.operands.size()); - const Expression opLiInE = bodyE.operands.at(1); - ASSERT_EQ(2, opLiInE.operands.size()); -} - -TEST(Containers, DONE_RecInitByList1){ +TEST(Containers, RecInitByList1){ string code = R"( Rec = type {x:: int, y:: int}. test = function(a:: int, b::int):: Rec; entry() { {x = a + b, y = 2} } )"; auto man = XreateManager::prepare(move(code)); man->run(); } -TEST(Containers, DONE_RecInitByList2){ +TEST(Containers, RecInitByList2){ string code = R"( Rec = type {x:: int, y:: int}. test = function(a:: int, b::int):: Rec; entry() { - {a + b, y = 2} + {a + b, y = 2} } )"; auto man = XreateManager::prepare(move(code)); man->run(); } -TEST(Containers, DONE_RecUpdateByList1){ +TEST(Containers, RecUpdateByList1){ string code = R"( Rec = type {x:: int, y:: int}. test = function(a:: int, b::int):: Rec; entry() { r = {0, y = 2}:: Rec. r : {a + b} } )"; auto man = XreateManager::prepare(move(code)); man->run(); } -TEST(Containers, DONE_RecUpdateByListIndex1){ +TEST(Containers, RecUpdateByListIndex1){ string code = R"( Rec = type {x:: int, y:: int}. test = function(a:: int, b::int):: int; entry() { r1 = undef:: Rec. r2 = r1 : {[1] = b, [0] = a}:: Rec. r2["x"] } )"; auto man = XreateManager::prepare(move(code)); Fn2Args program = (Fn2Args) man->run(); ASSERT_EQ(10, program(10, 11)); } -TEST(Containers, DONE_RecUpdateInLoop1){ +TEST(Containers, RecUpdateInLoop1){ FILE* code = fopen("scripts/containers/RecUpdateInLoop1.xreate", "r"); assert(code != nullptr); auto man = XreateManager::prepare(code); Fn1Args program = (Fn1Args) man->run(); ASSERT_EQ(11, program(10)); } -TEST(Containers, DONE_ArrayInit1){ +TEST(Containers, ArrayInit1){ XreateManager* man = XreateManager::prepare( R"Code( main = function(x:: int):: int; entry() { a = {1, 2, 3}:: [int]. a[x] } )Code"); void* mainPtr = man->run(); Fn1Args main = (Fn1Args) mainPtr; ASSERT_EQ(2, main(1)); delete man; } -TEST(Containers, DONE_ArrayUpdate1){ +TEST(Containers, ArrayUpdate1){ XreateManager* man = XreateManager::prepare(R"( main = function(x::int):: int; entry() { a = {1, 2, 3}:: [int]; csize(5). b = a : {[1] = x}:: [int]; csize(5). b[1] } )"); void* mainPtr = man->run(); Fn1Args main = (Fn1Args) mainPtr; ASSERT_EQ(2, main(2)); delete man; } -TEST(Containers, ListAsArray2){ - XreateManager* man = XreateManager::prepare( - -R"Code( - // CONTAINERS - import raw("scripts/dfa/ast-attachments.lp"). - import raw("scripts/containers/containers.lp"). - - main = function:: int;entry { - a= {1, 2, 3}:: [int]. - b= loop map(a->el:: int):: [int]{ - 2 * el - }. - - sum = loop fold(b->el:: int, 0->acc):: int { - acc + el - }. - - sum - } -)Code"); - - void* mainPtr = man->run(); - FnNoArgs main = (FnNoArgs) mainPtr; - ASSERT_EQ(12, main()); - - delete man; -} - -TEST(Containers, Doc_RecField1){ - string code_Variants1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "RecField1"); - XreateManager::prepare(move(code_Variants1)); - - ASSERT_TRUE(true); -} - -TEST(Containers, Doc_RecUpdate1){ - string code_Variants1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "RecUpdate1"); - XreateManager::prepare(move(code_Variants1)); - - ASSERT_TRUE(true); +TEST(Containers, FlyMap1){ + std::unique_ptr man(XreateManager::prepare(R"( +main = function:: int; entry() +{ + x = {1, 2, 3, 4}:: [int]. + y = loop map(x->el::int)::[int]; fly(csize(4)) + {2 * el:: int }. + loop fold((y::[int]; fly(csize(4)))->el:: int, 0->sum):: int {sum + el}-20 } +)")); -TEST(Containers, ContanierLinkedList1){ - FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r"); - assert(input != nullptr); - - Scanner scanner(input); - Parser parser(&scanner); - parser.Parse(); - - AST* ast = parser.root->finalize(); - CodeScope* body = ast->findFunction("test")->getEntryScope(); - const Symbol symb_chilrenRaw{body->getSymbol("childrenRaw"), body}; - - containers::ImplementationLinkedList iLL(symb_chilrenRaw); - - ASSERT_EQ(true, static_cast(iLL)); - ASSERT_EQ("next", iLL.fieldPointer); - - Implementation impl = Implementation::create(symb_chilrenRaw); - ASSERT_NO_FATAL_FAILURE(impl.extract()); - - ImplementationRec recOnthefly = impl.extract(); - ASSERT_EQ(symb_chilrenRaw, recOnthefly.source); + FnNoArgs mainFn = (FnNoArgs) man->run(); + intmax_t valueMain = mainFn(); + ASSERT_EQ(0, valueMain); } -TEST(Containers, Implementation_LinkedListFull){ - FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r"); - assert(input != nullptr); - - std::unique_ptr program(XreateManager::prepare(input)); - void* mainPtr = program->run(); - int (*main)() = (int (*)())(intptr_t)mainPtr; - - intmax_t answer = main(); - ASSERT_EQ(17, answer); - - fclose(input); +intmax_t fn_BUG_Triple(FnTuple3 callee){ + Tuple3 result = callee(); + return result.a+ result.b + result.c; } +TEST(Containers, BUG_Triple){ + std::unique_ptr man(XreateManager::prepare(R"( +Tuple2 = type {int, int}. +Tuple3 = type {int, int, int}. +Tuple4 = type {int, int, int, int}. -TEST(Containers, Doc_Intr_1){ - string example = R"Code( - import raw("scripts/containers/containers.lp"). - - test = function:: int; entry - { - - x - } - )Code"; - string body = getDocumentationExampleById("documentation/Concepts/containers.xml", "Intr_1"); - replace(example, "", body); - - XreateManager* xreate = XreateManager::prepare(move(example)); - FnNoArgs program = (FnNoArgs) xreate->run(); - - intmax_t result = program(); - ASSERT_EQ(1, result); +main = function:: Tuple3; entry() +{ + {1, 2, 3} } +)")); + FnTuple3 mainFn = (FnTuple3) man->run(); + intmax_t result = fn_BUG_Triple(mainFn); -TEST(Containers, Doc_OpAccessSeq_1){ - string example = getDocumentationExampleById("documentation/Concepts/containers.xml", "OpAccessSeq_1"); - XreateManager* xreate = XreateManager::prepare(move(example)); - FnNoArgs program = (FnNoArgs) xreate->run(); - - intmax_t result = program(); - ASSERT_EQ(15, result); + ASSERT_EQ(6, result); +// ASSERT_EQ(2, result.b); +// ASSERT_EQ(3, result.c); } -TEST(Containers, Doc_OpAccessRand_1){ - string example = getDocumentationExampleById("documentation/Concepts/containers.xml", "OpAccessRand_1"); - XreateManager* xreate = XreateManager::prepare(move(example)); - FnNoArgs program = (FnNoArgs) xreate->run(); - - intmax_t result = program(); - ASSERT_EQ(2, result); -} +TEST(Containers, ArrayArg1){ + FILE* code = fopen("scripts/containers/array_arg_1.xreate", "r"); + assert(code != nullptr); -TEST(Containers, Doc_ASTAttach_1){ - string example = getDocumentationExampleById("documentation/Concepts/containers.xml", "ASTAttach_1"); - string outputExpected = "containers_impl(s(1,-2,0),onthefly)"; - XreateManager* xreate = XreateManager::prepare(move(example)); - - testing::internal::CaptureStdout(); - xreate->run(); - std::string outputActual = testing::internal::GetCapturedStdout(); - - ASSERT_NE(std::string::npos, outputActual.find(outputExpected)); + std::unique_ptr man (XreateManager::prepare(code)); + FnNoArgs mainFn = (FnNoArgs) man->run(); + ASSERT_EQ(0, mainFn()); } -TEST(Containers, IntrinsicArrInit1){ - XreateManager* man = XreateManager::prepare( -R"Code( -FnAnns = type predicate { - entry -} - -main = function(x:: int):: int; entry() { - a{0} = intrinsic array_init(16):: [int]. - a{1} = a{0} + {15: 12} -} -)Code"); -} +//TEST(Containers, ListAsArray2){ +// XreateManager* man = XreateManager::prepare( +// +//R"Code( +// // CONTAINERS +// import raw("scripts/dfa/ast-attachments.lp"). +// import raw("scripts/containers/containers.lp"). +// +// main = function:: int;entry { +// a= {1, 2, 3}:: [int]. +// b= loop map(a->el:: int):: [int]{ +// 2 * el +// }. +// +// sum = loop fold(b->el:: int, 0->acc):: int { +// acc + el +// }. +// +// sum +// } +//)Code"); +// +// void* mainPtr = man->run(); +// FnNoArgs main = (FnNoArgs) mainPtr; +// ASSERT_EQ(12, main()); +// +// delete man; +//} +// +//TEST(Containers, Doc_RecField1){ +// string code_Variants1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "RecField1"); +// XreateManager::prepare(move(code_Variants1)); +// +// ASSERT_TRUE(true); +//} +// +//TEST(Containers, Doc_RecUpdate1){ +// string code_Variants1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "RecUpdate1"); +// XreateManager::prepare(move(code_Variants1)); +// +// ASSERT_TRUE(true); +//} +// +//TEST(Containers, ContanierLinkedList1){ +// FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r"); +// assert(input != nullptr); +// +// Scanner scanner(input); +// Parser parser(&scanner); +// parser.Parse(); +// +// AST* ast = parser.root->finalize(); +// CodeScope* body = ast->findFunction("test")->getEntryScope(); +// const Symbol symb_chilrenRaw{body->getSymbol("childrenRaw"), body}; +// +// containers::ImplementationLinkedList iLL(symb_chilrenRaw); +// +// ASSERT_EQ(true, static_cast(iLL)); +// ASSERT_EQ("next", iLL.fieldPointer); +// +// Implementation impl = Implementation::create(symb_chilrenRaw); +// ASSERT_NO_FATAL_FAILURE(impl.extract()); +// +// ImplementationRec recOnthefly = impl.extract(); +// ASSERT_EQ(symb_chilrenRaw, recOnthefly.source); +//} +// +//TEST(Containers, Implementation_LinkedListFull){ +// FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r"); +// assert(input != nullptr); +// +// std::unique_ptr program(XreateManager::prepare(input)); +// void* mainPtr = program->run(); +// int (*main)() = (int (*)())(intptr_t)mainPtr; +// +// intmax_t answer = main(); +// ASSERT_EQ(17, answer); +// +// fclose(input); +//} +// +//TEST(Containers, Doc_Intr_1){ +// string example = R"Code( +// import raw("scripts/containers/containers.lp"). +// +// test = function:: int; entry +// { +// +// x +// } +// )Code"; +// string body = getDocumentationExampleById("documentation/Concepts/containers.xml", "Intr_1"); +// replace(example, "", body); +// +// XreateManager* xreate = XreateManager::prepare(move(example)); +// FnNoArgs program = (FnNoArgs) xreate->run(); +// +// intmax_t result = program(); +// ASSERT_EQ(1, result); +//} +// +//TEST(Containers, Doc_OpAccessSeq_1){ +// string example = getDocumentationExampleById("documentation/Concepts/containers.xml", "OpAccessSeq_1"); +// XreateManager* xreate = XreateManager::prepare(move(example)); +// FnNoArgs program = (FnNoArgs) xreate->run(); +// +// intmax_t result = program(); +// ASSERT_EQ(15, result); +//} +// +//TEST(Containers, Doc_OpAccessRand_1){ +// string example = getDocumentationExampleById("documentation/Concepts/containers.xml", "OpAccessRand_1"); +// XreateManager* xreate = XreateManager::prepare(move(example)); +// FnNoArgs program = (FnNoArgs) xreate->run(); +// +// intmax_t result = program(); +// ASSERT_EQ(2, result); +//} +// +//TEST(Containers, Doc_ASTAttach_1){ +// string example = getDocumentationExampleById("documentation/Concepts/containers.xml", "ASTAttach_1"); +// string outputExpected = "containers_impl(s(1,-2,0),onthefly)"; +// XreateManager* xreate = XreateManager::prepare(move(example)); +// +// testing::internal::CaptureStdout(); +// xreate->run(); +// std::string outputActual = testing::internal::GetCapturedStdout(); +// +// ASSERT_NE(std::string::npos, outputActual.find(outputExpected)); +//} +// +//TEST(Containers, IntrinsicArrInit1){ +// XreateManager* man = XreateManager::prepare( +// +//R"Code( +//FnAnns = type predicate { +// entry +//} +// +//main = function(x:: int):: int; entry() { +// a{0} = intrinsic array_init(16):: [int]. +// a{1} = a{0} + {15: 12} +//} +//)Code"); +//} diff --git a/cpp/tests/problems.cpp b/cpp/tests/problems.cpp index 1ea7797..054fa66 100644 --- a/cpp/tests/problems.cpp +++ b/cpp/tests/problems.cpp @@ -1,134 +1,188 @@ // // Created by pgess on 26/03/2020. // #include "xreatemanager.h" #include "pass/compilepass.h" #include "llvmlayer.h" #include "supplemental/basics.h" #include "gtest/gtest.h" using namespace xreate; -TEST(Problems, MinMax1){ - struct Pair {intmax_t x; intmax_t y;}; - typedef Pair (*FnPair)(); +struct Pair {intmax_t x; intmax_t y;}; +typedef Pair (*FnPair)(); + +struct Tuple3 {intmax_t x; intmax_t y; intmax_t z; }; +typedef Tuple3 (*FnTuple3)(); + +//struct Tuple4 {Pair x; Pair y;}; +struct Tuple4 {intmax_t a; intmax_t b; intmax_t c; intmax_t d;}; +typedef Tuple4 (*FnTuple4)(); +TEST(Problems, MinMax1){ FILE* code = fopen("scripts/containers/minmax.xreate", "r"); assert(code != nullptr); auto man = details::tier1::XreateManager::prepare(code); LLVMLayer* llvm = man->llvm; man->analyse(); std::unique_ptr compiler(new compilation::CompilePassCustomDecorators<>(man)); compiler->prepare(); llvm::Function* fnMinMax1Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax1"))->compile(); llvm::Function* fnMinMax2Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax2"))->compile(); llvm::Function* fnMinMax3Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax3"))->compile(); llvm::Function* fnMinMax4Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax4"))->compile(); llvm::Function* fnMinMax5Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax5"))->compile(); llvm::Function* fnMinMax6Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax6"))->compile(); llvm::Function* fnMinMax7Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax7"))->compile(); llvm::Function* fnMinMax8Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax8"))->compile(); llvm::Function* fnMinMax9Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax9"))->compile(); llvm::Function* fnMinMax10Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax10"))->compile(); llvm::Function* fnMinMax11Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax11"))->compile(); llvm::Function* fnMinMax12Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax12"))->compile(); llvm::Function* fnMinMax13Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax13"))->compile(); llvm::Function* fnMinMax14Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax14"))->compile(); + llvm::Function* fnMinMax15Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax15"))->compile(); + llvm::Function* fnMinMax19Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax19"))->compile(); + llvm::Function* fnMinMax20Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax20"))->compile(); + llvm::Function* fnMinMax21Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax21"))->compile(); + llvm::Function* fnMinMax22Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax22"))->compile(); + llvm::Function* fnMinMax23Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax23"))->compile(); llvm->print(); llvm->initJit(); { FnPair fnMinxMax1 = (FnPair) llvm->getFunctionPointer(fnMinMax1Raw); Pair resultMinMax1 = fnMinxMax1(); ASSERT_EQ(3, resultMinMax1.x); ASSERT_EQ(37, resultMinMax1.y); } { FnNoArgs fnMinMax2 = (FnNoArgs) llvm->getFunctionPointer(fnMinMax2Raw); intmax_t resultMinMax2 = fnMinMax2(); ASSERT_EQ(10, resultMinMax2); } { FnNoArgs fnMinMax3 = (FnNoArgs) llvm->getFunctionPointer(fnMinMax3Raw); intmax_t resultMinMax3 = fnMinMax3(); ASSERT_EQ(146, resultMinMax3); } { FnNoArgs fnMinMax4 = (FnNoArgs) llvm->getFunctionPointer(fnMinMax4Raw); intmax_t resultMinMax4 = fnMinMax4(); ASSERT_EQ(6, resultMinMax4); } { FnPair fnMinMax5 = (FnPair) llvm->getFunctionPointer(fnMinMax5Raw); Pair resultMinMax5 = fnMinMax5(); ASSERT_EQ(4, resultMinMax5.x); ASSERT_EQ(11, resultMinMax5.y); } { FnPair fnMinMax6 = (FnPair) llvm->getFunctionPointer(fnMinMax6Raw); Pair resultMinMax6 = fnMinMax6(); ASSERT_EQ(2, resultMinMax6.x); ASSERT_EQ(8, resultMinMax6.y); } { FnPair fnMinMax7 = (FnPair) llvm->getFunctionPointer(fnMinMax7Raw); Pair resultMinMax7 = fnMinMax7(); ASSERT_EQ(1, resultMinMax7.x); ASSERT_EQ(3, resultMinMax7.y); } { FnPair fnMinMax8 = (FnPair) llvm->getFunctionPointer(fnMinMax8Raw); Pair resultMinMax8 = fnMinMax8(); ASSERT_EQ(2, resultMinMax8.x); ASSERT_EQ(3, resultMinMax8.y); } { FnPair fnMinMax9 = (FnPair) llvm->getFunctionPointer(fnMinMax9Raw); Pair resultMinMax9 = fnMinMax9(); ASSERT_EQ(1, resultMinMax9.x); ASSERT_EQ(8, resultMinMax9.y); } { FnNoArgs fnMinMax10 = (FnNoArgs ) llvm->getFunctionPointer(fnMinMax10Raw); intmax_t resultMinMax10 = fnMinMax10(); ASSERT_EQ(1, resultMinMax10); } { FnNoArgs fnMinMax11 = (FnNoArgs ) llvm->getFunctionPointer(fnMinMax11Raw); intmax_t resultMinMax11 = fnMinMax11(); ASSERT_EQ(8, resultMinMax11); } { FnNoArgs fnMinMax12 = (FnNoArgs ) llvm->getFunctionPointer(fnMinMax12Raw); intmax_t resultMinMax12 = fnMinMax12(); ASSERT_EQ(2, resultMinMax12); } { FnNoArgs fnMinMax13 = (FnNoArgs ) llvm->getFunctionPointer(fnMinMax13Raw); intmax_t resultMinMax13 = fnMinMax13(); ASSERT_EQ(3, resultMinMax13); } { FnPair fnMinMax14 = (FnPair) llvm->getFunctionPointer(fnMinMax14Raw); Pair resultMinMax14 = fnMinMax14(); ASSERT_EQ(2, resultMinMax14.x); ASSERT_EQ(3, resultMinMax14.y); } + + { + FnPair fnMinMax15 = (FnPair) llvm->getFunctionPointer(fnMinMax15Raw); + Pair resultMinMax15 = fnMinMax15(); + ASSERT_EQ(1, resultMinMax15.x); + ASSERT_EQ(16, resultMinMax15.y); + } + + { + FnNoArgs fnMinMax19 = (FnNoArgs) llvm->getFunctionPointer(fnMinMax19Raw); + intmax_t resultMinMax19 = fnMinMax19(); + ASSERT_EQ(3, resultMinMax19); + } + + { + FnNoArgs fnMinMax20 = (FnNoArgs) llvm->getFunctionPointer(fnMinMax20Raw); + intmax_t resultMinMax20 = fnMinMax20(); + ASSERT_EQ(4, resultMinMax20); + } + + { + FnNoArgs fnMinMax21 = (FnNoArgs) llvm->getFunctionPointer(fnMinMax21Raw); + intmax_t resultMinMax21 = fnMinMax21(); + ASSERT_EQ(5, resultMinMax21); + } + + { + FnPair fnMinMax22 = (FnPair) llvm->getFunctionPointer(fnMinMax22Raw); + Pair resultMinMax22 = fnMinMax22(); + ASSERT_EQ(-29, resultMinMax22.x); + ASSERT_EQ(-14, resultMinMax22.y); + } + + { + FnTuple4 fnMinMax23 = (FnTuple4) llvm->getFunctionPointer(fnMinMax23Raw); + Tuple4 resultMinMax23 = fnMinMax23(); + + ASSERT_EQ(96, resultMinMax23.a); + ASSERT_EQ(63, resultMinMax23.b); + ASSERT_EQ(28, resultMinMax23.c); + } } \ No newline at end of file diff --git a/grammar/xreate.ATG b/grammar/xreate.ATG index 8670b4e..307d0a6 100644 --- a/grammar/xreate.ATG +++ b/grammar/xreate.ATG @@ -1,836 +1,836 @@ //TODO add ListLiteral //TODO ExprTyped: assign default(none) type #include "ast.h" #include "ExternLayer.h" #include #include #include #define wprintf(format, ...) \ char __buffer[100]; \ wcstombs(__buffer, format, 100); \ fprintf(stderr, __buffer, __VA_ARGS__) using namespace std; COMPILER Xreate details::inconsistent::AST* root = nullptr; // current program unit void SemErr(std::initializer_list msgs){ std::wstringstream output; for(const auto& msg: msgs){output << msg;} SemErr(output.str().c_str()); } void ensureInitalizedAST(){ if (root == nullptr) root = new details::inconsistent::AST(); } struct { std::stack scopesOld; CodeScope* scope = nullptr; } context; void pushContextScope(CodeScope* scope){ context.scopesOld.push(context.scope); context.scope = scope; } void popContextScope(){ context.scope = context.scopesOld.top(); context.scopesOld.pop(); } int nextToken() { scanner->ResetPeek(); return scanner->Peek()->kind; } bool checkTokenAfterIdent(int key){ if (la->kind != _ident) return false; return nextToken() == key; } bool checkParametersList() { return la->kind == _ident && nextToken() == _lparen; } bool checkInfix() { return la->kind == _ident && nextToken() == _ident; } bool checkIndex() { return la->kind == _ident && nextToken() == _lbrack; } bool checkListIndex() { return la->kind == _lcurbrack && nextToken() == _lbrack; } bool checkFuncDecl() { if (la->kind != _ident) return false; int token2 = nextToken(); int token3 = scanner->Peek()->kind; return token2 == _assign && token3 == _function; } 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& id, const std::wstring& hint){ if (!context.scope) SemErr({L"Identifier found in undefined scope: ", hint}); if (!context.scope->recognizeIdentifier(id)){ root->postponeIdentifier(context.scope, id); } } enum SwitchKind{SWITCH_NORMAL, SWITCH_META}; CHARACTERS letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". any = ANY - '"'. digit = "0123456789". cr = '\r'. lf = '\n'. tab = '\t'. TOKENS ident = (letter ['-' letter] | '_') {letter ['-' letter] | digit | '_' }. number = digit{digit}. string = '"' { any } '"'. function = "function". comma = ','. period = '.'. lparen = '('. rparen = ')'. lbrack = '['. rbrack = ']'. lcurbrack = '{'. rcurbrack = '}'. equal = "==". assign = '='. implic = '-' '>'. colon = ':'. tagcolon = "::". lse = "<=". lss = "<". gte = ">=". gtr = ">". ne1 = "!=". ne2= "<>". COMMENTS FROM "/*" TO "*/" NESTED COMMENTS FROM "//" TO lf IGNORE cr + lf + tab PRODUCTIONS Xreate = (. Function* function; ensureInitalizedAST(); .) {( //RuleDecl InterfaceData | Imprt | GuardSection | IF(checkFuncDecl()) FDecl (. root->add(function); .) | TDecl | SkipModulesSection )} (. .) . Ident= ident (. name = t->val; .). // recognition IdentR = (. std::wstring name; .) Ident (. e = Expression(Atom(name)); .) (. recognizeIdentifier(e, name); .). //versioning IdentV= (. std::wstring name; .) Ident (. e = Expression(Atom(name)); .) [ Version ]. //recognition + versioning IdentVR= (. std::wstring name; .) Ident (. e = Expression(Atom(name)); .) [ Version ] (. recognizeIdentifier(e, name); .) . Version= lcurbrack ( ident (. SemErr({L"var version as ident is not implemented yet"}); .) | number (. Attachments::put(e, Atom(t->val).get()); .) ) rcurbrack . FDecl = (. std::wstring fname; std::wstring argName; TypeAnnotation typIn; TypeAnnotation typOut; Expression binding; .) Ident assign function (. f = new Function(fname); CodeScope* entry = f->getEntryScope(); .) [lparen Ident tagcolon ExprAnnotations (. f->addBinding(Atom(argName), move(binding)); .) {comma Ident tagcolon ExprAnnotations (. f->addBinding(Atom (argName), move(binding));.) } rparen] -[ tagcolon Type {';' FnTag }] +tagcolon Type {';' FnTag } BDecl (. const_cast(entry->getBody()).bindType(move(typOut));.) . GuardSection<>= (. std::wstring arg, guardI; Expression guardE, guardBinding; Function* f; TypeAnnotation guardT; .) "guard" lparen [Ident] tagcolon Ident (. guardE = Expression(Operator::CALL, {Atom(guardI)}); bool res = root->recognizeVariantConstructor(guardE); .) (. if(!res) SemErr(coco_string_create("Can't recognize a guard"));.) (. if (!arg.empty()) guardE.addBindings({Atom(arg)}); .) (. guardBinding.type = TypeAnnotation(TypeOperator::GUARD, {guardE.type}); guardBinding.type.__valueCustom = Atom(guardI).get(); .) rparen lcurbrack { FDecl (. f->guard = guardE; if (!arg.empty()){f->addBinding(Atom(arg), Expression(guardBinding));} .) (. root->add(f); .) } rcurbrack . /** * TYPES * */ TypeTerm = (. std::wstring tid; .) ( "string" (. typ = TypePrimitive::String;.) | "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; std::string field; .) ( TList | TRecord | TVariant | TPred | TSlave | TRef | TypeTerm (. typ = typ3; .) | IF (checkIndex()) Ident lbrack TypeIndex (. typ = TypeAnnotation(TypeOperator::ACCESS, {}); typ.__valueCustom = Atom(tid).get(); typ.fields.push_back(field); .) {comma TypeIndex (. typ.fields.push_back(field); .) } rbrack | Ident (. typ = TypeAnnotation(TypeOperator::ALIAS, {}); typ.__valueCustom = Atom(tid).get(); .) [lparen Type (. typ.__operands.push_back(typ2); .) {comma Type (. typ.__operands.push_back(typ2); .) } rparen] | '*' (.typ = TypeAnnotation(); .) ) . TypeIndex = ( number (. name = Atom(t->val).get(); .) | string (. name = Atom(t->val).get(); .) ) . TList = (. TypeAnnotation ty; .) lbrack Type rbrack (. typ = TypeAnnotation(TypeOperator::ARRAY, {ty}); .) . TRecordBody = (. TypeAnnotation t; std::wstring key; size_t keyCounter=0; typ = TypeAnnotation(TypeOperator::RECORD, {}); .) { ( IF(checkTokenAfterIdent(_tagcolon)) Ident tagcolon | (. key = to_wstring(keyCounter++); .) ) Type [comma] (. typ.__operands.push_back(t); .) (. typ.fields.push_back(Atom(key).get()); .) }. TRecord = lcurbrack TRecordBody rcurbrack (. if(!typ.__operands.size()) SemErr(coco_string_create("Record type can't be empty.")); .) . TVariantRec = (. TypeAnnotation typVoid; .) lparen TRecordBody rparen (. if(typ.__operands.size()==0) typ = typVoid; .) . TVariantBody = (. TypeAnnotation t, typVoid; std::vector operands; std::vector> keys; std::wstring v; .) lcurbrack { (. t = typVoid; .) Ident [TVariantRec] (. keys.push_back(Atom(v)); operands.push_back(t); .) [comma] } rcurbrack (. typ = TypeAnnotation(TypeOperator::VARIANT, {}); typ.__operands = operands; typ.addFields(std::move(keys)); .) . TVariant= "variant" TVariantBody (. if(!typ.__operands.size()) SemErr(coco_string_create("Variant type can't be empty.")); .) . TPred= "predicate" TVariantBody (. if(!typ.__operands.size()) SemErr(coco_string_create("Predicate type can't be empty.")); .) . TSlave= "slave" (. typ = TypeAnnotation(TypeOperator::SLAVE, {}); .) lparen string (. typ.__valueCustom = Atom(t->val).get(); .) rparen . TRef= (. TypeAnnotation typChild; .) "ref" lparen Type rparen (. typ = TypeAnnotation(TypeOperator::REF, {typChild}); .) . TDecl = (. TypeAnnotation t; std::wstring tname, arg; std::vector> args; .) Ident assign "type" [lparen Ident (. args.push_back(Atom(arg)); .) {comma Ident (. args.push_back(Atom(arg)); .) } rparen] Type[period] (. 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 = (. Expression var, value;.) IdentV assign ExprTyped (. Symbol identSymbol = f->addDefinition(move(var), move(value)); Attachments::put(value, identSymbol); .) . BDecl = lcurbrack (. Expression body; pushContextScope(scope); bool flagBodyFound = false; .) {(IF(checkAssignment()) VDecl period // | RuleContextDecl | ContextDeclperiod | ExprTyped (. scope->setBody(body); flagBodyFound = true; Attachments::put(body, Symbol{ScopedSymbol::RetSymbol, scope});.) )} rcurbrack (. if(!flagBodyFound) SemErr(coco_string_create("Code block with an empty body!")); popContextScope(); .) . IfDecl = (. Expression cond(Operator::AND, {}), condPart; ManagedScpPtr blockTrue = root->add(new CodeScope(context.scope)); ManagedScpPtr blockFalse = root->add(new CodeScope(context.scope)); e = Expression(Operator::IF, {}); .) "if" lparen Expr (. cond.operands.push_back(condPart); .) { comma Expr (. cond.operands.push_back(condPart); .) } rparen (. e.operands.push_back(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" lparen Expr implic Ident (. e = Expression(Operator::MAP, {eIn}); .) tagcolon ExprAnnotations rparen tagcolon ExprAnnotations (. e.addBindings({Atom(varEl)}); block->addBinding(Atom(varEl), move(tagsEl)); .) BDecl<&*block> (. e.addBlock(block); .) | "fold" lparen Expr implic Ident tagcolon ExprAnnotations ['|' Expr ] comma Expr implic Identrparen (. e = Expression(Operator::FOLD, {eIn, eAcc}); e.addBindings({Atom(varEl), Atom(varAcc)}); .) tagcolon ExprAnnotations (. Expression varAccBindingE; varAccBindingE.type = e.type; block->addBinding(Atom(varEl), move(tagsEl)); block->addBinding(Atom(varAcc), move(varAccBindingE)); .) BDecl<&*block> (. e.addBlock(block); .) | lparen Expr implic Ident rparen (. e = Expression(Operator::FOLD_INF, {eAcc}); e.addBindings({Atom(varAcc)}); .) tagcolon ExprAnnotations (. Expression varAccBindingE; varAccBindingE.type = e.type; block->addBinding(Atom(varAcc), move(varAccBindingE)); .) BDecl<&*block> (. e.addBlock(block); .) ). // Switches SwitchDecl = (. TypeAnnotation typ; eSwitch = Expression(Operator::SWITCH, {}); Expression eCondition; Expression tag;.) "switch" ( SwitchVariantDecl | SwitchLateDecl | lparen ExprTyped rparen tagcolon ExprAnnotations (. eSwitch.operands.push_back(eCondition);.) CaseDecl {CaseDecl} ) . CaseDecl = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); Expression condition; .) "case" ( IF(flagSwitchKind == SWITCH_META) lparen MetaSimpExpr rparen BDecl<&*scope> (. Expression exprCase(Operator::CASE, {}); exprCase.addTags({condition}); exprCase.addBlock(scope); outer.addArg(move(exprCase));.) | "default" BDecl<&*scope> (. Expression exprCase(Operator::CASE_DEFAULT, {}); exprCase.addBlock(scope); outer.operands.insert(++outer.operands.begin(), exprCase); .) | lparen CaseParams<&*scope> rparen (. ManagedScpPtr scopeBody = root->add(new CodeScope(&*scope)); Expression exprCase(Operator::CASE, {}); .) BDecl<&*scopeBody> (. exprCase.addBlock(scope); exprCase.addBlock(scopeBody); outer.addArg(move(exprCase)); .) ). CaseParams = (. Expression condition; Expression guard(Operator::LOGIC_AND, {}); pushContextScope(scope); .) ExprTyped (. guard.addArg(Expression(condition)); .) {comma ExprTyped (. guard.addArg(Expression(condition)); .) } (. scope->setBody(guard); popContextScope(); .) . SwitchLateDecl = (. std::wstring aliasCondition; Expression exprCondition, aliasAnns; expr = Expression(Operator::SWITCH_LATE, {}); ManagedScpPtr scope = root->add(new CodeScope(context.scope)); .) "late" lparen Expr [implic Ident] [tagcolon ExprAnnotations] rparen tagcolon ExprAnnotations BDecl<&*scope> (. expr.addArg(Expression(exprCondition)); expr.addBlock(scope); std::string alias; if(aliasCondition.empty()){ if(exprCondition.__state != Expression::IDENT){ SemErr(coco_string_create("An identifier expected in the short form")); return; } //Use exprCondition as identifier alias = exprCondition.getValueString(); } else { //Use aliasCondition alias = Atom(move(aliasCondition)).get(); } expr.addBindings({Atom(string(alias))}); scope->addBinding(Atom(move(alias)), move(aliasAnns)); .) . SwitchVariantDecl = (. Expression varTested; std::wstring varAlias; bool flagAliasFound = false; expr = Expression(Operator::SWITCH_VARIANT, {}); .) "variant" lparen Expr [implic Ident (. flagAliasFound = true; .) ] [tagcolon ExprAnnotations] rparen tagcolon ExprAnnotations (. expr.addArg(std::move(varTested)); if (flagAliasFound) { expr.addBindings({Atom(varAlias)}); } else { if(varTested.__state == Expression::IDENT){ expr.addBindings({Atom(string(varTested.getValueString()))}); } } .) CaseVariantDecl {CaseVariantDecl} . CaseVariantDecl = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); std::wstring key; scope->addBinding(Atom(string(expr.bindings.front())), Expression()); .) "case" lparen Ident rparen (. expr.addArg(root->recognizeVariantConstructor(Atom(std::move(key)))); .) BDecl<&*scope> (. expr.addBlock(scope); .) . IntrinsicDecl= (. std::wstring name; .) "intrinsic" ( Ident< name> (. outer = Expression(Operator::CALL_INTRINSIC, {}); outer.setValue(Atom(name)); root->recognizeIntrinsic(outer); .) lparen [CalleeParams] rparen | "query" (. outer = Expression(Operator::QUERY, {}); .) ( "late" IntrinsicQueryLateDecl | lparen [CalleeParams] rparen ) ). IntrinsicQueryLateDecl = (. std::wstring predicateAlias; Expression predicateE, predicateAnns; expr = Expression(Operator::QUERY_LATE, {}); ManagedScpPtr scope = root->add(new CodeScope(context.scope)); .) lparen Expr implic Ident tagcolon ExprAnnotations rparen tagcolon ExprAnnotations BDecl<&*scope> (. expr.addArg(move(predicateE)); expr.addBindings({Atom(wstring(predicateAlias))}); scope->addBinding(Atom(move(predicateAlias)), move(predicateAnns)); expr.addBlock(scope); .) . SequenceDecl = (. sequence = Expression(); sequence.setOp(Operator::SEQUENCE); ManagedScpPtr scope = root->add(new CodeScope(context.scope)); .) "seq" BDecl<&*scope> (. sequence.blocks.push_back(&*scope); scope = root->add(new CodeScope(&*scope)); .) { (. scope = root->add(new CodeScope(&*scope)); .) BDecl<&*scope> (. sequence.blocks.push_back(&*scope); .) }. /*============================ INTERFACES ===============================*/ Imprt<> = "import" "raw" lparen string (. root->__rawImports.push_back(Atom(t->val).get()); .) rparen period. InterfaceData<> = "interface" lparen ( "dfa" rparen InterfaceDFA // | "extern-c" rparen InterfaceExternC | "cfa" rparen InterfaceCFA ). // InterfaceExternC<> = (. ExternData data; .) // lcurbrack {ExternHeadersDecl | ExternAliasDecl } rcurbrack // (. root->addExternData(move(data)); .) // . // // ExternPkgDecl = // "pkgconfig" lparen // string (. package = t->val.) // rparen // . // // ExternAliasDecl = (. std::wstring alias, package; .) // Ident assign "library" lparen ExternPkgDecl rparen period // (. data.addLibAlias(Atom(alias), Atom(package)); .) // . // // ExternHeadersDecl = (. std::list listInc; std::wstring& package; .) // "include" // [lparen // ( // Ident (. data.requireLibAlias(Atom(alias)); .) // | ExternPkgDecl (. data.requireLibPackage(Atom(package)); .) // ) // rparen] // lcurbrack { string (. listInc.push_back(Atom(t->val).get()); .) // [comma] } rcurbrack [period] (. data.requireHeaders(listInc); .) // . InterfaceDFA<> = lcurbrack { InstructDecl } rcurbrack . InstructDecl = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; tags.push_back(Expression()); /* return value */ .) "operator" InstructAlias tagcolon lparen (.scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { comma MetaSimpExpr (. tags.push_back(tag); .) } ] rparen [ implic MetaSimpExpr (. tags[0] = tag; .) ] (. root->addDFAData(move(scheme)); .) period. InstructAlias = ( "map" (. op = Operator::MAP; .) | "list_range" (. op = Operator::LIST_RANGE; .) | "list" (. op = Operator::LIST; .) | "fold" (. op = Operator::FOLD; .) | "index" (. op = Operator::INDEX; .) ). InterfaceCFA<> = lcurbrack { InstructCFADecl } rcurbrack . InstructCFADecl<> = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; .) "operator" InstructAlias tagcolon (. scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { comma MetaSimpExpr (. tags.push_back(tag); .) } ] period (. root->addInterfaceData(CFA, move(scheme)); .). /*============================ METAPROGRAMMING ===============================*/ // TagsDecl = (. Expression tag; TagModifier mod = TagModifier::NONE; .) // ':' { MetaSimpExpr (. /*f.addTag(std::move(tag), mod); */ .) // }. FnTag = (. Expression tag; TagModifier mod = TagModifier::NONE; .) MetaSimpExpr ['-' TagMod] (. f->addTag(std::move(tag), mod); .). TagMod = ( "assert" (. mod = TagModifier::ASSERT; .) | "require" (. mod = TagModifier::REQUIRE; .) ). // RuleDecl<> = // "rule" tagcolon (. RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg; .) // lparen Ident tagcolon Domain (. args.add(arg, typ); .) // {comma Ident tagcolon Domain (. args.add(arg, typ); .) // } rparen // ["case" RGuard {comma RGuard}] // lcurbrack RBody rcurbrack . /* - TODO use RGuard for guards-*/ // RuleContextDecl = (.Expression eHead, eGuards, eBody; .) // "rule" "context" tagcolon MetaSimpExpr // "case" lparen MetaSimpExpr rparen // lcurbrack MetaSimpExpr rcurbrack (.scope->contextRules.push_back(Expression(Operator::CONTEXT_RULE, {eHead, eGuards, eBody})); .). // Domain = // ( // "function" (. dom = DomainAnnotation::FUNCTION; .) // | "variable" (. dom = DomainAnnotation::VARIABLE; .) // ). // RGuard= (. Expression e; .) // MetaExpr (. guards.add(std::move(e)); .). // MetaExpr= (.Operator op; Expression e2; .) // MetaExpr2 // [MetaOp MetaExpr2 (. e = Expression(op, {e, e2}); .) // ]. // MetaExpr2= // ( // lparen MetaExpr rparen // | MetaSimpExpr // ). MetaSimpExpr= (. std::wstring i1, infix; Expression e2; .) ( '-' MetaSimpExpr (. e = Expression(Operator::NEG, {e2}); .) | IF(checkParametersList()) Ident (. e = Expression(Operator::CALL, {Expression(Atom(i1))}); if (!root->recognizeVariantConstructor(e)) SemErr({L"Undefined predicate: ", i1}); .) lparen [ MetaCalleeParams ] rparen | IF(checkInfix()) Ident Ident MetaSimpExpr (. e = Expression(Operator::CALL, {Expression(Atom(infix))}); e.addArg(Expression(Atom(i1))); e.addArg(std::move(e2)); .) | IdentR | number (. e = Expression(Atom(t->val)); .) ). MetaCalleeParams = (. Expression e2; .) MetaSimpExpr (. e.addArg(Expression(e2)); .) {comma MetaSimpExpr (. e.addArg(Expression(e2)); .) }. // RBody = // (. Expression e; std::wstring msg; .) // "warning" MetaExpr ["message" string (. msg = t->val; .) // ] (. root->add(new RuleWarning(RuleArguments(args), RuleGuards(guards), std::move(e), Atom(msg))); .) // . // MetaOp< Operator& op> = // implic (. op = Operator::IMPL; .) // . /*============================ Expressions ===============================*/ ExprAnnotations = (. TypeAnnotation typ; std::list tags; Expression tag; e.tags.clear();.) Type (. e.bindType(move(typ)); .) {';' MetaSimpExpr (. tags.push_back(tag); .) } (. e.addTags(tags); .) . ExprTyped = Expr [tagcolon ExprAnnotations]. Expr< Expression& e> (. Expression e2; .) = ExprLogicAnd [ ("or" | "OR") Expr (. e = Expression(Operator::OR, {e, e2}); .) ] . ExprLogicAnd< Expression& e> (. Expression e2; .) = ExprRel [ ("and" | "AND") ExprLogicAnd (. e = Expression(Operator::AND, {e, e2}); .) ] . ExprRel< Expression& e> (. Operator op; Expression e2; .) = ExprArithmAdd [ RelOp ExprRel (. e = Expression(op, {e, e2}); .) ] . ExprArithmAdd< Expression& e>= (. Operator op; Expression e2; .) ExprArithmMul< e> [ AddOpExprArithmAdd< e2> (. e = Expression(op, {e, e2});.) ]. ExprArithmMul< Expression& e> (. Operator op; Expression e2; .) = ExprUpdate [ MulOp< op> ExprArithmMul< e2> (. e = Expression(op, {e, e2}); .) ]. ExprUpdate= (. Expression e2; .) ExprPostfix< e> [ colon ( IF(checkListIndex()) ListIndexLiteral | ListLiteral) (. e = Expression(Operator::UPDATE, {e, e2}); .) ]. ExprPostfix = Term [ (. e = Expression(Operator::INDEX, {e}); .) {lbrack CalleeParams rbrack } ]. Term< Expression& e> (. std::wstring name; e = Expression(); .) = (IF (checkParametersList()) Ident< name> (. e = Expression(Operator::CALL, {Atom(name)}); root->recognizeVariantConstructor(e); .) lparen [CalleeParams] rparen | IdentVR | ListLiteral | ListRangeLiteral | LoopDecl | IfDecl | SwitchDecl | IntrinsicDecl | SequenceDecl | number (. e = Expression(Atom(t->val)); .) | string (. e = Expression(Atom(t->val)); .) | "true" (. e = Expression(Atom(1)); e.bindType(TypePrimitive::Bool); .) | "false" (. e = Expression(Atom(0)); e.bindType(TypePrimitive::Bool); .) | "undef" (. e = Expression(Operator::UNDEF, {}); .) | '-' Term (. e = Expression(Operator::NEG, {e}); .) | lparen ExprTyped rparen ). ListLiteral = (. std::wstring key; Expression val; std::list> keys; e = Expression(Operator::LIST, {}); .) lcurbrack { ( IF(checkTokenAfterIdent(_assign)) Ident assign | (. key = L""; .) ) Expr (. keys.push_back(Atom(key)); e.operands.push_back(val); .) [comma] } rcurbrack (. e.addBindings(keys.begin(), keys.end()); .) . ListIndexLiteral = (. e = Expression(Operator::LIST_INDEX, {});Expression valE;.) lcurbrack { (. Expression idxE(Operator::LIST, {});.) lbrack CalleeParams rbrack assign Expr[comma] (. e.operands.push_back(idxE); e.operands.push_back(valE); .) } rcurbrack . ListRangeLiteral = (. Expression eFrom, eTo; .) lbrack Expr ".." Expr rbrack (. e = Expression(Operator::LIST_RANGE, {eFrom, eTo}); .) . CalleeParams = (. Expression e2; .) ExprTyped (. e.addArg(Expression(e2)); .) {comma ExprTyped (. e.addArg(Expression(e2)); .) }. AddOp< Operator& op> = (. op = Operator::ADD; .) ( '+' | '-' (. op = Operator::SUB; .) ). MulOp< Operator& op> = (. op = Operator::MUL; .) ( '*' | '/' (. op = Operator::DIV; .) | '%' (. op = Operator::MOD; .) ). 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} (lcurbrack {ANY} rcurbrack | '.'). END Xreate. diff --git a/scripts/containers/minmax.xreate b/scripts/containers/minmax.xreate index 8532993..a9478cb 100644 --- a/scripts/containers/minmax.xreate +++ b/scripts/containers/minmax.xreate @@ -1,282 +1,439 @@ El = type {idx:: int, val:: int}. PairT = type(X) {X, X}. Pair = type PairT(int). PairEl = type PairT(El). min = function(x:: int, y:: int):: int { if (x < y):: int { x } else { y } } max = function(x:: int, y:: int):: int { if (x > y):: int { x } else { y } } minEl = function(e1:: El, e2:: El):: El { if (e1["val"] < e2["val"]):: El {e1} else {e2} } maxEl = function(e1:: El, e2:: El):: El { if (e1["val"] > e2["val"]):: El {e1} else {e2} } minElIdx = function(x:: El, y:: El):: El { if (x["idx"] < y["idx"]):: El {x} else {y} } maxElIdx = function(x:: El, y:: El):: El { if (x["idx"] > y["idx"]):: El {x} else {y} } minLstEl = function(x:: El, y:: El):: El { if (x["val"] <= y["val"]):: El {x} else {y} } maxLstEl = function(x:: El, y:: El):: El { if (x["val"] >= y["val"]):: El {x} else {y} } +OptionalVal = type {flag:: bool, val:: int}. +OptionalEl = type {el:: El, exists:: bool}. + +getOptionalEl = function(elActual:: OptionalEl, elDefault::El):: El +{ + if (elActual["exists"])::El {elActual["el"]} else {elDefault} +} + +inRange = function(val::int, range::Pair):: bool +{ + val >= range[0] and val <= range[1] +} + fn-minmax1 = function:: {min:: int, max:: int} { arr = {25, 37, 12, 6, 5, 19, 3, 20}:: [int]. loop fold(arr->el:: int, {1000, 0}->state):: {min:: int, max:: int} { { min(el, state["min"]), max(el, state["max"]) }:: {min:: int, max:: int} } } fn-minmax2 = function:: int { arr = { {1, 72}, {3, 8}, {2, 5}, {3, 4}, {11, 1}, {6, 5}, {9, 2} } :: [{int, int}]. loop fold(arr->rect:: {int, int}, 1000->squareMin):: int { square = rect[0] * rect[1]:: int. min(square, squareMin) } } fn-minmax3 = function:: int { arr = { {1, 72}, {3, 8}, {2, 5}, {3, 4}, {11, 1}, {6, 5}, {9, 2} } :: [{int, int}]. loop fold(arr->rect:: {int, int}, 0->perMax):: int { per = 2 * (rect[0] + rect[1]):: int. max(per, perMax) } } fn-minmax4 = function:: int { arr = {25, 37, 12, 6, 5, 19, 3, 20}:: [int]. minInit = {0, 25}:: El. result = loop fold(arr->el:: int, {0, minInit}->state):: {idx:: int, minEl:: El} { elCur = {state["idx"], el}:: El. idxNext = state["idx"] + 1:: int. {idxNext, minEl(elCur, state["minEl"])}:: {idx:: int, minEl:: El} }. result["minEl", "idx"] } fn-minmax5 = function:: El { input = { {1, 72}, {3, 8}, {2, 5}, {3, 4}, {11, 1}, {6, 5}, {9, 2} } :: [{int, int}]. resultInit = {0, 0}:: El. result = loop fold(input->el:: Pair, {0, resultInit}->acc):: {idx:: int, max:: El} { density = el[0] / el[1] :: int. idxNext = acc["idx"] + 1:: int. elCur = {acc["idx"], density}:: El. {idxNext, maxEl(elCur, acc["max"])}:: {idx:: int, max:: El} }. result["max"] } fn-minmax6 = function:: Pair { arr = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]. init = {0, {{1000, 1000}, {0, 0}}}:: {int, PairEl}. result = loop fold(arr->val:: int, init->acc):: {int, PairEl} { el = {acc[0], val}:: El. idx = acc[0]+1 :: int. min = minEl(el, acc[1, 0]) :: El. max = maxLstEl(el, acc[1, 1]):: El. {idx, ({min, max}:: PairEl)}:: {int, PairEl} }. {result[1][0]["idx"], result[1][1]["idx"]} } fn-minmax7 = function:: Pair { arr = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]. init = {0, {{0, 0}, {1000, 1000}}}:: {int, PairEl}. result = loop fold(arr->val:: int, init->acc):: {int, PairEl} { el = {acc[0], val}:: El. idx = acc[0]+1 :: int. max = maxEl(el, acc[1, 0]) :: El. min = minLstEl(el, acc[1, 1]):: El. {idx, ({max, min}:: PairEl)}:: {int, PairEl} }. {result[1][0]["idx"], result[1][1]["idx"]} } fn-minmax8 = function:: Pair { input = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]. init = {0, {{1000, 1000}, {1000, 1000}}}:: {int, PairEl}. result = loop fold(input->val:: int, init->acc):: {int, PairEl} { el = {acc[0], val}:: El. idx = acc[0]+1 :: int. minF = minEl(el, acc[1, 0]) :: El. minL = minLstEl(el, acc[1, 1]):: El. {idx, {minF, minL}}:: {int, PairEl} }. {result[1, 0, "idx"], result[1, 1, "idx"]} } fn-minmax9 = function:: Pair { input = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]. init = {0, {{0, 0}, {0, 0}}}:: {int, PairEl}. result = loop fold(input->val:: int, init->acc):: {int, PairEl} { el = {acc[0], val}:: El. idx = acc[0]+1 :: int. maxF = maxEl(el, acc[1, 0]) :: El. maxL = maxLstEl(el, acc[1, 1]):: El. {idx, {maxF, maxL}}:: {int, PairEl} }. {result[1, 0, "idx"], result[1, 1, "idx"]} } fn-minmax10 = function:: int { input = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]. init = {0, {{1000, 1000}, {0, 0}}}:: {int, PairEl}. result = loop fold(input->val:: int, init->acc):: {int, PairEl} { el = {acc[0], val}:: El. idx = acc[0]+1 :: int. minF = minEl(el, acc[1, 0]) :: El. maxF = maxEl(el, acc[1, 1]):: El. {idx, {minF, maxF}}:: {int, PairEl} }. (minElIdx(result[1, 0], result[1, 1])::El)["idx"] } fn-minmax11 = function:: int { input = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]. ctxInit = {0, {{1000, 1000}, {0, 0}}}:: {int, PairEl}. result = loop fold(input-> val:: int, ctxInit->ctx):: {int, PairEl} { elCur = {ctx[0], val}:: El. elMinL = minLstEl(elCur, ctx[1, 0]):: El. elMaxL = maxLstEl(elCur, ctx[1, 1]):: El. {ctx[0]+1, {elMinL, elMaxL}}:: {int, PairEl} }. (maxElIdx(result[1, 0], result[1, 1])::El)["idx"] } fn-minmax12 = function:: int { input = {-8, 16, 3, -5, 2, -11, -905, -54}:: [int]. result = loop fold(input->val:: int, {1000, false} -> state):: {minPstv:: int, flagPstvFound:: bool} { if (val > 0):: int { {min(val, state["minPstv"]), true}:: {minPstv:: int, flagPstvFound:: bool} } else { state } }. if (result["flagPstvFound"])::int {result["minPstv"]} else { 0 } } -OptionalVal = type {flag:: bool, val:: int}. + fn-minmax13 = function::int { input = {-8, 16, 3, -5, 2, -11, -905, -54}:: [int]. result = loop fold(input->x:: int, {false, -1000} -> state):: OptionalVal { if (x % 2 == 1):: OptionalVal {{true, max(x, state["val"])}:: OptionalVal } else { state } }. result["val"] } -OptionalEl = type {el:: El, exists:: bool}. - fn-minmax14 = function:: El { input = { -8, 16, 3, -5, 2, -11, -905, -54 }:: [int]. threshold = 2:: int. result = loop fold (input -> x:: int, {0, {el = { 0, 1000 }, exists = false }} -> result):: {int , OptionalEl} { xEl = {result[0], x}:: El. if(x > threshold):: {int , OptionalEl} { { result[0] + 1, { el = minEl(xEl, result[1, "el"]), exists = true } }:: {int , OptionalEl} } else { result : {[0]= result[0] + 1} } }. if (result[1, "exists"]):: El { result[1, "el"] } else { {0, 0}:: El } } + +State15 = type {idx:: int, max:: OptionalEl}. +fn-minmax15 = function:: El +{ + input = { -8, 16, 3, -5, 2, -11, -905, -54 }:: [int]. + range = {2, 17}:: Pair. + + result = loop fold(input->val::int, {0, {el = {0, 0}, exists = false}}->state):: State15 + { + el = {state["idx"], val}:: El. + stateNew = state : {idx = state["idx"] + 1}:: State15. + + if (inRange(val, range)):: State15 + { + stateNew : {max = ({maxEl(el, state["max", "el"]), true}:: OptionalEl)} + } + else + { + stateNew + } + }. + + getOptionalEl(result["max"], {0, 0}::El) +} + +State19 = type {min:: int, length:: int}. +fn-minmax19 = function:: int +{ + input = { 18, 16, 2, 5, 2, 11, 905, 2 }:: [int]. + + result = loop fold(input->x:: int, {1000, 0}->state)::State19 + { + if(x < state["min"]):: State19 { {x, 1}:: State19 } + else + { + if (x == state["min"])::State19 { state: { length=state["length"] + 1 } } + else { state } + } + }. + + result["length"] +} + +State20 = type { + min:: int, + lenMin:: int, + max:: int, + lenMax:: int +}. + +fn-minmax20 = function:: int +{ + input = { 18, 16, 2, 5, 2, 11, 905, 2 }:: [int]. + + result = loop fold(input->x:: int, {1000, 0, 0, 0}->state)::State20 + { + stateA = if(x < state["min"]):: State20 { state : {min = x, lenMin = 1} } + else + { + if (x == state["min"])::State20 { state: { lenMin = state["lenMin"] + 1 } } + else { state } + }. + + if(x > stateA["max"]):: State20 { stateA : {max = x, lenMax = 1} } + else + { + if (x == state["max"])::State20 { stateA: { lenMax = stateA["lenMax"] + 1 } } + else { stateA } + } + }. + + result["lenMin"] + result["lenMax"] +} + +State21 = type {sum:: int, size:: int}. +fn-minmax21 = function:: int +{ + input = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}:: [int]. + + minmax = loop fold(input->x:: int, {1000, 0} ->minmax):: Pair + { + minmaxA = if (x < minmax[0])::Pair { minmax: {[0]=x} } else {minmax}. + if (x > minmax[1])::Pair {minmaxA : {[1] = x}} else {minmaxA} + }. + + result = loop fold(input->x:: int, {0, 0}->result):: State21 + { + if (x != minmax[0], x!= minmax[1]):: State21 + { { + sum = result["sum"] + x, + size = result["size"] + 1 + }:: State21} else {result} + }. + + result["sum"] / result["size"] +} + +min2 = function (val:: int, min:: Pair):: Pair +{ + if (val < min[0]):: Pair { {val, min[0]}::Pair } + else + { + if(val < min[1]):: Pair { {min[0], val}::Pair } + else { min } + } +} + +fn-minmax22 = function:: Pair +{ + input = {-5, 18, 63, -29, 11, 17, 96, 28, -14}:: [int]. + + loop fold(input->x:: int, {1000, 1000}->min):: Pair + { + min2(x, min):: Pair + } +} + +Triple = type {int, int, int}. + +max3 = function(x:: int, max:: Triple):: Triple +{ + if (x > max[0])::Triple { {x, max[0], max[1]}:: Triple } + else + { + if (x > max[1]):: Triple {{max[0], x, max[1]}::Triple} + else + { + if (x > max[2]):: Triple { max: {[2]=x} } + else { max } + } + } +} + +Tuple4 = type {int, int, int, int}. + +fn-minmax23 = function:: Tuple4 +{ + input = {-5, 18, 63, -29, 11, 17, 96, 28, -14}:: [int]. + + result = loop fold(input->x:: int, {-1000, -1000, -1000}->max):: Triple + { + max3(x, max):: Triple + }. + + {result[0], result[1], result[2], 0} +}