No OneTemporary

File Metadata

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

Event Timeline