No OneTemporary

File Metadata

Created
Sun, Feb 15, 6:39 PM
diff --git a/cpp/Configurations.cmake b/cpp/Configurations.cmake
index 34eec0c..2c732b0 100644
--- a/cpp/Configurations.cmake
+++ b/cpp/Configurations.cmake
@@ -1,160 +1,161 @@
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
+ aux/kludges.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 fa29af4..807a633 100644
--- a/cpp/src/analysis/predefinedanns.cpp
+++ b/cpp/src/analysis/predefinedanns.cpp
@@ -1,79 +1,88 @@
-//
-// Created by pgess on 19/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: predefinedanns.cpp
+ * Author: pgess <v.melnychenko@xreate.org>
+ *
+ * Created on 19/03/2020
+ */
#include "analysis/predefinedanns.h"
#include "analysis/resources.h"
namespace xreate{ namespace analysis{
PredefinedAnns
PredefinedAnns::__instance = PredefinedAnns();
PredefinedAnns::PredefinedAnns(){
fnAnnsT = TypeAnnotation(TypeOperator::VARIANT, {});
exprAnnsT = TypeAnnotation(TypeOperator::VARIANT, {});
//Function annotations
fnAnnsT.__operands.push_back(TypePrimitive::Invalid);
fnAnnsT.fields.push_back(FN_ENTRY_PREDICATE);
fnAnnsT.__operands.push_back(TypePrimitive::Invalid);
fnAnnsT.fields.push_back(FN_EXTERIOR_PREDICATE);
//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,
- TypeAnnotation::alias("hintsContT")
+ TypeAnnotation(TypeOperator::REF, {TypeAnnotation::alias("hintsContT")}),
+ TypePrimitive ::Invalid
});
- hintsContT.fields.push_back("csize");
- hintsContT.fields.push_back("fly");
+ hintsContT.fields.push_back(CONTAINERS_IMPL_ARRAY_PREDICATE);
+ hintsContT.fields.push_back(CONTAINERS_IMPL_FLY_PREDICATE);
+ hintsContT.fields.push_back(CONTAINERS_IMPL_RANGE_PREDICATE);
}
void
PredefinedAnns::registerVariants(std::map<std::string, std::pair<TypeAnnotation, int>> &__registry) const{
//annotation; type; variant id;
__registry = {
//Functions:
{FN_ENTRY_PREDICATE, {fnAnnsT, (unsigned) FnAnnotations::ENTRY}},
{FN_EXTERIOR_PREDICATE, {fnAnnsT, (unsigned) FnAnnotations::EXTERIOR}},
//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}},
+ {CONTAINERS_IMPL_ARRAY_PREDICATE, {hintsContT, (unsigned) ContHints::ARRAY}},
+ {CONTAINERS_IMPL_FLY_PREDICATE, {hintsContT, (unsigned) ContHints::FLY}},
+ {CONTAINERS_IMPL_RANGE_PREDICATE, {hintsContT, (unsigned) ContHints::RANGE}},
};
}
void
PredefinedAnns::registerAliases(std::map<std::string, TypeAnnotation> &__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 687bd6f..2cbad67 100644
--- a/cpp/src/analysis/predefinedanns.h
+++ b/cpp/src/analysis/predefinedanns.h
@@ -1,49 +1,55 @@
-//
-// Created by pgess on 19/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: predefinedanns.h
+ * Author: pgess <v.melnychenko@xreate.org>
+ *
+ * Created 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, EXTERIOR
};
enum class ExprAnnotations{
I12N
};
enum class I12ModeTag{
ON, OFF
};
enum class IntHints{
SIZE
};
enum class ContHints{
- ARRAY, FLY
+ ARRAY, FLY, RANGE
};
TypeAnnotation fnAnnsT;
TypeAnnotation exprAnnsT;
TypeAnnotation hintsIntT;
TypeAnnotation hintsContT;
//Interpretation
TypeAnnotation i12nModeT;
PredefinedAnns();
static const PredefinedAnns& instance(){ return __instance; }
void registerVariants(std::map<std::string, std::pair<TypeAnnotation, int>> &__registry) const;
void registerAliases(std::map<std::string, TypeAnnotation>& __registry) const;
private:
static PredefinedAnns __instance;
};
}} // end of xreate::analysis
#endif //XREATE_PREDEFINEDANNS_H
diff --git a/cpp/src/analysis/resources.cpp b/cpp/src/analysis/resources.cpp
index 042046e..69c22cd 100644
--- a/cpp/src/analysis/resources.cpp
+++ b/cpp/src/analysis/resources.cpp
@@ -1,25 +1,27 @@
#include "analysis/resources.h"
namespace xreate{namespace analysis{
const char *VAR_ANN_PREDICATE_TPL = "bind(%1%, %2%)";
const char *VAR_ANN_PREDICATE = "bind";
const char *SCOPE_ANN_PREDICATE_TPL = "bind_scope(%1%, %2%)";
const char *SCOPE_ANN_PREDICATE = "bind_scope";
const char *FUNCTION_ANN_PREDICATE_TPL = "bind_func(\"%1%\", %2%)";
const char *FUNCTION_ANN_PREDICATE = "bind_func";
const char *TRANSCEND_PASS_SECTION = "% == STATIC ANALYSIS: ANNOTATIONS ==";
const char *FUNCTION_PREDICATE_TPL = "function(\"%1%\")";
const char *SITE_SYMBOL_PREDICATE = "s";
const char *SITE_ANON_PREDICATE = "a";
const char *DEMAND_FORMAL_PREDICATE = "func_demand";
const char *DEMAND_ACTUAL_PREDICATE = "func_supply";
const char *FN_ENTRY_PREDICATE = "entry";
const char *FN_EXTERIOR_PREDICATE = "exterior";
const char *POLYMORPH_SUPPLY_PREDICATE = "func_supply_guard";
+extern const char *CONTAINERS_IMPL_ARRAY_PREDICATE = "csize";
+extern const char *CONTAINERS_IMPL_FLY_PREDICATE = "fly";
+extern const char *CONTAINERS_IMPL_RANGE_PREDICATE = "range";
+
const char *CONTAINERS_ID_IMPL_PREDICATE = "containers_impl";
const char *CONTAINERS_ID_LINKLIST_PREDICATE = "linkedlist";
-const char *CONTAINERS_IMPL_SOLID_PREDICATE = "solid";
-const char *CONTAINERS_IMPL_ONTHEFLY_PREDICATE = "onthefly";
}}
\ No newline at end of file
diff --git a/cpp/src/analysis/resources.h b/cpp/src/analysis/resources.h
index b0ec50d..3d4a9df 100644
--- a/cpp/src/analysis/resources.h
+++ b/cpp/src/analysis/resources.h
@@ -1,38 +1,40 @@
//
// Created by pgess on 15/01/2020.
//
#ifndef XREATE_RESOURCES_H
#define XREATE_RESOURCES_H
#include "transcendlayer.h"
#include <tuple>
#include <string>
namespace xreate{namespace analysis {
extern const char *FUNCTION_PREDICATE_TPL;
extern const char *FUNCTION_ANN_PREDICATE_TPL;
extern const char *FUNCTION_ANN_PREDICATE;
extern const char *SCOPE_ANN_PREDICATE_TPL;
extern const char *SCOPE_ANN_PREDICATE;
extern const char *VAR_ANN_PREDICATE_TPL;
extern const char *VAR_ANN_PREDICATE;
extern const char *TRANSCEND_PASS_SECTION;
extern const char *SITE_SYMBOL_PREDICATE;
extern const char *SITE_ANON_PREDICATE;
extern const char *DEMAND_FORMAL_PREDICATE;
extern const char *DEMAND_ACTUAL_PREDICATE;
extern const char *POLYMORPH_SUPPLY_PREDICATE;
extern const char *FN_ENTRY_PREDICATE;
extern const char *FN_EXTERIOR_PREDICATE;
+extern const char *CONTAINERS_IMPL_ARRAY_PREDICATE;
+extern const char *CONTAINERS_IMPL_FLY_PREDICATE;
+extern const char *CONTAINERS_IMPL_RANGE_PREDICATE;
+
extern const char *CONTAINERS_ID_IMPL_PREDICATE;
extern const char *CONTAINERS_ID_LINKLIST_PREDICATE;
-extern const char *CONTAINERS_IMPL_SOLID_PREDICATE;
-extern const char *CONTAINERS_IMPL_ONTHEFLY_PREDICATE;
typedef std::tuple<std::string, std::string, std::string> DEMAND_FORMAL_SCHEME; //fn, key, type-alias
typedef std::tuple<xreate::ASTSitePacked, std::string, Gringo::Symbol> DEMAND_ACTUAL_SCHEME; //fn, key, type-alias
typedef std::tuple<xreate::ASTSitePacked, Gringo::Symbol, std::string> POLYMORPH_SUPPLY_SCHEME; //site, data, type-variant
}}
#endif //XREATE_RESOURCES_H
diff --git a/cpp/src/analysis/typehints.cpp b/cpp/src/analysis/typehints.cpp
index f504d2d..3bba26d 100644
--- a/cpp/src/analysis/typehints.cpp
+++ b/cpp/src/analysis/typehints.cpp
@@ -1,68 +1,74 @@
-//
-// Created by pgess on 24/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: typehints.cpp
+ * Author: pgess <v.melnychenko@xreate.org>
+ *
+ * Created on 24/03/2020
+ */
#include "analysis/typehints.h"
#include "analysis/predefinedanns.h"
#include "analysis/utils.h"
#include "aux/expressions.h"
namespace xreate{namespace typehints{
namespace impl {
template<class Hint>
inline Hint getHint(const Expression& e, const Hint& def, unsigned annId, const ExpandedType& hintT){
const std::list<Expression>& hintsL = getAnnotations(e);
auto predefined = analysis::PredefinedAnns::instance();
const Expression& hintActual = analysis::findAnnById(annId, hintT, hintsL);
if (!hintActual.isValid()){
return def;
}
return parse<Hint>(hintActual);
}
}
template<> IntBits
parse(const Expression& e){
return {(unsigned) e.operands.at(0).getValueDouble()};
}
template<> ArrayHint
parse(const Expression& e){
return {(unsigned) e.operands.at(0).getValueDouble()};
}
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<IntBits>(e, def,
(unsigned) analysis::PredefinedAnns::IntHints::SIZE,
ExpandedType(predefined.hintsIntT)
);
}
template<> ArrayHint
find(const Expression& e, const ArrayHint& def){
auto predefined = analysis::PredefinedAnns::instance();
return impl::getHint<ArrayHint>(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<FlyHint>(e, def,
(unsigned) analysis::PredefinedAnns::ContHints::FLY,
ExpandedType(predefined.hintsContT));
}
}}
\ No newline at end of file
diff --git a/cpp/src/analysis/utils.cpp b/cpp/src/analysis/utils.cpp
index f932768..ccf9015 100644
--- a/cpp/src/analysis/utils.cpp
+++ b/cpp/src/analysis/utils.cpp
@@ -1,350 +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 <v.melnychenko@xreate.org>
*/
/**
* \file src/analysis/utils.h
* \brief Various reasoning related utilities
*/
#include "utils.h"
#include "resources.h"
+#include "aux/kludges.h"
#include <boost/format.hpp>
using namespace std;
namespace xreate { namespace analysis {
typedef vector<int> InstancePacked;
std::list<Expression>
generateAllInstancesInDomain2(const ExpandedType& domainT) {
if(!domainT->isValid()) {
return {Expression()};
}
assert(domainT->__operator == TypeOperator::VARIANT);
std::list<Expression> 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<Expression> 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<Gringo::Symbol>& 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<Gringo::Symbol> 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<Gringo::Symbol>& 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<string, list < Gringo::Symbol>> 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<Gringo::Symbol> symbols;
for(auto row : model) {
symbols.push_back(row.second);
}
return ExpandedType(collapseFnGroup(symbols));
}
ASTSitePacked
getSite(const Expression& e, TranscendLayer* transcend){
Attachments::put<ExprId_A>(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<ASTSitePacked>(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<Number_t>(atom.num()));
}
case TypePrimitive::String:
{
return Expression(Atom<String_t>(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<string, int> 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<Expression> 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.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<std::string>& srcList){
Expression dstE(Operator::LIST, {});
for(const string op: srcList){
dstE.operands.push_back(Atom<String_t>(string(op)));
}
return dstE;
}
Expression
findAnnById(unsigned annId, const ExpandedType& annT, const std::list<Expression>& 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<Expression> tagsL;
- for(const auto& tag: expr.tags){tagsL.push_back(tag.second);}
+ std::list<Expression> tagsL = kludges::getAnnotations(expr);
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/ast.cpp b/cpp/src/ast.cpp
index d53ea10..483b048 100644
--- a/cpp/src/ast.cpp
+++ b/cpp/src/ast.cpp
@@ -1,964 +1,966 @@
/* 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 <v.melnychenko@xreate.org>
* File: ast.cpp
*/
#include "ast.h"
#include "analysis/typeinference.h"
#include "analysis/predefinedanns.h"
#ifdef XREATE_ENABLE_EXTERN
#include "ExternLayer.h"
#endif
#include <stdexcept>
#include <iostream>
//TODO BDecl. forbid multiple body declaration (ExprTyped)
namespace std {
std::size_t
hash<xreate::ScopedSymbol>::operator()(xreate::ScopedSymbol const& s) const {
return s.id ^ (s.version << 2);
}
bool
equal_to<xreate::ScopedSymbol>::operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const {
return __x.id == __y.id && __x.version == __y.version;
}
size_t
hash<xreate::Symbol>::operator()(xreate::Symbol const& s) const {
return hash<xreate::ScopedSymbol>()(s.identifier) ^ ((long int) s.scope << 1);
}
bool
equal_to<xreate::Symbol>::operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const {
return __x == __y;
};
}
using namespace std;
namespace xreate {
Atom<Identifier_t>::Atom(const std::wstring& value) {
__value = wstring_to_utf8(value);
}
Atom<Identifier_t>::Atom(std::string && name) : __value(name) {
}
const std::string&
Atom<Identifier_t>::get() const {
return __value;
}
Atom<Number_t>::Atom(wchar_t* value) {
//DEBT reconsider number literal recognition
__value = wcstol(value, 0, 10);
}
Atom<Number_t>::Atom(int value)
: __value(value) {
}
double
Atom<Number_t>::get()const {
return __value;
}
Atom<String_t>::Atom(const std::wstring& value) {
assert(value.size() >= 2);
__value = wstring_to_utf8(value.substr(1, value.size() - 2));
}
Atom<String_t>::Atom(std::string && name) : __value(name) {}
const std::string&
Atom<String_t>::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<std::string> trace,
const std::map<std::string, TypeAnnotation>& scope = std::map<std::string, TypeAnnotation>())
: __ast(ast), __scope(scope), __trace(trace), __parent(parent) {}
ExpandedType
operator()(const TypeAnnotation &t, const std::vector<TypeAnnotation> &args = std::vector<TypeAnnotation>()) {
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<TypeAnnotation> elTy = this->operator()(t.__operands.at(0));
return ExpandedType(TypeAnnotation(TypeOperator::ARRAY, {elTy.get()}));
}
case TypeOperator::RECORD:
{
std::vector<TypeAnnotation>&& packOperands = expandOperands(t.__operands);
auto typNew = TypeAnnotation(TypeOperator::RECORD, move(packOperands));
typNew.fields = t.fields;
return ExpandedType(move(typNew));
};
case TypeOperator::VARIANT:
{
std::vector<TypeAnnotation>&& 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<TypeAnnotation>&& 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).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<std::string, TypeAnnotation> __scope;
std::set<std::string> __trace;
TypeResolver* __parent;
std::vector<TypeAnnotation>
expandOperands(const std::vector<TypeAnnotation>& operands) {
std::vector<TypeAnnotation> pack;
pack.reserve(operands.size());
std::transform(operands.begin(), operands.end(), std::inserter(pack, pack.end()),
[this](const TypeAnnotation & 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<TypeAnnotation> operands)
: __operator(op), __operands(operands) {
}
TypeAnnotation::TypeAnnotation(TypeOperator op, std::vector<TypeAnnotation>&& 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
-TypeAnnotation::alias(const std::string& alias)
-{
+TypeAnnotation::alias(const std::string& alias) {
+ TypeAnnotation aliasT(TypeOperator::ALIAS, {});
+ aliasT.__valueCustom = alias;
+ return aliasT;
}
void
TypeAnnotation::addBindings(std::vector<Atom<Identifier_t>>&& params) {
bindings.reserve(bindings.size() + params.size());
std::transform(params.begin(), params.end(), std::inserter(bindings, bindings.end()),
[](const Atom<Identifier_t>& ident) {
return ident.get(); });
}
void
TypeAnnotation::addFields(std::vector<Atom<Identifier_t>>&& listFields) {
fields.reserve(fields.size() + listFields.size());
std::transform(listFields.begin(), listFields.end(), std::inserter(fields, fields.end()),
[](const Atom<Identifier_t>& ident) {
return ident.get(); });
}
unsigned int Expression::nextVacantId = 0;
Expression::Expression(const Atom<Number_t>& number)
: Expression() {
__state = NUMBER;
op = Operator::INVALID;
__valueD = number.get();
}
Expression::Expression(const Atom<String_t>& a)
: Expression() {
__state = STRING;
op = Operator::INVALID;
__valueS = a.get();
}
Expression::Expression(const Atom<Identifier_t> &ident)
: Expression() {
__state = IDENT;
op = Operator::INVALID;
__valueS = ident.get();
}
Expression::Expression(const Operator &oprt, std::initializer_list<Expression> 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<Expression> 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<Atom<Identifier_t>> 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>&
Expression::getOperands() const {
return operands;
}
double
Expression::getValueDouble() const {
return __valueD;
}
const std::string&
Expression::getValueString() const {
return __valueS;
}
void
Expression::setValue(const Atom<Identifier_t>&& 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<std::string, IntrinsicFn>
AST::__registryIntrinsics = {};
AST::AST() {
Attachments::init<versions::VariableVersion>();
Attachments::init<IdentifierSymbol>();
Attachments::init<ExprAlias_A>();
Attachments::init<TypeInferred>();
Attachments::init<ExprId_A>();
initIntrinsics();
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<Identifier_t> 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 = "main";
return name;
}
ManagedPtr<Function>
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<Function>(range.first->second, &this->__functions);
}
std::list<ManagedFnPtr>
AST::getAllFunctions() const {
const size_t size = __functions.size();
std::list<ManagedFnPtr> result;
for (size_t i = 0; i < size; ++i) {
result.push_back(ManagedFnPtr(i, &this->__functions));
}
return result;
}
//TASK select default specializations
std::list<ManagedFnPtr>
AST::getFnSpecializations(const std::string& fnName) const {
auto functions = __dictFunctions.equal_range(fnName);
std::list<ManagedFnPtr> result;
std::transform(functions.first, functions.second, inserter(result, result.end()),
[this](auto f) {
return ManagedFnPtr(f.second, &this->__functions);
});
return result;
}
template<>
ManagedPtr<Function>
AST::begin<Function>() {
return ManagedPtr<Function>(0, &this->__functions);
}
template<>
ManagedPtr<CodeScope>
AST::begin<CodeScope>() {
return ManagedPtr<CodeScope>(0, &this->__scopes);
}
template<>
ManagedPtr<MetaRuleAbstract>
AST::begin<MetaRuleAbstract>() {
return ManagedPtr<MetaRuleAbstract>(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<Number_t>
AST::recognizeVariantConstructor(Atom<Identifier_t> ident) {
std::string variant = ident.get();
assert(__registryVariants.count(variant) && "Can't recognize variant constructor");
auto record = __registryVariants.at(variant);
return Atom<Number_t>(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<xreate::AST*> (this);
}
void
AST::initIntrinsics(){
if (__registryIntrinsics.size()) return;
__registryIntrinsics = {
{"array_init", IntrinsicFn::ARR_INIT},
{"rec_fields", IntrinsicFn::REC_FIELDS}
};
}
} } //namespace details::incomplete
Expanded<TypeAnnotation>
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<TypeAnnotation>
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<Identifier_t>& 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<std::string, Expression>&
Function::getTags() const {
return __tags;
}
CodeScope*
Function::getEntryScope() const {
return __entry;
}
void
Function::addBinding(Atom <Identifier_t>&& 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<versions::VariableVersion>(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<versions::VariableVersion>(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<CodeScope*> (this);
Attachments::put<IdentifierSymbol>(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<Identifier_t> &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<String_t>&& 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; i<this->operands.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<ExprAlias_A>(id)){
const Symbol& siteS = Attachments::get<ExprAlias_A>(id);
return CodeScope::getDefinition(siteS, true);
}
return Attachments::get<ExprId_A>(id);
}
} //end of namespace xreate
diff --git a/cpp/src/aux/kludges.cpp b/cpp/src/aux/kludges.cpp
new file mode 100644
index 0000000..9b297b1
--- /dev/null
+++ b/cpp/src/aux/kludges.cpp
@@ -0,0 +1,32 @@
+/* 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: kludges.cpp
+ * Author: pgess <v.melnychenko@xreate.org>
+ *
+ * Created on 25/04/2020
+ */
+
+#include "aux/kludges.h"
+#include "aux/expressions.h"
+
+namespace xreate { namespace kludges{
+std::list <Expression>
+getAnnotations(const Expression &e) {
+ if (e.tags.size()){
+ return xreate::getAnnotations(e);
+ }
+
+ if (e.__state == Expression::IDENT){
+ Symbol s = Attachments::get<IdentifierSymbol>(e);
+ Expression e2 = CodeScope::getDefinition(s, true);
+ return kludges::getAnnotations(e2);
+ }
+
+ return {};
+}
+}} // end of xreate::kludges
+
+
+
diff --git a/cpp/src/aux/kludges.h b/cpp/src/aux/kludges.h
new file mode 100644
index 0000000..2bf69e0
--- /dev/null
+++ b/cpp/src/aux/kludges.h
@@ -0,0 +1,26 @@
+/* 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: kludges.h
+ * Author: pgess
+ *
+ * Created on 25/04/2020
+ */
+
+/**
+ * \brief Pile of quick'n'dirty solutons.
+ * See to keep as little functionality as possible in here.
+ */
+#ifndef XREATE_KLUDGES_H
+#define XREATE_KLUDGES_H
+
+#include "ast.h"
+
+namespace xreate { namespace kludges{
+
+std::list <Expression>
+getAnnotations(const Expression &e);
+
+}} //end of xreate::kludges
+#endif //XREATE_KLUDGES_H
diff --git a/cpp/src/compilation/containers.cpp b/cpp/src/compilation/containers.cpp
index c5f5438..f0882b2 100644
--- a/cpp/src/compilation/containers.cpp
+++ b/cpp/src/compilation/containers.cpp
@@ -1,287 +1,368 @@
/* 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 <v.melnychenko@xreate.org>
*/
/**
* \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;
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<IdentifierSymbol>(aggrE);
aggr2E = CodeScope::getDefinition(aggrS);
} else {
aggr2E = aggrE;
}
switch(aggr2E.op){
case Operator::LIST:{
typehints::ArrayHint aggrHint = typehints::find(
aggr2E, typehints::ArrayHint{aggr2E.operands.size()}
);
return new ArrayIR(aggrT, aggrHint, context);
}
default:
typehints::ArrayHint aggrHint = typehints::find(
aggr2E, typehints::ArrayHint{0}
);
assert(aggrHint.size != 0);
return new ArrayIR(aggrT, aggrHint, context);
}
assert(false);
return nullptr;
}
llvm::Type*
IContainersIR::getRawType(const Expression& aggrE, const ExpandedType& aggrT, LLVMLayer* llvm){
auto manPredefined = analysis::PredefinedAnns::instance();
const Expression& hintE = analysis::findAnnByType(aggrE, ExpandedType(manPredefined.hintsContT), llvm->ast);
assert(hintE.isValid());
return getRawTypeByHint(hintE, aggrT, llvm);
}
llvm::Type*
IContainersIR::getRawTypeByHint(const Expression& hintE, const ExpandedType& aggrT, LLVMLayer* llvm) {
ImplementationType hintImpl = (ImplementationType ) hintE.getValueDouble();
switch (hintImpl){
case SOLID: {
typehints::ArrayHint hint = typehints::parse<typehints::ArrayHint>(hintE);
return ArrayIR::getRawType(aggrT, hint, llvm);
}
case ON_THE_FLY:{
typehints::FlyHint hint = typehints::parse<typehints::FlyHint>(hintE);
return FlyIR::getRawType(aggrT, hint, llvm);
}
- default: break;
+ case RANGE: {
+ return RangeIR::getRawType(aggrT, llvm);
+ }
}
assert(false);
return nullptr;
}
llvm::Value *
RecordIR::init(llvm::StructType *tyAggr){
return llvm::UndefValue::get(tyAggr);
}
llvm::Value*
RecordIR::init(std::forward_list<llvm::Type*> fields){
std::vector<llvm::Type*> fieldsVec(fields.begin(), fields.end());
llvm::ArrayRef<llvm::Type *> 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){
interpretation::InterpretationScope *scopeI12n =
__context.pass->targetInterpretation->transformContext(__context);
TypesHelper helper(__context.pass->man->llvm);
const auto &fields = helper.getRecordFields(aggrT);
std::map<std::string, size_t> 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;
}
llvm::Value*
-FlyIR::create(llvm::Value* sourceRaw, CodeScope* body, const std::string& hintAlias){
+FlyIR::init(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::Type*
FlyIR::getRawType(const ExpandedType& aggrT, const typehints::FlyHint& hint, LLVMLayer* llvm){
assert(aggrT->__operator == TypeOperator::ARRAY);
TypesHelper types(llvm);
llvm::Type* sourceTRaw = IContainersIR::getRawTypeByHint(hint.hintSrc, aggrT, llvm);
llvm::Type* elTRaw = llvm->toLLVMType(ExpandedType(aggrT->__operands.at(0)));
llvm::Type* resultTRaw = types.getPreferredIntTy();
llvm::Type* fnTnsfTRaw = llvm::FunctionType::get(resultTRaw, llvm::ArrayRef<llvm::Type*>(elTRaw), false);
std::vector<llvm::Type*> fieldsVec = {
sourceTRaw,
fnTnsfTRaw->getPointerTo()
};
llvm::ArrayRef<llvm::Type *> fieldsArr(fieldsVec);
llvm::StructType* resultTR = llvm::StructType::get(llvm->llvmContext, fieldsArr, false);
return resultTR;
}
llvm::Value*
FlyIR::getTransformFn(llvm::Value* aggrRaw){
LLVMLayer* llvm = __context.pass->man->llvm;
llvm::Value* fnRaw = llvm->irBuilder.CreateExtractValue(aggrRaw, llvm::ArrayRef<unsigned>{1});
return fnRaw;
}
llvm::Value*
FlyIR::getSourceAggr(llvm::Value* aggrRaw){
LLVMLayer* llvm = __context.pass->man->llvm;
return llvm->irBuilder.CreateExtractValue(aggrRaw, llvm::ArrayRef<unsigned>{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);
+ return init(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<typehints::ArrayHint>(hintE), context);
return new FwdIteratorIR<SOLID>(compiler);
}
case ON_THE_FLY:{
return new FwdIteratorIR<ON_THE_FLY>(typehints::parse<typehints::FlyHint>(hintE), aggrT, context);
}
+ case RANGE: {
+ return new FwdIteratorIR<RANGE>(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<ON_THE_FLY>::begin() {
+FwdIteratorIR<ON_THE_FLY>::begin(llvm::Value* aggrRaw) {
std::unique_ptr<IFwdIteratorIR> itSrcIR(IFwdIteratorIR::createByHint(__hint.hintSrc, __aggrT, __context));
- return itSrcIR->begin();
+ FlyIR compilerFly(__hint, __context);
+ llvm::Value* aggrSrcRaw = compilerFly.getSourceAggr(aggrRaw);
+
+ return itSrcIR->begin(aggrSrcRaw);
}
llvm::Value*
-FwdIteratorIR<ON_THE_FLY>::end() {
+FwdIteratorIR<ON_THE_FLY>::end(llvm::Value* aggrRaw) {
std::unique_ptr<IFwdIteratorIR> itSrcIR(IFwdIteratorIR::createByHint(__hint.hintSrc, __aggrT, __context));
- return itSrcIR->end();
+ FlyIR compilerFly(__hint, __context);
+ llvm::Value* aggrSrcRaw = compilerFly.getSourceAggr(aggrRaw);
+
+ return itSrcIR->end(aggrSrcRaw);
}
llvm::Value*
FwdIteratorIR<ON_THE_FLY>::advance(llvm::Value* idxRaw, const std::string& hintAlias){
std::unique_ptr<IFwdIteratorIR> itSrcIR(IFwdIteratorIR::createByHint(__hint.hintSrc, __aggrT, __context));
return itSrcIR->advance(idxRaw, hintAlias);
}
llvm::Value*
FwdIteratorIR<ON_THE_FLY>::get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintAlias){
std::unique_ptr<IFwdIteratorIR> 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<llvm::PointerType>(fnTnsfRaw->getType())->getElementType();
llvm::FunctionType* fnTnsfTRaw = llvm::cast<llvm::FunctionType>(fnTnsfTRawRaw);
compilation::BruteFnInvocation fnTnsfInvoc(fnTnsfRaw, fnTnsfTRaw, __context.pass->man->llvm);
return fnTnsfInvoc({valueSrcRaw}, hintAlias);
}
+llvm::Value*
+RangeIR::init(const Expression& aggrE, const ExpandedType& aggrT, const std::string& hintAlias){
+ assert(aggrE.op == Operator::LIST_RANGE);
+ assert(aggrE.operands.size()==2);
+
+ RecordIR recordIR(__context);
+ LLVMLayer* llvm = __context.pass->man->llvm;
+
+ llvm::Value* aggrRaw = recordIR.init(getRawType(aggrT, llvm));
+ llvm::Value* valueFromRaw = __context.scope->process(aggrE.operands.at(0));
+ llvm::Value* valueToRaw = __context.scope->process(aggrE.operands.at(1));
+ aggrRaw = llvm->irBuilder.CreateInsertValue(aggrRaw, valueFromRaw, 0);
+ aggrRaw = llvm->irBuilder.CreateInsertValue(aggrRaw, valueToRaw, 1);
+
+ return aggrRaw;
+}
+
+llvm::Value*
+RangeIR::getValueFrom(llvm::Value* aggrRaw){
+ LLVMLayer* llvm = __context.pass->man->llvm;
+ return llvm->irBuilder.CreateExtractValue(aggrRaw, llvm::ArrayRef<unsigned>{0});
+}
+
+llvm::Value*
+RangeIR::getValueTo(llvm::Value* aggrRaw){
+ LLVMLayer* llvm = __context.pass->man->llvm;
+ return llvm->irBuilder.CreateExtractValue(aggrRaw, llvm::ArrayRef<unsigned>{1});
+}
+
+llvm::StructType*
+RangeIR::getRawType(const ExpandedType& aggrT, LLVMLayer* llvm){
+ assert(aggrT->__operator == TypeOperator::ARRAY);
+
+ ExpandedType elT(aggrT->__operands.at(0));
+ llvm::Type* elRawT = llvm->toLLVMType(elT);
+
+ std::vector<llvm::Type*> fieldsVec = {elRawT, elRawT};
+ llvm::ArrayRef<llvm::Type *> fieldsArr(fieldsVec);
+ llvm::StructType* rangeRawT = llvm::StructType::get(llvm->llvmContext, fieldsArr, false);
+
+ return rangeRawT;
+}
+
+llvm::Value*
+FwdIteratorIR<RANGE>::begin(llvm::Value* aggrRaw){
+ RangeIR compiler(__context);
+ return compiler.getValueFrom(aggrRaw);
+}
+
+llvm::Value*
+FwdIteratorIR<RANGE>::end(llvm::Value* aggrRaw){
+ RangeIR compiler(__context);
+ return compiler.getValueTo(aggrRaw);
+}
+
+llvm::Value*
+FwdIteratorIR<RANGE>::get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintAlias){
+ return idxRaw;
+}
+
+llvm::Value*
+FwdIteratorIR<RANGE>::advance(llvm::Value* idxRaw, const std::string& hintAlias) {
+ LLVMLayer* llvm = __context.pass->man->llvm;
+ TypesHelper types(llvm);
+ llvm::Type* intT = types.getPreferredIntTy();
+
+ return llvm->irBuilder.CreateAdd(idxRaw, llvm::ConstantInt::get(intT, 1), hintAlias);
+}
+
}} //end of xreate::containers
diff --git a/cpp/src/compilation/containers.h b/cpp/src/compilation/containers.h
index 6ec9f12..40d73b9 100644
--- a/cpp/src/compilation/containers.h
+++ b/cpp/src/compilation/containers.h
@@ -1,111 +1,140 @@
/* 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 <v.melnychenko@xreate.org>
*/
#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);
static llvm::Type* getRawType(const Expression& aggrE, const ExpandedType& aggrT, LLVMLayer* llvm);
static llvm::Type* getRawTypeByHint(const Expression& hintE, const ExpandedType& aggrT, LLVMLayer* llvm);
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<llvm::Type*> 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);
- static llvm::Type *getRawType(const ExpandedType& aggrT, const typehints::FlyHint& hint, LLVMLayer* llvm);
-
-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* begin(llvm::Value* aggrRaw) = 0;
+ virtual llvm::Value* end(llvm::Value* aggrRaw) = 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<ImplementationType I>
class FwdIteratorIR;
+class FlyIR{
+public:
+ FlyIR(typehints::FlyHint hint, compilation::Context context);
+
+ llvm::Value* init(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);
+ static llvm::Type *getRawType(const ExpandedType& aggrT, const typehints::FlyHint& hint, LLVMLayer* llvm);
+
+private:
+ typehints::FlyHint __hint;
+ compilation::Context __context;
+};
/** \brief The lazy container implementation.
*
* Represents computation on the fly.
* \sa xreate::containers::IFwdIteratorIR, \sa xreate::containers::Query
*/
template<>
class FwdIteratorIR<ON_THE_FLY> : public IFwdIteratorIR {
public:
FwdIteratorIR<ON_THE_FLY>(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* begin(llvm::Value* aggrRaw) override;
+ virtual llvm::Value* end(llvm::Value* aggrRaw) 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;
};
-}}
+
+class RangeIR{
+public:
+ RangeIR(const compilation::Context& ctx): __context(ctx){}
+ llvm::Value* getValueFrom(llvm::Value* aggrRaw);
+ llvm::Value* getValueTo(llvm::Value* aggrRaw);
+ static llvm::StructType* getRawType(const ExpandedType& aggrT, LLVMLayer* llvm);
+ llvm::Value* init(const Expression& aggrE, const ExpandedType& aggrT, const std::string& hintAlias="");
+
+
+private:
+ compilation::Context __context;
+};
+
+template<>
+class FwdIteratorIR<RANGE>: public IFwdIteratorIR {
+public:
+ FwdIteratorIR<RANGE>(compilation::Context ctx): __context(ctx){}
+
+ virtual llvm::Value* begin(llvm::Value* aggrRaw) override;
+ virtual llvm::Value* end(llvm::Value* aggrRaw) 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:
+ compilation::Context __context;
+};
+
+}} //end of xreate::containers
+
+
#endif //CODEINSTRUCTIONS_H
diff --git a/cpp/src/compilation/containers/arrays.cpp b/cpp/src/compilation/containers/arrays.cpp
index 713a374..b0c03f2 100644
--- a/cpp/src/compilation/containers/arrays.cpp
+++ b/cpp/src/compilation/containers/arrays.cpp
@@ -1,167 +1,167 @@
/* 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 <v.melnychenko@xreate.org>
*
* Created in March 2020.
*/
#include "compilation/containers/arrays.h"
#include "aux/expressions.h"
using namespace std;
using namespace llvm;
namespace xreate { namespace containers{
llvm::PointerType*
ArrayIR::getRawType(const ExpandedType& aggrT, const typehints::ArrayHint& hint, LLVMLayer* llvm){
assert(aggrT->__operator == TypeOperator::ARRAY);
assert(aggrT->__operands.size() == 1);
llvm::Type* elRawT = llvm->toLLVMType(ExpandedType(aggrT->__operands.at(0)));
return llvm::ArrayType::get(elRawT, hint.size)->getPointerTo();
}
llvm::Value*
ArrayIR::init(const string& hintAlias){
LLVMLayer* llvm = __context.pass->man->llvm;
TypesHelper helper(llvm);
llvm::PointerType* aggrRawT = getRawType(__aggrT, __hint, __context.pass->man->llvm);
//llvm::Value* aggrLengthRaw = ConstantInt::get(helper.getPreferredIntTy(), aggrInfo.size);
llvm::Value* aggrRaw = llvm->irBuilder.CreateAlloca(aggrRawT->getElementType(), 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::PointerType* aggrRawT = getRawType(__aggrT, __hint, __context.pass->man->llvm);
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->getElementType(), aggrRaw, ArrayRef<llvm::Value*>(std::vector<Value*>{idxZeroRaw, keyRaw}));
llvm->irBuilder.CreateStore(elRaw, elLoc) ;
}
return aggrRaw;
}
llvm::Value*
ArrayIR::get(llvm::Value* aggrRaw, std::vector<llvm::Value *> 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<llvm::Value *>(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<IdentifierSymbol>(expr.getOperands()[0]);
//
// ImplementationRec<SOLID> implIn = containers::Query::queryImplementation(symbolIn).extract<SOLID>(); // 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->getBruteScope(scopeLoop);
// scopeLoopUnit->bindArg(elIn, move(varEl));
// Value* elOut = scopeLoopUnit->compile();
// Value *pElOut = builder.CreateGEP(dataOut, ArrayRef<Value *>(std::vector<Value*>{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<SOLID>(*this);
}
llvm::Value *
-FwdIteratorIR<SOLID>::begin(){
+FwdIteratorIR<SOLID>::begin(llvm::Value* aggrRaw){
TypesHelper helper(__compiler.__context.pass->man->llvm);
llvm::IntegerType* intT = helper.getPreferredIntTy();
return llvm::ConstantInt::get(intT, 0);
}
llvm::Value *
-FwdIteratorIR<SOLID>::end(){
+FwdIteratorIR<SOLID>::end(llvm::Value* aggrRaw){
TypesHelper helper(__compiler.__context.pass->man->llvm);
llvm::IntegerType* intT = helper.getPreferredIntTy();
size_t size = __compiler.__hint.size;
return llvm::ConstantInt::get(intT, size);
}
llvm::Value *
FwdIteratorIR<SOLID>::get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintAlias){
return __compiler.get(aggrRaw, {idxRaw}, hintAlias);
}
llvm::Value *
FwdIteratorIR<SOLID>::advance(llvm::Value *idxRaw, const std::string &hintAlias){
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 5b378be..f8aa251 100644
--- a/cpp/src/compilation/containers/arrays.h
+++ b/cpp/src/compilation/containers/arrays.h
@@ -1,63 +1,63 @@
/* 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 <v.melnychenko@xreate.org>
*
* Created in March 2020.
*/
#ifndef XREATE_ARRAYSIR_H
#define XREATE_ARRAYSIR_H
#include "compilation/containers.h"
namespace xreate { namespace containers{
class IFwdIteratorIR;
/** \brief The contiguous container implementation.
*
* Represents contiguous in memory(array) implementation.
* \sa xreate::containers::IFwdIteratorIR, \sa xreate::containers::Query
*/
class ArrayIR : public IContainersIR{
friend class FwdIteratorIR<SOLID>;
public:
ArrayIR(const ExpandedType &aggrT, const typehints::ArrayHint &hints, const compilation::Context &context)
: __context(context), __aggrT(aggrT), __hint(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<llvm::Value *> idxL, const std::string &hintAlias);
static llvm::PointerType *getRawType(const ExpandedType& aggrT, const typehints::ArrayHint& hint, LLVMLayer* llvm);
/** \brief `loop map` statement compilation*/
llvm::Value* operatorMap(const Expression& expr, const std::string& hintAlias);
private:
compilation::Context __context;
ExpandedType __aggrT;
typehints::ArrayHint __hint;
};
template<>
class FwdIteratorIR<SOLID>: public IFwdIteratorIR {
public:
FwdIteratorIR(const ArrayIR& arraysIR): __compiler(arraysIR) {};
- virtual llvm::Value* begin() override;
- virtual llvm::Value* end() override;
+ virtual llvm::Value* begin(llvm::Value* aggrRaw) override;
+ virtual llvm::Value* end(llvm::Value* aggrRaw) 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 fc4653c..6eb5fc6 100644
--- a/cpp/src/compilation/control.cpp
+++ b/cpp/src/compilation/control.cpp
@@ -1,393 +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
+ * File: control.cpp
* Author: pgess <v.melnychenko@xreate.org>
*
* 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<llvm::IntegerType*> (ctx.pass->man->llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::Int))))) {
}
Value*
ControlIR::compileStructIndex(llvm::Value* aggregate, ExpandedType aggrT, const list<string>& 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<std::string>& 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<unsigned>{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);
IFwdIteratorIR* aggrItIR = IFwdIteratorIR::create(aggrE, aggrT, context);
- llvm::Value* idxBeginRaw = aggrItIR->begin();
- llvm::Value* idxEndRaw = aggrItIR->end();
+ llvm::Value* idxBeginRaw = aggrItIR->begin(aggrRaw);
+ llvm::Value* idxEndRaw = aggrItIR->end(aggrRaw);
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 *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);
std::unique_ptr<TransformerSaturation> transformerSaturation(new TransformerSaturation(blockProlog, context.pass->managerTransformations));
//Header:
// * create phi
llvm->irBuilder.SetInsertPoint(blockHeader);
llvm::PHINode *accum = llvm->irBuilder.CreatePHI(accumRawT, 2, accumAlias);
accum->addIncoming(accumInitRaw, blockProlog);
llvm::PHINode *idxCurrentRaw = llvm->irBuilder.CreatePHI(idxBeginRaw->getType(), 2, "foldIt");
idxCurrentRaw->addIncoming(idxBeginRaw, blockProlog);
// * loop checks
Value* condRange = llvm->irBuilder.CreateICmpNE(idxCurrentRaw, idxEndRaw);
llvm->irBuilder.CreateCondBr(condRange, blockBody, blockEpilog);
//Body:
llvm->irBuilder.SetInsertPoint(blockBody);
CodeScope* scopeLoop = loopE.blocks.front();
compilation::IBruteScope* loopUnit = function->getBruteScope(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(blockFooter, blockEpilog, context);
llvm::BasicBlock* blockSaturation = llvm->irBuilder.GetInsertBlock();
if (!flagSaturationTriggered){
llvm->irBuilder.CreateBr(blockFooter);
}
//Footer:
// * computing next iteration state
llvm->irBuilder.SetInsertPoint(blockFooter);
Value *itLoopNext = aggrItIR->advance(idxCurrentRaw);
accum->addIncoming(accumNext, llvm->irBuilder.GetInsertBlock());
idxCurrentRaw->addIncoming(itLoopNext, llvm->irBuilder.GetInsertBlock());
llvm->irBuilder.CreateBr(blockHeader);
//Prolog:
llvm->irBuilder.SetInsertPoint(context.scope->lastBlockRaw);
llvm->irBuilder.CreateBr(blockProlog);
llvm->irBuilder.SetInsertPoint(blockProlog);
llvm->irBuilder.CreateBr(blockHeader);
// Epilog:
llvm->irBuilder.SetInsertPoint(blockEpilog);
if (!flagSaturationTriggered){
return accum;
}
llvm::PHINode* result = llvm->irBuilder.CreatePHI(accumRawT, 2, hintAlias);
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> 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->getBruteScope(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->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->getBruteScope(scopeTrue)->compile();
llvm::BasicBlock * blockTrueEnd = builder.GetInsertBlock();
builder.CreateBr(blockEpilog);
builder.SetInsertPoint(blockFalse);
CodeScope* scopeFalse = exprIf.blocks.back();
llvm::Value* resultFalse = function->getBruteScope(scopeFalse)->compile();
llvm::BasicBlock * blockFalseEnd = builder.GetInsertBlock();
builder.CreateBr(blockEpilog);
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->getBruteScope(exprSwitch.operands[i].blocks.front())->compile();
builder.SetInsertPoint(blockCase);
llvm::Value* resultCase = function->getBruteScope(exprSwitch.operands[i].blocks.back())->compile();
builder.CreateBr(blockEpilog);
ret->addIncoming(resultCase, builder.GetInsertBlock());
builder.SetInsertPoint(blockProlog);
instructionSwitch->addCase(
dyn_cast<llvm::ConstantInt>(
typeinference::doAutomaticTypeConversion(condCase, typI8, builder)),
blockCase);
}
//compile default block:
builder.SetInsertPoint(blockDefault);
CodeScope* scopeDefault = exprSwitch.operands[1].blocks.front();
llvm::Value* resultDefault = function->getBruteScope(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<unsigned>({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<llvm::StructType>(typVariantRaw)->getElementType(1);
llvm::Value* storageRaw = builder.CreateExtractValue(conditionSwitchRaw, llvm::ArrayRef<unsigned>({1}));
addrAsStorage = llvm->irBuilder.CreateAlloca(typStorageRaw);
llvm->irBuilder.CreateStore(storageRaw, addrAsStorage);
}
llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(idRaw, nullptr, casesCount);
llvm::BasicBlock* blockDefaultUndefined;
std::list<CodeScope*>::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->getBruteScope(*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<TypeInferred>(identSymb, instType);
}
llvm::Value* resultCase = function->getBruteScope(*scopeCaseIt)->compile();
builder.CreateBr(blockEpilog);
ret->addIncoming(resultCase, blockDefaultUndefined = builder.GetInsertBlock());
builder.SetInsertPoint(blockProlog);
instructionSwitch->addCase(dyn_cast<llvm::ConstantInt>(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<Constant *> 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->getBruteScope(scope)->compile();
}
return result;
}
diff --git a/cpp/src/compilation/control.h b/cpp/src/compilation/control.h
index 556bc09..d4b3e7d 100644
--- a/cpp/src/compilation/control.h
+++ b/cpp/src/compilation/control.h
@@ -1,73 +1,73 @@
/* 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: ControlIR.h
+ * File: Control.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on June 26, 2016, 6:00 PM
*/
/**
* \file advancedinstructions.h
* \brief Compound statements compilation
*/
#ifndef INSTRUCTIONSADVANCED_H
#define INSTRUCTIONSADVANCED_H
#include "ast.h"
#include "llvmlayer.h"
#include "pass/compilepass.h"
#include <vector>
namespace xreate {
namespace compilation {
/** \brief Advanced compilation primitives */
class ControlIR {
public:
ControlIR(compilation::Context ctx);
/** \brief Struct field access operator compilation*/
llvm::Value* compileStructIndex(llvm::Value* aggregate, ExpandedType aggrT, const std::list<std::string>& indices);
/*
* - map Computation -> Llvm_Array: Prohibited, we do not know a result size
* - map Llvm_Array -> Computation: considered in `compileGetElement`
* - map Llvm_Array -> Llvm_Array considered by this method
*/
/** \brief `loop map` statement compilation*/
llvm::Value* compileMapSolidOutput(const Expression &expr, const std::string hintRetVar = "");
/** \brief `loop fold` statement compilation*/
llvm::Value* compileFold(const Expression& loopE, const std::string& hintAlias="");
/** \brief `loop` statement compilation*/
llvm::Value* compileFoldInf(const Expression& fold, const std::string& ident="");
/** \brief `if` statement compilation*/
llvm::Value* compileIf(const Expression& exprIf, const std::string& ident);
/** \brief `switch` statement compilation*/
llvm::Value* compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar);
/** \brief `switch` statement compilation*/
llvm::Value* compileSwitchVariant(const Expression& exprSwitch, const std::string& hintRetVar);
/** \brief `switch variant` statement compilation*/
llvm::Value* compileConstantStringAsPChar(const std::string &data, const std::string& hintRetVar);
/** \brief `seq` statement compilation */
llvm::Value* compileSequence(const Expression &expr);
private:
compilation::Context context;
llvm::IntegerType* const tyNum;
};
}}
#endif /* INSTRUCTIONSADVANCED_H */
diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp
index 98960c0..4eb8b7f 100644
--- a/cpp/src/pass/compilepass.cpp
+++ b/cpp/src/pass/compilepass.cpp
@@ -1,895 +1,895 @@
/* 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 <v.melnychenko@xreate.org>
- *
- * 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 <boost/optional.hpp>
#include <memory>
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(__function->__name).size() > 1 ?
__function->__name + std::to_string(__function.id()) :
__function->__name;
return name;
}
std::vector<llvm::Type*>
BasicBruteFunction::prepareSignature() {
CodeScope* entry = __function->__entry;
return getScopeSignature(entry);
}
llvm::Type*
BasicBruteFunction::prepareResult() {
LLVMLayer* llvm = IBruteFunction::pass->man->llvm;
AST* ast = IBruteFunction::pass->man->root;
CodeScope* entry = __function->__entry;
return llvm->toLLVMType(ast->expandType(entry->__declarations.at(ScopedSymbol::RetSymbol).type));
}
llvm::Function::arg_iterator
BasicBruteFunction::prepareBindings() {
CodeScope* entry = __function->__entry;
IBruteScope* entryCompilation = IBruteFunction::getBruteScope(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), lastBlockRaw(nullptr) { }
llvm::Value*
BruteFnInvocation::operator()(std::vector<llvm::Value *>&& args, const std::string& hintDecl) {
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;
}
}
}
//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<llvm::Value *>&& 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<llvm::Value *>&& 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<IsImplementationOnTheFly>(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->getBruteScope(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;
}
IFnInvocation*
BasicBruteScope::findFunction(const Expression& opCall) {
const std::string& calleeName = opCall.getValueString();
LLVMLayer* llvm = pass->man->llvm;
const std::list<ManagedFnPtr>& 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->getBruteFn(
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;
default:;
}
switch (expr.op) {
case Operator::AND:
{
assert(expr.operands.size());
llvm::Value* resultRaw = process(expr.operands.at(0));
if (expr.operands.size() == 1) return resultRaw;
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.at(0));
if (expr.operands.size() == 1) return resultRaw;
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::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::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]);
if(leftT->__operator == TypeOperator::VARIANT && rightT->__operator == TypeOperator::VARIANT){
llvm::Type* selectorT = llvm::cast<llvm::StructType>(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::NE:
return l.irBuilder.CreateICmpNE(leftRaw, rightRaw, DEFAULT("tmp_ne"));
break;
case Operator::LSS:
return l.irBuilder.CreateICmpSLT(leftRaw, rightRaw, DEFAULT("tmp_lss"));
break;
case Operator::LSE:
return l.irBuilder.CreateICmpSLE(leftRaw, rightRaw, DEFAULT("tmp_lse"));
break;
case Operator::GTR:
return l.irBuilder.CreateICmpSGT(leftRaw, rightRaw, DEFAULT("tmp_gtr"));
break;
case Operator::GTE:
return l.irBuilder.CreateICmpSGE(leftRaw, rightRaw, DEFAULT("tmp_gte"));
break;
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);
}
break;
}
case Operator::CALL:
{
assert(expr.__state == Expression::COMPOUND);
shared_ptr<IFnInvocation> callee(findFunction(expr));
const std::string& nameCallee = expr.getValueString();
//prepare arguments
std::vector<llvm::Value *> args;
args.reserve(expr.operands.size());
std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()),
[this](const Expression & operand) {
return process(operand);
}
);
return (*callee)(move(args), DEFAULT("res_" + nameCallee));
}
case Operator::IF:
{
return controlIR.compileIf(expr, DEFAULT("tmp_if"));
}
case Operator::SWITCH:
{
return controlIR.compileSwitch(expr, DEFAULT("tmp_switch"));
}
case Operator::LOGIC_AND:
{
assert(expr.operands.size() == 1);
return process(expr.operands[0]);
}
case Operator::LIST: //init record or array
{
ExpandedType exprT = l.ast->getType(expr, expectedT);
TypesHelper helper(pass->man->llvm);
enum {RECORD, ARRAY} kind;
if (helper.isArrayT(exprT)){
kind = ARRAY;
} else if (helper.isRecordT(exprT)){
kind = RECORD;
} else {
assert(false && "Inapproriate type");
}
#ifdef XREATE_ENABLE_EXTERN
if (exprT->__operator == TypeOperator::ALIAS){
if (l.layerExtern->isArrayType(exprT->__valueCustom)){
flagIsArray = true;
break;
}
if (l.layerExtern->isRecordType(exprT->__valueCustom)){
flagIsArray = false;
break;
}
assert(false && "Inapproriate external type");
}
#endif
switch(kind){
case RECORD:{
const std::vector<string> fieldsFormal = helper.getRecordFields(exprT);
containers::RecordIR irRecords(ctx);
llvm::StructType *recordTRaw = llvm::cast<llvm::StructType>(l.toLLVMType(exprT));
llvm::Value *resultRaw = irRecords.init(recordTRaw);
return irRecords.update(resultRaw, exprT, expr);
}
case ARRAY: {
std::unique_ptr<containers::IContainersIR> containerIR(
containers::IContainersIR::create(expr, expectedT, ctx));
llvm::Value* aggrRaw = containerIR->init(hintAlias);
return containerIR->update(aggrRaw, expr, hintAlias);
}
}
break;
};
case Operator::LIST_RANGE:
{
- assert(false); //no compilation phase for a range list
- // return InstructionList(this).compileConstantArray(expr, l, hintRetVar);
+ containers::RangeIR compiler(ctx);
+ const ExpandedType& aggrT = pass->man->root->getType(expr);
+
+ return compiler.init(expr, aggrT, hintAlias);
};
case Operator::MAP:
{
assert(expr.blocks.size());
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"));
}
case containers::ImplementationType::ON_THE_FLY:{
FlyHint hint = find<FlyHint>(expr, {});
containers::FlyIR compiler(hint, ctx);
return compiler.operatorMap(expr, DEFAULT("map"));
}
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:
{
list<string> 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<llvm::Value*> indexes;
std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()),
[this] (const Expression & op) {
return process(op);
}
);
std::unique_ptr<containers::IContainersIR> containersIR(
containers::IContainersIR::create(aggrE, expectedT, ctx)
);
containers::ArrayIR* arraysIR = static_cast<containers::ArrayIR*>(containersIR.get());
return arraysIR->get(aggrRaw, indexes, hintAlias);
};
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<VersionsScopeDecoratorTag>::getInterface(this);
// llvm::Value* storage = decoratorVersions->processIntrinsicInit(result->getType());
// decoratorVersions->processIntrinsicCopy(result, storage);
//
// return l.irBuilder.CreateLoad(storage, hintAlias);
// }
assert(false && "undefined intrinsic");
}
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<llvm::StructType>(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<unsigned>({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<TypeInferred>(expr.operands.at(fieldId), typField);
llvm::Value* fieldRaw = process(expr.operands.at(fieldId));
assert(fieldRaw);
variantRaw = l.irBuilder.CreateInsertValue(variantRaw, fieldRaw, llvm::ArrayRef<unsigned>({fieldId}));
}
llvm::Type* typStorageRaw = llvm::cast<llvm::StructType>(typResultRaw)->getElementType(1);
llvm::Value* addrAsStorage = l.irBuilder.CreateAlloca(typStorageRaw);
llvm::Value* addrAsVariant = l.irBuilder.CreateBitOrPointerCast(addrAsStorage, typVariantRaw->getPointerTo());
l.irBuilder.CreateStore(variantRaw, addrAsVariant);
llvm::Value* storageRaw = l.irBuilder.CreateLoad(typStorageRaw, addrAsStorage);
resultRaw = l.irBuilder.CreateInsertValue(resultRaw, storageRaw, llvm::ArrayRef<unsigned>({1}));
return resultRaw;
}
case Operator::SWITCH_VARIANT:
{
return controlIR.compileSwitchVariant(expr, DEFAULT("tmpswitch"));
}
case Operator::SWITCH_LATE:
{
assert(false && "Instruction's compilation should've been redirected to interpretation");
return nullptr;
}
case Operator::SEQUENCE:
{
return controlIR.compileSequence(expr);
}
case Operator::UNDEF:
{
llvm::Type* typExprUndef = l.toLLVMType(pass->man->root->getType(expr, expectedT));
return llvm::UndefValue::get(typExprUndef);
}
case Operator::UPDATE:
{
TypesHelper helper(pass->man->llvm);
containers::RecordIR irRecords(ctx);
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);
if (helper.isRecordT(aggrT)){
return irRecords.update(aggrRaw, aggrT, updE);
}
if (helper.isArrayT(aggrT)){
if (updE.op == Operator::LIST_INDEX){
std::unique_ptr<containers::IContainersIR> containersIR(
containers::IContainersIR::create(aggrE, TypeAnnotation(), ctx
));
return containersIR->update(aggrRaw, updE, hintAlias);
}
}
assert(false);
return nullptr;
}
case Operator::INVALID:
assert(expr.__state != Expression::COMPOUND);
switch (expr.__state) {
case Expression::IDENT:
{
Symbol s = Attachments::get<IdentifierSymbol>(expr);
return processSymbol(s, expr.getValueString());
}
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");
}
case Expression::STRING:
{
return controlIR.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str"));
};
default:
{
break;
}
};
break;
default: break;
}
assert(false && "Can't compile expression");
return 0;
}
llvm::Value*
BasicBruteScope::compile(const std::string& hintBlockDecl) {
LLVMLayer* llvm = pass->man->llvm;
if (!hintBlockDecl.empty()) {
llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm->llvmContext, hintBlockDecl, function->raw);
pass->man->llvm->irBuilder.SetInsertPoint(block);
}
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<llvm::Type*>&& types = prepareSignature();
llvm::Type* expectedResultType = prepareResult();
llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false);
raw = llvm::cast<llvm::Function>(llvm->module->getOrInsertFunction(functionName, ft));
prepareBindings();
applyAttributes();
const std::string& blockName = "entry";
llvm::BasicBlock* blockCurrent = builder.GetInsertBlock();
llvm::Value* result = getBruteScope(__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::getBruteScope(const CodeScope * const scope) {
if (__scopes.count(scope)) {
auto result = __scopes.at(scope).lock();
if (result) {
return result.get();
}
}
std::shared_ptr<IBruteScope> unit(pass->buildCodeScopeUnit(scope, this));
if (scope->__parent != nullptr) {
auto parentUnit = Decorators<CachedScopeDecoratorTag>::getInterface(getBruteScope(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 getBruteScope(&*scope);
}
IBruteScope*
IBruteFunction::getEntry() {
return getBruteScope(__entry);
}
std::vector<llvm::Type*>
IBruteFunction::getScopeSignature(CodeScope* scope){
LLVMLayer* llvm = IBruteFunction::pass->man->llvm;
AST* ast = IBruteFunction::pass->man->root;
std::vector<llvm::Type*> result;
std::transform(scope->__bindings.begin(), scope->__bindings.end(), std::inserter(result, result.end()),
[llvm, ast, scope](const std::string & argAlias)->llvm::Type* {
assert(scope->__identifiers.count(argAlias));
ScopedSymbol argS{scope->__identifiers.at(argAlias), versions::VERSION_NONE};
const Expression& argE = scope->__declarations.at(argS);
const ExpandedType& argT = ast->expandType(argE.type);
return llvm->toLLVMType(argT, argE);
});
return result;
}
template<>
compilation::IBruteFunction*
CompilePassCustomDecorators<void, void>
::buildFunctionUnit(const ManagedFnPtr& function) {
return new BruteFunctionDefault(function, this);
}
template<>
compilation::IBruteScope*
CompilePassCustomDecorators<void, void>
::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::getBruteFn(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 modelEntry = man->transcend->query(analysis::FN_ENTRY_PREDICATE);
if (man->options.requireEntryFn){
assert(modelEntry.size() && "Error: No entry function found");
assert(modelEntry.size() == 1 && "Error: Ambiguous entry function");
}
if(modelEntry.size()){
string fnEntryName = std::get<0>(TranscendLayer::parse<std::string>(modelEntry.begin()->second));
compilation::IBruteFunction* fnEntry = getBruteFn(man->root->findFunction(fnEntryName));
__fnEntryRaw = fnEntry->compile();
}
//Compile exterior functions:
StaticModel modelExterior = man->transcend->query(analysis::FN_EXTERIOR_PREDICATE);
for(const auto entry: modelExterior){
const string& fnName = std::get<0>(TranscendLayer::parse<std::string>(entry.second));
getBruteFn(man->root->findFunction(fnName))->compile();
}
}
llvm::Function*
CompilePass::getEntryFunction() {
return __fnEntryRaw;
}
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<void, void>` constructs the default compiler.
*
*/
diff --git a/cpp/src/query/containers.cpp b/cpp/src/query/containers.cpp
index 2b8fc8c..a658cab 100644
--- a/cpp/src/query/containers.cpp
+++ b/cpp/src/query/containers.cpp
@@ -1,112 +1,112 @@
/* 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 <v.melnychenko@xreate.org>
*
* containers.cpp
* Created on 3/14/15.
*/
#include <transcendlayer.h>
#include "query/containers.h"
#include "analysis/resources.h"
using namespace std;
using namespace xreate::containers;
using namespace xreate;
Implementation
Query::queryImplementation(xreate::Symbol const &s) {
if (Attachments::exists<Implementation>(s)) {
return Attachments::get<Implementation>(s);
}
return Implementation::create(s);
}
Query::Query() {
Attachments::init<Implementation>();
}
void
Query::init(TranscendLayer* transcend) {
if (flagDataIsLoaded) return;
//Fill implementation data for a data sources:
auto range = transcend->query(xreate::analysis::CONTAINERS_ID_IMPL_PREDICATE);
if (range.size())
for(auto atom : range) {
auto data = TranscendLayer::parse<SymbolPacked, Gringo::Symbol>(atom.second);
Symbol var = transcend->unpack(get<0>(data));
string implStr = get<1>(data).name().c_str();
- if (implStr == xreate::analysis::CONTAINERS_IMPL_SOLID_PREDICATE) {
+ if (implStr == xreate::analysis::CONTAINERS_IMPL_ARRAY_PREDICATE) {
auto size = TranscendLayer::parse<int>(get<1>(data));
Attachments::put<Implementation>(var,{SOLID, ImplementationRec<SOLID>
{get<0>(size)}});
- } else if (implStr == xreate::analysis::CONTAINERS_IMPL_ONTHEFLY_PREDICATE) {
+ } else if (implStr == xreate::analysis::CONTAINERS_IMPL_FLY_PREDICATE) {
Attachments::put<Implementation>(var,{ON_THE_FLY, ImplementationRec<ON_THE_FLY>
{var}});
} else {
assert(false && "Unable to determine proper implementation for the symbol");
}
}
flagDataIsLoaded = true;
}
Implementation
Implementation::create(const Symbol &var) {
//TODO review implementation determination strategy
Expression varDecl = CodeScope::getDefinition(var);
switch (varDecl.op) {
case Operator::LIST_RANGE:
{
ImplementationRec<ON_THE_FLY> rec{var};
return {ON_THE_FLY, rec};
}
case Operator::LIST:
{
return {SOLID, ImplementationRec<SOLID> {varDecl.getOperands().size()}};
}
default: break;
};
ImplementationLinkedList ill(var);
if (ill) {
return ill.getImplementationData();
}
assert(false && "Unable to determine proper implementation for the symbol");
return Implementation();
}
ImplementationLinkedList::ImplementationLinkedList(const Symbol& source)
: flagIsValid(false), s(source) {
const Expression& sourceExpr = CodeScope::getDefinition(source);
if (sourceExpr.tags.count(analysis::CONTAINERS_ID_LINKLIST_PREDICATE)) {
flagIsValid = true;
Expression tagLinkedlist = sourceExpr.tags.at(analysis::CONTAINERS_ID_LINKLIST_PREDICATE);
assert(tagLinkedlist.operands.size() == 2);
fieldPointer = tagLinkedlist.operands.at(0).getValueString();
terminator = tagLinkedlist.operands.at(1);
}
}
ImplementationLinkedList::operator bool () const {
return flagIsValid;
}
Implementation
ImplementationLinkedList::getImplementationData() const {
return {ON_THE_FLY, ImplementationRec<ON_THE_FLY>{s}};
}
diff --git a/cpp/src/query/containers.h b/cpp/src/query/containers.h
index 8f19dd9..472f4b1 100644
--- a/cpp/src/query/containers.h
+++ b/cpp/src/query/containers.h
@@ -1,96 +1,96 @@
/* 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 <v.melnychenko@xreate.org>
*
* containers.h
* Created on 3/14/15.
*/
/**
* \file query/containers.h
* \brief Transcend solutions on [Containers](/d/concepts/containers/) implementation details
*/
#ifndef _XREATE_CONTAINERSQUERY_H_
#define _XREATE_CONTAINERSQUERY_H_
#include "xreatemanager.h"
#include "transcendlayer.h"
#include <boost/variant.hpp>
namespace xreate {
namespace containers {
- enum ImplementationType {SOLID, ON_THE_FLY, LINKED_LIST};
+ enum ImplementationType {SOLID, ON_THE_FLY, RANGE, LINKED_LIST};
template<ImplementationType I>
struct ImplementationRec;
template<>
struct ImplementationRec<SOLID> {
size_t size;
};
template<>
struct ImplementationRec<ON_THE_FLY>{
Symbol source;
};
struct Implementation;
struct ImplementationLinkedList {
bool flagIsValid;
std::string fieldPointer;
Expression terminator;
ImplementationLinkedList(const Symbol& source);
operator bool() const;
Implementation getImplementationData() const;
private:
Symbol s;
};
struct Implementation {
typedef boost::variant<ImplementationRec<SOLID>, ImplementationRec<ON_THE_FLY>> Variant;
ImplementationType impl;
Variant data;
static Implementation create(const Symbol &var);
static Implementation create(const Symbol& var, const std::string &implSerialized);
template<ImplementationType I>
const ImplementationRec<I>& extract() const{
const ImplementationRec<I>& rec = boost::get<ImplementationRec<I>>(data);
return rec;
}
};
/**
* \brief Queries Transcend solutions on containers implementation details
* \sa xreate::containers::IFwdIteratorIR
*/
class Query : public xreate::IQuery {
public:
static Implementation queryImplementation(xreate::Symbol const &s);
void init(TranscendLayer* transcend);
Query();
~Query(){}
private:
bool flagDataIsLoaded = false;
PassManager *man;
};
}
template<>
struct AttachmentsDict<containers::Implementation> {
typedef containers::Implementation Data;
static const unsigned int key = 1;
};
}
#endif //_XREATE_CONTAINERSQUERY_H_
diff --git a/cpp/tests/containers.cpp b/cpp/tests/containers.cpp
index bcd9bef..0049586 100644
--- a/cpp/tests/containers.cpp
+++ b/cpp/tests/containers.cpp
@@ -1,325 +1,327 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* containers.cpp
*
* Created on: Jun 9, 2015
* Author: pgess <v.melnychenko@xreate.org>
*/
#include "xreatemanager.h"
#include "query/containers.h"
#include "main/Parser.h"
#include "pass/compilepass.h"
#include "llvmlayer.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;
struct Tuple2 {intmax_t a; intmax_t b;};
typedef Tuple2 (*FnTuple2)();
struct Tuple4 {intmax_t a; intmax_t b; intmax_t c; intmax_t d;};
typedef Tuple4 (*FnTuple4)();
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, RecInitByList2){
string code = R"(
Rec = type {x:: int, y:: int}.
test = function(a:: int, b::int):: Rec; entry() {
{a + b, y = 2}
}
)";
auto man = XreateManager::prepare(move(code));
man->run();
}
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, 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, 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, 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, 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, FlyMap1){
std::unique_ptr<XreateManager> 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
}
)"));
FnNoArgs mainFn = (FnNoArgs) man->run();
intmax_t valueMain = mainFn();
ASSERT_EQ(0, valueMain);
}
TEST(Containers, ArrayArg1){
FILE* code = fopen("scripts/containers/containers-tests.xreate", "r");
assert(code != nullptr);
- auto man = details::tier1::XreateManager::prepare(code);
- LLVMLayer* llvm = man->llvm;
- man->analyse();
-
- std::unique_ptr<CompilePass> compiler(new compilation::CompilePassCustomDecorators<>(man));
- compiler->prepare();
- llvm::Function* fnMainRaw = compiler->getBruteFn(man->root->findFunction("fn-ArrayArg1"))->compile();
- llvm->print();
- llvm->initJit();
-
- FnNoArgs mainFn = (FnNoArgs) llvm->getFunctionPointer(fnMainRaw);
- ASSERT_EQ(1, mainFn());
+ std::unique_ptr<XreateManager> man(XreateManager::prepare(code));
+ man->options.requireEntryFn = false;
+ man->run();
+ FnNoArgs fnTested = (FnNoArgs) man->getExteriorFn("fn-ArrayArg1");
+ ASSERT_EQ(1, fnTested());
}
TEST(Containers, FlyArg1){
FILE* code = fopen("scripts/containers/containers-tests.xreate", "r");
assert(code != nullptr);
- auto man = details::tier1::XreateManager::prepare(code);
- LLVMLayer* llvm = man->llvm;
- man->analyse();
+ std::unique_ptr<XreateManager> man(XreateManager::prepare(code));
+ man->options.requireEntryFn = false;
+ man->run();
+ FnNoArgs fnTested = (FnNoArgs) man->getExteriorFn("fn-FlyArg1");
+ ASSERT_EQ(8, fnTested());
+}
- std::unique_ptr<CompilePass> compiler(new compilation::CompilePassCustomDecorators<>(man));
- compiler->prepare();
- llvm::Function* fnTestedRaw = compiler->getBruteFn(man->root->findFunction("fn-FlyArg1"))->compile();
- llvm->print();
+TEST(Containers, Range1){
+ FILE* code = fopen("scripts/containers/containers-tests.xreate", "r");
+ assert(code != nullptr);
- llvm->optsLevel = llvm::CodeGenOpt::Aggressive;
- llvm->initJit();
+ std::unique_ptr<XreateManager> man(XreateManager::prepare(code));
+ man->options.requireEntryFn = false;
+ man->run();
+ {
+ FnNoArgs fnRange1 = (FnNoArgs) man->getExteriorFn("fn-Range1");
+ ASSERT_EQ(10, fnRange1());
+ }
- FnNoArgs fnTested = (FnNoArgs) llvm->getFunctionPointer(fnTestedRaw);
- ASSERT_EQ(8, fnTested());
+ {
+ FnNoArgs fnRange2 = (FnNoArgs) man->getExteriorFn("fn-Range2");
+ ASSERT_EQ(20, fnRange2());
+ }
}
//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<bool>(iLL));
// ASSERT_EQ("next", iLL.fieldPointer);
//
// Implementation impl = Implementation::create(symb_chilrenRaw);
// ASSERT_NO_FATAL_FAILURE(impl.extract<ON_THE_FLY>());
//
// ImplementationRec<ON_THE_FLY> recOnthefly = impl.extract<ON_THE_FLY>();
// 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<XreateManager> 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
// {
// <BODY>
// x
// }
// )Code";
// string body = getDocumentationExampleById("documentation/Concepts/containers.xml", "Intr_1");
// replace(example, "<BODY>", 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/scripts/containers/containers-tests.assembly.lp b/scripts/containers/containers-tests.assembly.lp
new file mode 100644
index 0000000..4618171
--- /dev/null
+++ b/scripts/containers/containers-tests.assembly.lp
@@ -0,0 +1,9 @@
+select(test(common)).
+%select(function("fn-Range2")).
+
+bind_func(Fn, exterior):-
+ select(test(Template));
+ bind_func(Fn, test(Template)).
+
+bind_func(FnName, exterior):-
+ select(function(FnName)).
diff --git a/scripts/containers/containers-tests.xreate b/scripts/containers/containers-tests.xreate
index a9c8e13..7196d06 100644
--- a/scripts/containers/containers-tests.xreate
+++ b/scripts/containers/containers-tests.xreate
@@ -1,48 +1,79 @@
+import raw ("scripts/containers/containers-tests.assembly.lp").
+
+Test = type predicate{
+ common
+}.
+
+FnAnns = type predicate{
+ test(kind:: Test)
+}
+
min = function(x:: [int]; csize(5)):: int
{
loop fold((x:: [int]; csize(5))->el:: int, 1000->min):: int
{
if (el < min):: int { el } else { min }
}
}
min2 = function(x:: [int]; fly(csize(5))):: int
{
loop fold((x:: [int]; fly(csize(5)))->el:: int, 1000->min):: int
{
if (el < min):: int { el } else { min }
}
}
-fn-FlyArg1 = function:: int; entry()
+fn-ArrayArg1 = function:: int; test(common())
+{
+ a = {3, 2, 1, 4, 5}:: [int]; csize(5).
+ min(a)
+}
+
+fn-FlyArg1 = function:: int; test(common())
{
a = {3, 2, 1, 4, 5}:: [int]; csize(5).
b = loop map(a->x:: int):: [int]; fly(csize(5))
{
8 * x :: int
}.
min2(b)
}
+fn-Range1 = function:: int; test(common())
+{
+ range = [1..5]:: [int]; range().
+ loop fold(range->x:: int, 0->sum):: int {sum + x}
+}
+
+fn-Range2 = function:: int; test(common())
+{
+ range1 = [1..5]:: [int]; range().
+ range2 = loop map (range1->x:: int):: [int]; fly(range()) {2 * x:: int}.
+ loop fold(range2->x:: int, 0->sum):: int {sum + x}
+}
+
+/*
reorder = function(aggrSrc:: [int], idxs::[int]):: [int]
{
loop map(idxs->idx)::[int]
{
aggrSrc[idx])
}
}
reverse = function(aggrSrc::[int])::[int]
{
sizeDst = 5:: int.
idxsDst = [0..sizeDst - 1]:: [int].
idxsTnsf = loop map(idxsDst-> idx:: int):: [int]
{
sizeDstClone = 5:: int.
sizeDstClone - idx - 1
}
reorder(aggrSrc, idxsTnsf)
}
+*/
diff --git a/scripts/containers/minmax.xreate b/scripts/containers/minmax.xreate
index a9478cb..f4f3a51 100644
--- a/scripts/containers/minmax.xreate
+++ b/scripts/containers/minmax.xreate
@@ -1,439 +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].
+ arr = {25, 37, 12, 6, 5, 19, 3, 20}:: [int];csize(8).
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}].
+ } :: [{int, int}]; csize(7).
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}].
+ } :: [{int, int}]; csize(7).
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].
+ arr = {25, 37, 12, 6, 5, 19, 3, 20}:: [int]; csize(8).
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}].
+ } :: [{int, int}]; csize(7).
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].
+ arr = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]; csize(10).
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].
+ arr = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]; csize(10).
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].
+ input = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]; csize(10).
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].
+ input = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]; csize(10).
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].
+ input = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]; csize(10).
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].
+ input = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]; csize(10).
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].
+ input = {-8, 16, 3, -5, 2, -11, -905, -54}:: [int]; csize(8).
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 }
}
fn-minmax13 = function::int
{
- input = {-8, 16, 3, -5, 2, -11, -905, -54}:: [int].
+ input = {-8, 16, 3, -5, 2, -11, -905, -54}:: [int]; csize(8).
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"]
}
fn-minmax14 = function:: El
{
- input = { -8, 16, 3, -5, 2, -11, -905, -54 }:: [int].
+ input = { -8, 16, 3, -5, 2, -11, -905, -54 }:: [int]; csize(8).
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].
+ input = { -8, 16, 3, -5, 2, -11, -905, -54 }:: [int]; csize(8).
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].
+ input = { 18, 16, 2, 5, 2, 11, 905, 2 }:: [int]; csize(8).
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].
+ input = { 18, 16, 2, 5, 2, 11, 905, 2 }:: [int]; csize(8).
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].
+ input = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}:: [int]; csize(10).
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].
+ input = {-5, 18, 63, -29, 11, 17, 96, 28, -14}:: [int]; csize(9).
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].
+ input = {-5, 18, 63, -29, 11, 17, 96, 28, -14}:: [int]; csize(9).
result = loop fold(input->x:: int, {-1000, -1000, -1000}->max):: Triple
{
max3(x, max):: Triple
}.
{result[0], result[1], result[2], 0}
}

Event Timeline