Page Menu
Home
Xreate
Search
Configure Global Search
Log In
Docs
Questions
Repository
Issues
Patches
Internal API
Files
F2718191
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sun, Feb 15, 5:09 PM
Size
151 KB
Mime Type
text/x-diff
Expires
Tue, Feb 17, 5:09 PM (1 d, 17 h)
Engine
blob
Format
Raw Data
Handle
237590
Attached To
rXR Xreate
View Options
diff --git a/.gitignore b/.gitignore
index 8f97d68..189db3d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,105 +1,106 @@
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Compiled Dynamic libraries
*.so
*.so.*
*.dylib
*.dll
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
*.class
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.ear
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
# Qt-es
/.qmake.cache
/.qmake.stash
*.pro.user
*.pro.user.*
*.moc
moc_*.cpp
qrc_*.cpp
ui_*.h
Makefile*
*-build-*
# QtCreator
*.autosave
coco/*.old
coco/*~
*~
# XREATE
cpp/build-*/
cpp/xreate-debug/*
cpp/xreate-release/*
cpp/.idea
CMakeLists.txt.user
cmake_install.cmake
project/*
nb*.xml
.*
target/*
/tools/phabricator/xreate-frontend/nbproject/private/
documentation/trash4/
trash/
CMakeFiles/
gen-cpp/
generated-cpp/
gen-php/
generated-js/
books/
build/
coco/Parser.*
coco/Scanner.*
tools/phabricator/administration/
tmp-*
cpp/tests/vendorsAPI/
secrets/
/tools/site/init-data/
code-coverage.sh
codestyle-netbeans/
deferred/
design/
documentation-tools/xmlmind-custom-css
grammar/main/
grammar/modules/
+grammar/universal/
model-to-graph
tools/netdata*
tools/nginx-tests/
tools/phabricator/diagrams/
tools/phabricator/docker/
tools/phabricator/nbproject/
tools/phabricator/xreate-frontend/install-xreate-frontend.sh
tools/scaleway-perf
tools/scaleway-perf.ods
tools/site/init-data/
tools/site/secrets/
valgrind.sh
diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp
index 4f92561..f313cff 100644
--- a/cpp/src/ast.cpp
+++ b/cpp/src/ast.cpp
@@ -1,972 +1,973 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Author: pgess <v.melnychenko@xreate.org>
* File: ast.cpp
*/
#include "ast.h"
#include "analysis/typeinference.h"
#include "analysis/predefinedanns.h"
#ifdef XREATE_ENABLE_EXTERN
#include "ExternLayer.h"
#endif
#include <stdexcept>
#include <iostream>
//TODO BDecl. forbid multiple body declaration (ExprTyped)
namespace std {
std::size_t
hash<xreate::ScopedSymbol>::operator()(xreate::ScopedSymbol const& s) const {
return s.id ^ (s.version << 2);
}
bool
equal_to<xreate::ScopedSymbol>::operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const {
return __x.id == __y.id && __x.version == __y.version;
}
size_t
hash<xreate::Symbol>::operator()(xreate::Symbol const& s) const {
return hash<xreate::ScopedSymbol>()(s.identifier) ^ ((long int) s.scope << 1);
}
bool
equal_to<xreate::Symbol>::operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const {
return __x == __y;
};
}
using namespace std;
namespace xreate {
Atom<Identifier_t>::Atom(const std::wstring& value) {
__value = wstring_to_utf8(value);
}
Atom<Identifier_t>::Atom(std::string && name) : __value(name) {
}
const std::string&
Atom<Identifier_t>::get() const {
return __value;
}
Atom<Number_t>::Atom(wchar_t* value) {
//DEBT reconsider number literal recognition
__value = wcstol(value, 0, 10);
}
Atom<Number_t>::Atom(int value)
: __value(value) {
}
double
Atom<Number_t>::get()const {
return __value;
}
Atom<String_t>::Atom(const std::wstring& value) {
assert(value.size() >= 2);
__value = wstring_to_utf8(value.substr(1, value.size() - 2));
}
Atom<String_t>::Atom(std::string && name) : __value(name) {}
const std::string&
Atom<String_t>::get() const {
return __value;
}
/** \brief xreate::Expression static information*/
class ExpressionHints {
public:
static bool
isStringValueValid(const Expression& e) {
switch (e.__state) {
case Expression::INVALID:
assert(false);
case Expression::IDENT:
case Expression::STRING:
return true;
case Expression::NUMBER:
case Expression::BINDING:
return false;
case Expression::COMPOUND:
{
switch (e.op) {
case Operator::CALL:
return true;
default: return false;
}
}
}
return false;
}
static bool
isDoubleValueValid(const Expression& e) {
switch (e.__state) {
case Expression::NUMBER:
return true;
case Expression::INVALID:
assert(false);
case Expression::IDENT:
case Expression::STRING:
case Expression::BINDING:
return false;
case Expression::COMPOUND: {
switch (e.op) {
case Operator::VARIANT:
return true;
default: return false;
}
}
}
return false;
}
};
class TypeResolver {
public:
TypeResolver(const AST* ast,
TypeResolver * parent,
std::set<std::string> trace,
const std::map<std::string, TypeAnnotation>& scope = std::map<std::string, TypeAnnotation>())
: __ast(ast), __scope(scope), __trace(trace), __parent(parent) {}
ExpandedType
operator()(const TypeAnnotation &t, const std::vector<TypeAnnotation> &args = std::vector<TypeAnnotation>()) {
assert(args.size() == t.bindings.size()); // invalid number of arguments
for (size_t i = 0; i < args.size(); ++i) {
__scope[t.bindings.at(i)] = args.at(i);
}
switch (t.__operator) {
case TypeOperator::ARRAY:{
assert(t.__operands.size() == 1);
Expanded<TypeAnnotation> elTy = this->operator()(t.__operands.at(0));
return ExpandedType(TypeAnnotation(TypeOperator::ARRAY, {elTy.get()}));
}
case TypeOperator::RECORD:
{
std::vector<TypeAnnotation>&& packOperands = expandOperands(t.__operands);
auto typNew = TypeAnnotation(TypeOperator::RECORD, move(packOperands));
typNew.fields = t.fields;
return ExpandedType(move(typNew));
};
case TypeOperator::VARIANT:
{
std::vector<TypeAnnotation>&& packOperands = expandOperands(t.__operands);
auto typNew = TypeAnnotation(TypeOperator::VARIANT, move(packOperands));
typNew.fields = t.fields;
return ExpandedType(move(typNew));
};
case TypeOperator::ALIAS: {
std::string alias = t.__valueCustom;
if (__trace.count(alias)){
assert(false && "Recursive Type");
return ExpandedType(TypeAnnotation());
}
const TypeAnnotation& tyAlias = findType(alias);
std::vector<TypeAnnotation>&& operands = expandOperands(t.__operands);
auto traceNew =__trace;
traceNew.insert(alias);
return TypeResolver(__ast, this, traceNew, __scope)(tyAlias, operands);
};
case TypeOperator::ACCESS:
{
std::string alias = t.__valueCustom;
const TypeAnnotation& ty = findType(alias);
TypeAnnotation tyAggr = this->operator()(ty).get();
for (const string& field : t.fields) {
auto fieldIt = std::find(tyAggr.fields.begin(), tyAggr.fields.end(), field);
assert(fieldIt != tyAggr.fields.end() && "unknown field");
int fieldId = fieldIt - tyAggr.fields.begin();
tyAggr = tyAggr.__operands.at(fieldId);
}
return ExpandedType(tyAggr);
}
case TypeOperator::NONE:
case TypeOperator::VOID:
case TypeOperator::SLAVE:
case TypeOperator::REF: {
return ExpandedType(t);
}
default:
assert(false);
}
assert(false);
return ExpandedType(TypeAnnotation());
}
private:
const AST* __ast;
std::map<std::string, TypeAnnotation> __scope;
std::set<std::string> __trace;
TypeResolver* __parent;
std::vector<TypeAnnotation>
expandOperands(const std::vector<TypeAnnotation>& operands) {
std::vector<TypeAnnotation> pack;
pack.reserve(operands.size());
std::transform(operands.begin(), operands.end(), std::inserter(pack, pack.end()),
[this](const TypeAnnotation & t) {
return this->operator()(t).get();
});
return pack;
}
TypeAnnotation findType(const std::string& alias){
if (__scope.count(alias)) {
return __scope.at(alias);
} else if (__parent){
return __parent->findType(alias);
} else if (__ast->__registryTypes.count(alias)){
return __ast->__registryTypes.at(alias);
}
assert(false && "Undefined or external type");
return TypeAnnotation();
}
};
TypeAnnotation::TypeAnnotation()
: __operator(TypeOperator::NONE), __value(TypePrimitive::Invalid) {
}
TypeAnnotation::TypeAnnotation(TypePrimitive typ)
: __value(typ)
{}
TypeAnnotation::TypeAnnotation(TypeOperator op, std::initializer_list<TypeAnnotation> operands)
: __operator(op), __operands(operands) {
}
TypeAnnotation::TypeAnnotation(TypeOperator op, std::vector<TypeAnnotation>&& operands)
: __operator(op), __operands(operands) {
}
bool
TypeAnnotation::isValid() const {
return !(__value == TypePrimitive::Invalid && __operator == TypeOperator::NONE);
}
bool
TypeAnnotation::operator<(const TypeAnnotation& t) const {
if (__operator != t.__operator) return __operator < t.__operator;
if (__operator == TypeOperator::NONE)
return __value < t.__value;
if (__operator == TypeOperator::ALIAS || __operator == TypeOperator::ACCESS) {
if (__valueCustom != t.__valueCustom)
return __valueCustom < t.__valueCustom;
}
return __operands < t.__operands;
}
TypeAnnotation
TypeAnnotation::alias(const std::string& alias) {
TypeAnnotation aliasT(TypeOperator::ALIAS, {});
aliasT.__valueCustom = alias;
return aliasT;
}
void
TypeAnnotation::addBindings(std::vector<Atom<Identifier_t>>&& params) {
bindings.reserve(bindings.size() + params.size());
std::transform(params.begin(), params.end(), std::inserter(bindings, bindings.end()),
[](const Atom<Identifier_t>& ident) {
return ident.get(); });
}
void
TypeAnnotation::addFields(std::vector<Atom<Identifier_t>>&& listFields) {
fields.reserve(fields.size() + listFields.size());
std::transform(listFields.begin(), listFields.end(), std::inserter(fields, fields.end()),
[](const Atom<Identifier_t>& ident) {
return ident.get(); });
}
unsigned int Expression::nextVacantId = 0;
Expression::Expression(const Atom<Number_t>& number)
: Expression() {
__state = NUMBER;
op = Operator::INVALID;
__valueD = number.get();
}
Expression::Expression(const Atom<String_t>& a)
: Expression() {
__state = STRING;
op = Operator::INVALID;
__valueS = a.get();
}
Expression::Expression(const Atom<Identifier_t> &ident)
: Expression() {
__state = IDENT;
op = Operator::INVALID;
__valueS = ident.get();
}
Expression::Expression(const Operator &oprt, std::initializer_list<Expression> params)
: Expression() {
__state = COMPOUND;
op = oprt;
if (op == Operator::CALL) {
assert(params.size() > 0);
Expression arg = *params.begin();
assert(arg.__state == Expression::IDENT);
__valueS = std::move(arg.__valueS);
operands.insert(operands.end(), params.begin() + 1, params.end());
return;
}
operands.insert(operands.end(), params.begin(), params.end());
}
void
Expression::setOp(Operator oprt) {
op = oprt;
switch (op) {
case Operator::INVALID:
__state = INVALID;
break;
default:
__state = COMPOUND;
break;
}
}
void
Expression::addArg(Expression &&arg) {
operands.push_back(arg);
}
void
Expression::addTags(const std::list<Expression> tags) const {
std::transform(tags.begin(), tags.end(), std::inserter(this->tags, this->tags.end()),
[](const Expression & tag) {
return make_pair(tag.getValueString(), tag);
});
}
void
Expression::addBindings(std::initializer_list<Atom<Identifier_t>> params) {
addBindings(params.begin(), params.end());
}
void
Expression::bindType(TypeAnnotation t) {
type = move(t);
}
void
Expression::addBlock(ManagedScpPtr scope) {
blocks.push_back(scope.operator->());
}
const std::vector<Expression>&
Expression::getOperands() const {
return operands;
}
double
Expression::getValueDouble() const {
return __valueD;
}
const std::string&
Expression::getValueString() const {
return __valueS;
}
void
Expression::setValue(const Atom<Identifier_t>&& v) {
__valueS = v.get();
}
void Expression::setValueDouble(double value) {
__valueD = value;
}
bool
Expression::isValid() const {
return (__state != INVALID);
}
bool
Expression::isDefined() const {
return (__state != BINDING && __state != INVALID);
}
Expression::Expression()
: __state(INVALID), op(Operator::INVALID), id(nextVacantId++) {
}
namespace details { namespace inconsistent {
std::map<std::string, IntrinsicFn>
AST::__registryIntrinsics = {};
AST::AST() {
Attachments::init<versions::VariableVersion>();
Attachments::init<IdentifierSymbol>();
Attachments::init<ExprAlias_A>();
Attachments::init<TypeInferred>();
Attachments::init<ExprId_A>();
initIntrinsics();
analysis::PredefinedAnns man = analysis::PredefinedAnns::instance();
man.registerVariants(__registryVariants);
man.registerAliases(__registryTypes);
}
void
AST::addInterfaceData(const ASTInterface& interface, Expression&& data) {
__interfacesData.emplace(interface, move(data));
}
void
AST::addDFAData(Expression &&data) {
__dfadata.push_back(data);
}
void
AST::addExternData(ExternData &&entry) {
//__externdata.push_back(entry);
}
void
AST::add(Function* f) {
__functions.push_back(f);
__dictFunctions.emplace(f->getName(), __functions.size() - 1);
}
void
AST::add(MetaRuleAbstract *r) {
__rules.push_back(r);
}
void
AST::add(TypeAnnotation t, Atom<Identifier_t> alias) {
if (t.__operator == TypeOperator::VARIANT) {
for (int i = 0, size = t.fields.size(); i < size; ++i) {
__registryVariants.emplace(t.fields[i], make_pair(t, i));
}
}
__registryTypes.emplace(alias.get(), move(t));
}
ManagedScpPtr
AST::add(CodeScope* scope) {
this->__scopes.push_back(scope);
return ManagedScpPtr(this->__scopes.size() - 1, &this->__scopes);
}
std::string
AST::getModuleName() {
const std::string name = "main";
return name;
}
ManagedPtr<Function>
AST::findFunction(const std::string& name) {
int count = __dictFunctions.count(name);
if (!count) {
return ManagedFnPtr::Invalid();
}
assert(count == 1);
auto range = __dictFunctions.equal_range(name);
return ManagedPtr<Function>(range.first->second, &this->__functions);
}
std::list<ManagedFnPtr>
AST::getAllFunctions() const {
const size_t size = __functions.size();
std::list<ManagedFnPtr> result;
for (size_t i = 0; i < size; ++i) {
result.push_back(ManagedFnPtr(i, &this->__functions));
}
return result;
}
//TASK select default specializations
std::list<ManagedFnPtr>
AST::getFnSpecializations(const std::string& fnName) const {
auto functions = __dictFunctions.equal_range(fnName);
std::list<ManagedFnPtr> result;
std::transform(functions.first, functions.second, inserter(result, result.end()),
[this](auto f) {
return ManagedFnPtr(f.second, &this->__functions);
});
return result;
}
template<>
ManagedPtr<Function>
AST::begin<Function>() {
return ManagedPtr<Function>(0, &this->__functions);
}
template<>
ManagedPtr<CodeScope>
AST::begin<CodeScope>() {
return ManagedPtr<CodeScope>(0, &this->__scopes);
}
template<>
ManagedPtr<MetaRuleAbstract>
AST::begin<MetaRuleAbstract>() {
return ManagedPtr<MetaRuleAbstract>(0, &this->__rules);
}
void
AST::recognizeIntrinsic(Expression& fn) const {
assert(fn.op == Operator::CALL_INTRINSIC);
if (!__registryIntrinsics.count(fn.getValueString())){
assert(false);
}
IntrinsicFn fnCode = __registryIntrinsics.at(fn.getValueString());
fn.op = Operator::CALL_INTRINSIC;
fn.setValueDouble((int) fnCode);
}
bool
AST::recognizeVariantConstructor(Expression& function) {
assert(function.op == Operator::CALL);
std::string variant = function.getValueString();
if (!__registryVariants.count(variant)) {
return false;
}
auto record = __registryVariants.at(variant);
const TypeAnnotation& typ = record.first;
function.op = Operator::VARIANT;
function.setValueDouble(record.second);
function.type = typ;
return true;
}
Atom<Number_t>
AST::recognizeVariantConstructor(Atom<Identifier_t> ident) {
std::string variant = ident.get();
assert(__registryVariants.count(variant) && "Can't recognize variant constructor");
auto record = __registryVariants.at(variant);
return Atom<Number_t>(record.second);
}
void
AST::postponeIdentifier(CodeScope* scope, const Expression& id) {
__bucketUnrecognizedIdentifiers.emplace(scope, id);
}
void
AST::recognizePostponedIdentifiers() {
for (const auto& identifier : __bucketUnrecognizedIdentifiers) {
if (!identifier.first->recognizeIdentifier(identifier.second)) {
//exception: Ident not found
std::cout << "Unknown identifier: " << identifier.second.getValueString() << std::endl;
assert(false && "Unknown identifier");
}
}
}
xreate::AST*
AST::finalize() {
//all finalization steps:
recognizePostponedIdentifiers();
return reinterpret_cast<xreate::AST*> (this);
}
void
AST::initIntrinsics(){
if (__registryIntrinsics.size()) return;
__registryIntrinsics = {
{"array_init", IntrinsicFn::ARR_INIT},
- {"rec_fields", IntrinsicFn::REC_FIELDS}
+ {"fields", IntrinsicFn::REC_FIELDS},
+ {"keys", IntrinsicFn::CON_KEYS}
};
}
} } //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& identE) {
versions::VariableVersion version = Attachments::get<versions::VariableVersion>(identE, versions::VERSION_NONE);
const std::string& identStr = identE.getValueString();
//search identifier in the current block
if (__identifiers.count(identStr)) {
VNameId id = __identifiers.at(identStr);
Symbol identS;
identS.identifier = ScopedSymbol{id, version};
identS.scope = const_cast<CodeScope*> (this);
Attachments::put<IdentifierSymbol>(identE, identS);
return true;
}
//search in the parent scope
bool result = false;
if (__parent) {
result = __parent->recognizeIdentifier(identE);
}
if (trackExternalSymbs && result){
Symbol identS = Attachments::get<IdentifierSymbol>(identE);
boundExternalSymbs.insert(identS);
}
return result;
}
ScopedSymbol
CodeScope::findSymbolByAlias(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);
+ 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 db518d6..20f7ea9 100644
--- a/cpp/src/ast.h
+++ b/cpp/src/ast.h
@@ -1,754 +1,755 @@
/* 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;
bool trackExternalSymbs = false;
std::set<Symbol> boundExternalSymbs;
private:
ScopedSymbol registerIdentifier(const Expression& identifier, const VNameId hintBindingId = 0);
public:
bool recognizeIdentifier(const Expression& identE);
ScopedSymbol findSymbolByAlias(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
+ REC_FIELDS,
+ CON_KEYS
};
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/aux/latereasoning.h b/cpp/src/aux/latereasoning.h
index e6ba460..457456d 100644
--- a/cpp/src/aux/latereasoning.h
+++ b/cpp/src/aux/latereasoning.h
@@ -1,91 +1,91 @@
/*
* 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 2, 2018, 1:08 PM
*/
/**
* \file src/aux/latereasoning.h
* \brief Late reasoning support
*/
#ifndef LATEREASONING_H
#define LATEREASONING_H
#include "transcendlayer.h"
namespace xreate{ namespace latereasoning{
/** \brief Represents Late Annotation, i.e. an annotation with late or runtime defined parameters*/
struct LateAnnotation{
LateAnnotation(){}
LateAnnotation(const Gringo::Symbol& symbolStatic);
std::list<std::pair<std::list<Gringo::Symbol>, Gringo::Symbol>> guardedContent;
std::list<SymbolPacked> guardKeys;
boost::optional<Gringo::Symbol> select(const std::list<Expression>& keys, AST* root, TranscendLayer* transcend) const;
};
/** \brief Represents a group of all late annotations attached to a specific target */
struct LateAnnotationsGroup{
std::unordered_map<Gringo::Symbol, LateAnnotation> annotations;
};
typedef std::map<Gringo::Symbol, LateAnnotation> LateModel;
/**
* \brief Decorates \ref TranscendLayer to support late annotations processing
* \extends TranscendLayer
*/
template<class Parent>
class LateReasoningTranscendDecorator: public Parent{
public:
const LateAnnotationsGroup& queryLate(const std::string& alias) const{
static LateAnnotationsGroup groupInvalid;
if(!__modelLate.count(alias)) return groupInvalid;
return __modelLate.at(alias);
}
protected:
virtual bool processSolution(Gringo::Model const &model) override{
const std::string& atomLateStatement = "late";
for(const Gringo::Symbol& atom: model.atoms(clingo_show_type_atoms)){
std::string atomName(atom.name().c_str());
if(atomName == atomLateStatement){
//late atom's format: (Target, (tuple of keys), (tuple of values), late-annotation)
auto atomLate = TranscendLayer::parse<Gringo::Symbol, std::list<SymbolPacked>, std::list<Gringo::Symbol>, Gringo::Symbol>(atom);
- const std::string& atomAlias = std::get<3>(atomLate).name().c_str();
+ std::string atomAlias = std::get<3>(atomLate).name().c_str();
addLateAtom(atomAlias, std::get<0>(atomLate),
std::get<3>(atomLate), std::get<1>(atomLate),
std::get<2>(atomLate));
}
}
return Parent::processSolution(model);
}
private:
std::map<std::string, LateAnnotationsGroup> __modelLate;
void addLateAtom(const std::string& alias, const Gringo::Symbol& annId,
const Gringo::Symbol& content, const std::list<SymbolPacked>& guardKeys,
const std::list<Gringo::Symbol>& guardValues){
LateAnnotationsGroup& group = __modelLate[alias];
LateAnnotation& annotation = group.annotations[annId];
if (annotation.guardedContent.empty()){
annotation.guardKeys = guardKeys;
}
annotation.guardedContent.push_back(std::make_pair(guardValues, content));
}
};
}} // end of xreate::latereasoning
#endif /* LATEREASONING_H */
diff --git a/cpp/src/compilation/containers.cpp b/cpp/src/compilation/containers.cpp
index f0882b2..f71c4fd 100644
--- a/cpp/src/compilation/containers.cpp
+++ b/cpp/src/compilation/containers.cpp
@@ -1,368 +1,374 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: containers.cpp
* Author: pgess <v.melnychenko@xreate.org>
*/
/**
* \file compilation/containers.h
* \brief Containers compilation support. See [Containers](/d/concepts/containers/) in the Xreate's documentation.
*/
#include "compilation/containers.h"
#include "compilation/targetinterpretation.h"
#include "aux/expressions.h"
#include "compilation/containers/arrays.h"
#include "compilation/lambdas.h"
#include "analysis/predefinedanns.h"
#include "analysis/utils.h"
using namespace std;
namespace xreate { namespace containers{
ImplementationType
IContainersIR::getImplementation(const Expression& aggrE, AST* ast){
auto manPredefined = analysis::PredefinedAnns::instance();
const Expression& hintE = analysis::findAnnByType(aggrE, ExpandedType(manPredefined.hintsContT), ast);
assert(hintE.isValid());
return (ImplementationType ) hintE.getValueDouble();
}
IContainersIR *
IContainersIR::create(const Expression &aggrE, const TypeAnnotation &expectedT, const compilation::Context &context){
ExpandedType aggrT = context.pass->man->root->getType(aggrE, expectedT);
Expression aggr2E;
if (aggrE.__state == Expression::IDENT && !aggrE.tags.size()){
Symbol aggrS = Attachments::get<IdentifierSymbol>(aggrE);
aggr2E = CodeScope::getDefinition(aggrS);
} else {
aggr2E = aggrE;
}
switch(aggr2E.op){
case Operator::LIST:{
typehints::ArrayHint aggrHint = typehints::find(
aggr2E, typehints::ArrayHint{aggr2E.operands.size()}
);
return new ArrayIR(aggrT, aggrHint, context);
}
default:
typehints::ArrayHint aggrHint = typehints::find(
aggr2E, typehints::ArrayHint{0}
);
assert(aggrHint.size != 0);
return new ArrayIR(aggrT, aggrHint, context);
}
assert(false);
return nullptr;
}
llvm::Type*
IContainersIR::getRawType(const Expression& aggrE, const ExpandedType& aggrT, LLVMLayer* llvm){
auto manPredefined = analysis::PredefinedAnns::instance();
const Expression& hintE = analysis::findAnnByType(aggrE, ExpandedType(manPredefined.hintsContT), llvm->ast);
assert(hintE.isValid());
return getRawTypeByHint(hintE, aggrT, llvm);
}
llvm::Type*
IContainersIR::getRawTypeByHint(const Expression& hintE, const ExpandedType& aggrT, LLVMLayer* llvm) {
ImplementationType hintImpl = (ImplementationType ) hintE.getValueDouble();
switch (hintImpl){
case SOLID: {
typehints::ArrayHint hint = typehints::parse<typehints::ArrayHint>(hintE);
return ArrayIR::getRawType(aggrT, hint, llvm);
}
case ON_THE_FLY:{
typehints::FlyHint hint = typehints::parse<typehints::FlyHint>(hintE);
return FlyIR::getRawType(aggrT, hint, llvm);
}
case RANGE: {
return RangeIR::getRawType(aggrT, llvm);
}
}
assert(false);
return nullptr;
}
llvm::Value *
RecordIR::init(llvm::StructType *tyAggr){
return llvm::UndefValue::get(tyAggr);
}
llvm::Value*
RecordIR::init(std::forward_list<llvm::Type*> fields){
std::vector<llvm::Type*> fieldsVec(fields.begin(), fields.end());
llvm::ArrayRef<llvm::Type *> fieldsArr(fieldsVec);
llvm::StructType* resultTR = llvm::StructType::get(__context.pass->man->llvm->llvmContext, fieldsArr, false);
return init(resultTR);
}
llvm::Value *
RecordIR::update(llvm::Value *aggrRaw, const ExpandedType &aggrT, const Expression &updE){
interpretation::InterpretationScope *scopeI12n =
__context.pass->targetInterpretation->transformContext(__context);
TypesHelper helper(__context.pass->man->llvm);
const auto &fields = helper.getRecordFields(aggrT);
std::map<std::string, size_t> indexFields;
for(size_t i = 0, size = fields.size(); i < size; ++i){
indexFields.emplace(fields[i], i);
}
for(const auto &entry: reprListAsDict(updE)){
unsigned keyId;
std::string keyHint;
const Expression keyE = scopeI12n->process(entry.first);
switch(keyE.__state){
case Expression::STRING:
keyId = indexFields.at(keyE.getValueString());
keyHint = keyE.getValueString();
break;
case Expression::NUMBER:
keyId = keyE.getValueDouble();
keyHint = aggrT->fields.at(keyId);
break;
default:
assert(false);
break;
}
const TypeAnnotation &valueT = aggrT->__operands.at(keyId);
llvm::Value *valueRaw = __context.scope->process(entry.second, keyHint, valueT);
aggrRaw = __context.pass->man->llvm->irBuilder.CreateInsertValue(
aggrRaw,
valueRaw,
keyId);
}
return aggrRaw;
}
llvm::Value*
FlyIR::init(llvm::Value* sourceRaw, CodeScope* body, const std::string& hintAlias){
RecordIR recordIR(__context);
compilation::LambdaIR lambdaIR(__context.pass);
llvm::Function* fnTransform = lambdaIR.compile(body, hintAlias);
llvm::Value* resultRaw = recordIR.init({
sourceRaw->getType(),
fnTransform->getFunctionType()->getPointerTo()
});
resultRaw = __context.pass->man->llvm->irBuilder.CreateInsertValue(
resultRaw, sourceRaw, 0);
resultRaw = __context.pass->man->llvm->irBuilder.CreateInsertValue(
resultRaw, fnTransform, 1);
return resultRaw;
}
llvm::Type*
FlyIR::getRawType(const ExpandedType& aggrT, const typehints::FlyHint& hint, LLVMLayer* llvm){
assert(aggrT->__operator == TypeOperator::ARRAY);
TypesHelper types(llvm);
llvm::Type* sourceTRaw = IContainersIR::getRawTypeByHint(hint.hintSrc, aggrT, llvm);
llvm::Type* elTRaw = llvm->toLLVMType(ExpandedType(aggrT->__operands.at(0)));
llvm::Type* resultTRaw = types.getPreferredIntTy();
llvm::Type* fnTnsfTRaw = llvm::FunctionType::get(resultTRaw, llvm::ArrayRef<llvm::Type*>(elTRaw), false);
std::vector<llvm::Type*> fieldsVec = {
sourceTRaw,
fnTnsfTRaw->getPointerTo()
};
llvm::ArrayRef<llvm::Type *> fieldsArr(fieldsVec);
llvm::StructType* resultTR = llvm::StructType::get(llvm->llvmContext, fieldsArr, false);
return resultTR;
}
llvm::Value*
FlyIR::getTransformFn(llvm::Value* aggrRaw){
LLVMLayer* llvm = __context.pass->man->llvm;
llvm::Value* fnRaw = llvm->irBuilder.CreateExtractValue(aggrRaw, llvm::ArrayRef<unsigned>{1});
return fnRaw;
}
llvm::Value*
FlyIR::getSourceAggr(llvm::Value* aggrRaw){
LLVMLayer* llvm = __context.pass->man->llvm;
return llvm->irBuilder.CreateExtractValue(aggrRaw, llvm::ArrayRef<unsigned>{0});
}
llvm::Value*
FlyIR::operatorMap(const Expression& expr, const std::string& hintAlias){
const Expression& sourceE = expr.getOperands().at(0);
llvm::Value* sourceRaw = __context.scope->process(sourceE);
CodeScope* loopS = expr.blocks.front();
return init(sourceRaw, loopS, hintAlias);
}
FlyIR::FlyIR(typehints::FlyHint hint, compilation::Context context)
: __hint(hint), __context(context){}
IFwdIteratorIR*
IFwdIteratorIR::createByHint(const Expression& hintE, const ExpandedType& aggrT, const compilation::Context& context){
ImplementationType hintType = (ImplementationType) hintE.getValueDouble();
switch(hintType){
case SOLID:{
ArrayIR compiler(aggrT, typehints::parse<typehints::ArrayHint>(hintE), context);
return new FwdIteratorIR<SOLID>(compiler);
}
case ON_THE_FLY:{
return new FwdIteratorIR<ON_THE_FLY>(typehints::parse<typehints::FlyHint>(hintE), aggrT, context);
}
case RANGE: {
return new FwdIteratorIR<RANGE>(context);
}
default: break;
}
assert(false);
return nullptr;
}
IFwdIteratorIR*
IFwdIteratorIR::create(const Expression& aggrE, const ExpandedType& aggrT, const compilation::Context& context){
auto manPredefined = analysis::PredefinedAnns::instance();
const Expression& hintE = analysis::findAnnByType(
aggrE,
ExpandedType(manPredefined.hintsContT),
context.pass->man->root
);
assert(hintE.isValid());
return createByHint(hintE, aggrT, context);
}
llvm::Value*
FwdIteratorIR<ON_THE_FLY>::begin(llvm::Value* aggrRaw) {
std::unique_ptr<IFwdIteratorIR> itSrcIR(IFwdIteratorIR::createByHint(__hint.hintSrc, __aggrT, __context));
FlyIR compilerFly(__hint, __context);
llvm::Value* aggrSrcRaw = compilerFly.getSourceAggr(aggrRaw);
return itSrcIR->begin(aggrSrcRaw);
}
llvm::Value*
FwdIteratorIR<ON_THE_FLY>::end(llvm::Value* aggrRaw) {
std::unique_ptr<IFwdIteratorIR> itSrcIR(IFwdIteratorIR::createByHint(__hint.hintSrc, __aggrT, __context));
FlyIR compilerFly(__hint, __context);
llvm::Value* aggrSrcRaw = compilerFly.getSourceAggr(aggrRaw);
return itSrcIR->end(aggrSrcRaw);
}
llvm::Value*
FwdIteratorIR<ON_THE_FLY>::advance(llvm::Value* idxRaw, const std::string& hintAlias){
std::unique_ptr<IFwdIteratorIR> itSrcIR(IFwdIteratorIR::createByHint(__hint.hintSrc, __aggrT, __context));
return itSrcIR->advance(idxRaw, hintAlias);
}
llvm::Value*
FwdIteratorIR<ON_THE_FLY>::get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintAlias){
std::unique_ptr<IFwdIteratorIR> srcIterIR(IFwdIteratorIR::createByHint(__hint.hintSrc, __aggrT, __context));
FlyIR compilerFly(__hint, __context);
llvm::Value* aggrSrcRaw = compilerFly.getSourceAggr(aggrRaw);
llvm::Value* valueSrcRaw = srcIterIR->get(aggrSrcRaw, idxRaw);
FlyIR flyIR(__hint, __context);
llvm::Value* fnTnsfRaw = flyIR.getTransformFn(aggrRaw);
llvm::Type* fnTnsfTRawRaw = llvm::cast<llvm::PointerType>(fnTnsfRaw->getType())->getElementType();
llvm::FunctionType* fnTnsfTRaw = llvm::cast<llvm::FunctionType>(fnTnsfTRawRaw);
compilation::BruteFnInvocation fnTnsfInvoc(fnTnsfRaw, fnTnsfTRaw, __context.pass->man->llvm);
return fnTnsfInvoc({valueSrcRaw}, hintAlias);
}
llvm::Value*
-RangeIR::init(const Expression& aggrE, const ExpandedType& aggrT, const std::string& hintAlias){
- assert(aggrE.op == Operator::LIST_RANGE);
- assert(aggrE.operands.size()==2);
-
+RangeIR::create(const ExpandedType& aggrT, llvm::Value* valueFromRaw, llvm::Value* valueToRaw){
RecordIR recordIR(__context);
LLVMLayer* llvm = __context.pass->man->llvm;
llvm::Value* aggrRaw = recordIR.init(getRawType(aggrT, llvm));
- llvm::Value* valueFromRaw = __context.scope->process(aggrE.operands.at(0));
- llvm::Value* valueToRaw = __context.scope->process(aggrE.operands.at(1));
aggrRaw = llvm->irBuilder.CreateInsertValue(aggrRaw, valueFromRaw, 0);
aggrRaw = llvm->irBuilder.CreateInsertValue(aggrRaw, valueToRaw, 1);
return aggrRaw;
}
+llvm::Value*
+RangeIR::init(const Expression& aggrE, const ExpandedType& aggrT, const std::string& hintAlias){
+ assert(aggrE.op == Operator::LIST_RANGE);
+ assert(aggrE.operands.size()==2);
+
+ llvm::Value* valueFromRaw = __context.scope->process(aggrE.operands.at(0));
+ llvm::Value* valueToRaw = __context.scope->process(aggrE.operands.at(1));
+
+ return create(aggrT, valueFromRaw, valueToRaw);
+}
+
llvm::Value*
RangeIR::getValueFrom(llvm::Value* aggrRaw){
LLVMLayer* llvm = __context.pass->man->llvm;
return llvm->irBuilder.CreateExtractValue(aggrRaw, llvm::ArrayRef<unsigned>{0});
}
llvm::Value*
RangeIR::getValueTo(llvm::Value* aggrRaw){
LLVMLayer* llvm = __context.pass->man->llvm;
return llvm->irBuilder.CreateExtractValue(aggrRaw, llvm::ArrayRef<unsigned>{1});
}
llvm::StructType*
RangeIR::getRawType(const ExpandedType& aggrT, LLVMLayer* llvm){
assert(aggrT->__operator == TypeOperator::ARRAY);
ExpandedType elT(aggrT->__operands.at(0));
llvm::Type* elRawT = llvm->toLLVMType(elT);
std::vector<llvm::Type*> fieldsVec = {elRawT, elRawT};
llvm::ArrayRef<llvm::Type *> fieldsArr(fieldsVec);
llvm::StructType* rangeRawT = llvm::StructType::get(llvm->llvmContext, fieldsArr, false);
return rangeRawT;
}
llvm::Value*
FwdIteratorIR<RANGE>::begin(llvm::Value* aggrRaw){
RangeIR compiler(__context);
return compiler.getValueFrom(aggrRaw);
}
llvm::Value*
FwdIteratorIR<RANGE>::end(llvm::Value* aggrRaw){
RangeIR compiler(__context);
return compiler.getValueTo(aggrRaw);
}
llvm::Value*
FwdIteratorIR<RANGE>::get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintAlias){
return idxRaw;
}
llvm::Value*
FwdIteratorIR<RANGE>::advance(llvm::Value* idxRaw, const std::string& hintAlias) {
LLVMLayer* llvm = __context.pass->man->llvm;
TypesHelper types(llvm);
llvm::Type* intT = types.getPreferredIntTy();
return llvm->irBuilder.CreateAdd(idxRaw, llvm::ConstantInt::get(intT, 1), hintAlias);
}
}} //end of xreate::containers
diff --git a/cpp/src/compilation/containers.h b/cpp/src/compilation/containers.h
index 40d73b9..1c919ed 100644
--- a/cpp/src/compilation/containers.h
+++ b/cpp/src/compilation/containers.h
@@ -1,140 +1,141 @@
/* 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);
+ virtual ~IContainersIR(){}
static ImplementationType getImplementation(const Expression& aggrE, AST* ast);
static llvm::Type* getRawType(const Expression& aggrE, const ExpandedType& aggrT, LLVMLayer* llvm);
static llvm::Type* getRawTypeByHint(const Expression& hintE, const ExpandedType& aggrT, LLVMLayer* llvm);
- virtual llvm::Value *init(const std::string &hintAlias = "") = 0;
- virtual llvm::Value *update(llvm::Value *aggrRaw, const Expression &updE, const std::string &hintAlias) = 0;
virtual IFwdIteratorIR* getFwdIterator() = 0;
- virtual ~IContainersIR(){}
+ 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 llvm::Value* keys(llvm::Value* aggrRaw, const std::string &hintAlias = "") { return nullptr; }
};
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;
};
/**
* \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(llvm::Value* aggrRaw) = 0;
virtual llvm::Value* end(llvm::Value* aggrRaw) = 0;
virtual llvm::Value* get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintAlias="") = 0;
virtual llvm::Value* advance(llvm::Value* idxRaw, const std::string& hintAlias="") = 0;
static IFwdIteratorIR* create(const Expression& aggrE, const ExpandedType& aggrT, const compilation::Context& context);
static IFwdIteratorIR* createByHint(const Expression& hintE, const ExpandedType& aggrT, const compilation::Context& context);
};
template<ImplementationType I>
class FwdIteratorIR;
class FlyIR{
public:
FlyIR(typehints::FlyHint hint, compilation::Context context);
llvm::Value* init(llvm::Value* sourceRaw, CodeScope* body, const std::string& hintAlias);
llvm::Value* getSourceAggr(llvm::Value* aggrRaw);
llvm::Value* getTransformFn(llvm::Value* aggrRaw);
llvm::Value* operatorMap(const Expression& expr, const std::string& hintAlias);
static llvm::Type *getRawType(const ExpandedType& aggrT, const typehints::FlyHint& hint, LLVMLayer* llvm);
private:
typehints::FlyHint __hint;
compilation::Context __context;
};
/** \brief The lazy container implementation.
*
* Represents computation on the fly.
* \sa xreate::containers::IFwdIteratorIR, \sa xreate::containers::Query
*/
template<>
class FwdIteratorIR<ON_THE_FLY> : public IFwdIteratorIR {
public:
FwdIteratorIR<ON_THE_FLY>(typehints::FlyHint hint, const ExpandedType &aggrT, compilation::Context context)
: __aggrT(aggrT), __hint(hint), __context(context){}
virtual llvm::Value* begin(llvm::Value* aggrRaw) override;
virtual llvm::Value* end(llvm::Value* aggrRaw) override;
virtual llvm::Value* get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintAlias="") override;
virtual llvm::Value* advance(llvm::Value* idxRaw, const std::string& hintAlias="") override;
private:
ExpandedType __aggrT;
typehints::FlyHint __hint;
compilation::Context __context;
};
class RangeIR{
public:
RangeIR(const compilation::Context& ctx): __context(ctx){}
llvm::Value* getValueFrom(llvm::Value* aggrRaw);
llvm::Value* getValueTo(llvm::Value* aggrRaw);
static llvm::StructType* getRawType(const ExpandedType& aggrT, LLVMLayer* llvm);
llvm::Value* init(const Expression& aggrE, const ExpandedType& aggrT, const std::string& hintAlias="");
-
+ llvm::Value* create(const ExpandedType& aggrT, llvm::Value* valueFromRaw, llvm::Value* valueToRaw);
private:
compilation::Context __context;
};
template<>
class FwdIteratorIR<RANGE>: public IFwdIteratorIR {
public:
FwdIteratorIR<RANGE>(compilation::Context ctx): __context(ctx){}
virtual llvm::Value* begin(llvm::Value* aggrRaw) override;
virtual llvm::Value* end(llvm::Value* aggrRaw) override;
virtual llvm::Value* get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintAlias="") override;
virtual llvm::Value* advance(llvm::Value* idxRaw, const std::string& hintAlias="") override;
private:
compilation::Context __context;
};
}} //end of xreate::containers
#endif //CODEINSTRUCTIONS_H
diff --git a/cpp/src/compilation/containers/arrays.cpp b/cpp/src/compilation/containers/arrays.cpp
index b0c03f2..5cd0ce7 100644
--- a/cpp/src/compilation/containers/arrays.cpp
+++ b/cpp/src/compilation/containers/arrays.cpp
@@ -1,167 +1,179 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: arrays.cpp
* Author: pgess <v.melnychenko@xreate.org>
*
* Created in March 2020.
*/
#include "compilation/containers/arrays.h"
#include "aux/expressions.h"
using namespace std;
using namespace llvm;
namespace xreate { namespace containers{
llvm::PointerType*
ArrayIR::getRawType(const ExpandedType& aggrT, const typehints::ArrayHint& hint, LLVMLayer* llvm){
assert(aggrT->__operator == TypeOperator::ARRAY);
assert(aggrT->__operands.size() == 1);
llvm::Type* elRawT = llvm->toLLVMType(ExpandedType(aggrT->__operands.at(0)));
return llvm::ArrayType::get(elRawT, hint.size)->getPointerTo();
}
llvm::Value*
ArrayIR::init(const string& hintAlias){
LLVMLayer* llvm = __context.pass->man->llvm;
TypesHelper helper(llvm);
llvm::PointerType* aggrRawT = getRawType(__aggrT, __hint, __context.pass->man->llvm);
//llvm::Value* aggrLengthRaw = ConstantInt::get(helper.getPreferredIntTy(), aggrInfo.size);
llvm::Value* aggrRaw = llvm->irBuilder.CreateAlloca(aggrRawT->getElementType(), nullptr, hintAlias);
return aggrRaw;
}
llvm::Value*
ArrayIR::update(llvm::Value* aggrRaw, const Expression& updE, const std::string& hintAlias) {
LLVMLayer* llvm = __context.pass->man->llvm;
TypesHelper helper(llvm);
llvm::IntegerType* intT = helper.getPreferredIntTy();
llvm::Value* idxZeroRaw = ConstantInt::get(intT, 0);
llvm::PointerType* aggrRawT = getRawType(__aggrT, __hint, __context.pass->man->llvm);
const TypeAnnotation& elT = __aggrT->__operands.at(0);
//llvm::Type* elTRaw = llvm->toLLVMType(ExpandedType(aggrT->__operands.at(0)));
for (const auto& entry: reprListAsDict(updE)){
llvm::Value* keyRaw = __context.scope->process(entry.first);
llvm::Value* elRaw = __context.scope->process(entry.second, "", elT);
llvm::Value* elLoc = llvm->irBuilder.CreateGEP(
aggrRawT->getElementType(), aggrRaw, ArrayRef<llvm::Value*>(std::vector<Value*>{idxZeroRaw, keyRaw}));
llvm->irBuilder.CreateStore(elRaw, elLoc) ;
}
return aggrRaw;
}
llvm::Value*
ArrayIR::get(llvm::Value* aggrRaw, std::vector<llvm::Value *> idxL, const std::string& hintAlias) {
LLVMLayer* llvm = __context.pass->man->llvm;
TypesHelper helper(llvm);
llvm::IntegerType* intT = helper.getPreferredIntTy();
llvm::Value* zeroRaw = ConstantInt::get(intT, 0);
idxL.insert(idxL.begin(), zeroRaw);
llvm::Value *pEl = llvm->irBuilder.CreateGEP(aggrRaw, llvm::ArrayRef<llvm::Value *>(idxL));
return llvm->irBuilder.CreateLoad(pEl, hintAlias);
}
llvm::Value*
ArrayIR::operatorMap(const Expression& expr, const std::string& hintAlias) {
assert(false); return nullptr;
//EXPAND_CONTEXT UNUSED(scope);
// //initializationcompileListAsSolidArray
// Symbol symbolIn = Attachments::get<IdentifierSymbol>(expr.getOperands()[0]);
//
// ImplementationRec<SOLID> implIn = containers::Query::queryImplementation(symbolIn).extract<SOLID>(); // impl of input list
// size_t size = implIn.size;
// CodeScope* scopeLoop = expr.blocks.front();
// std::string varEl = scopeLoop->__bindings[0];
//
// IFwdIteratorIR* it = IFwdIteratorIR::create(context, symbolIn);
// llvm::Value *rangeFrom = it->begin();
// llvm::Value *rangeTo = it->end();
//
// //definitions
// ArrayType* tyNumArray = nullptr; //(ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::Int, size))));
// llvm::IRBuilder<> &builder = llvm->irBuilder;
//
// llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm->llvmContext, "loop", function->raw);
// llvm::BasicBlock *blockBeforeLoop = builder.GetInsertBlock();
// llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm->llvmContext, "postloop", function->raw);
// Value* dataOut = llvm->irBuilder.CreateAlloca(tyNumArray, ConstantInt::get(tyNum, size), NAME("map"));
//
// // * initial check
// Value* condBefore = builder.CreateICmpSLE(rangeFrom, rangeTo);
// builder.CreateCondBr(condBefore, blockLoop, blockAfterLoop);
//
// // create PHI:
// builder.SetInsertPoint(blockLoop);
// llvm::PHINode *stateLoop = builder.CreatePHI(tyNum, 2, "mapIt");
// stateLoop->addIncoming(rangeFrom, blockBeforeLoop);
//
// // loop body:
// Value* elIn = it->get(stateLoop, varEl);
// compilation::IBruteScope* scopeLoopUnit = function->getBruteScope(scopeLoop);
// scopeLoopUnit->bindArg(elIn, move(varEl));
// Value* elOut = scopeLoopUnit->compile();
// Value *pElOut = builder.CreateGEP(dataOut, ArrayRef<Value *>(std::vector<Value*>{ConstantInt::get(tyNum, 0), stateLoop}));
// builder.CreateStore(elOut, pElOut);
//
// //next iteration preparing
// Value *stateLoopNext = builder.CreateAdd(stateLoop, llvm::ConstantInt::get(tyNum, 1));
// stateLoop->addIncoming(stateLoopNext, builder.GetInsertBlock());
//
// //next iteration checks:
// Value* condAfter = builder.CreateICmpSLE(stateLoopNext, rangeTo);
// builder.CreateCondBr(condAfter, blockLoop, blockAfterLoop);
//
// //finalization:
// builder.SetInsertPoint(blockAfterLoop);
//
// return dataOut;
}
+llvm::Value*
+ArrayIR::keys(llvm::Value* aggrRaw, const std::string &hintAlias){
+ TypesHelper helper(__context.pass->man->llvm);
+ RangeIR compiler(__context);
+
+ llvm::Type* intRawT = helper.getPreferredIntTy();
+ llvm::Value* keyBeginRaw = llvm::ConstantInt::get(intRawT, 0);
+ llvm::Value* keyEndRaw = llvm::ConstantInt::get(intRawT, __hint.size);
+
+ return compiler.create(__aggrT, keyBeginRaw, keyEndRaw);
+}
+
IFwdIteratorIR* ArrayIR::getFwdIterator(){
return new FwdIteratorIR<SOLID>(*this);
}
llvm::Value *
FwdIteratorIR<SOLID>::begin(llvm::Value* aggrRaw){
TypesHelper helper(__compiler.__context.pass->man->llvm);
llvm::IntegerType* intT = helper.getPreferredIntTy();
return llvm::ConstantInt::get(intT, 0);
}
llvm::Value *
FwdIteratorIR<SOLID>::end(llvm::Value* aggrRaw){
TypesHelper helper(__compiler.__context.pass->man->llvm);
llvm::IntegerType* intT = helper.getPreferredIntTy();
size_t size = __compiler.__hint.size;
return llvm::ConstantInt::get(intT, size);
}
llvm::Value *
FwdIteratorIR<SOLID>::get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintAlias){
return __compiler.get(aggrRaw, {idxRaw}, hintAlias);
}
llvm::Value *
FwdIteratorIR<SOLID>::advance(llvm::Value *idxRaw, const std::string &hintAlias){
LLVMLayer* llvm = __compiler.__context.pass->man->llvm;
TypesHelper helper(llvm);
llvm::IntegerType* intT = helper.getPreferredIntTy();
llvm::Value* cnstOneRaw = llvm::ConstantInt::get(intT, 1);
return llvm->irBuilder.CreateAdd(idxRaw, cnstOneRaw, hintAlias);
}
}} //xreate::containers
\ No newline at end of file
diff --git a/cpp/src/compilation/containers/arrays.h b/cpp/src/compilation/containers/arrays.h
index f8aa251..77c6586 100644
--- a/cpp/src/compilation/containers/arrays.h
+++ b/cpp/src/compilation/containers/arrays.h
@@ -1,63 +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: arrays.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created in March 2020.
*/
#ifndef XREATE_ARRAYSIR_H
#define XREATE_ARRAYSIR_H
#include "compilation/containers.h"
namespace xreate { namespace containers{
class IFwdIteratorIR;
/** \brief The contiguous container implementation.
*
* Represents contiguous in memory(array) implementation.
* \sa xreate::containers::IFwdIteratorIR, \sa xreate::containers::Query
*/
class ArrayIR : public IContainersIR{
friend class FwdIteratorIR<SOLID>;
public:
ArrayIR(const ExpandedType &aggrT, const typehints::ArrayHint &hints, const compilation::Context &context)
: __context(context), __aggrT(aggrT), __hint(hints){}
virtual llvm::Value *init(const std::string &hintAlias = "") override;
virtual llvm::Value *update(llvm::Value *aggrRaw, const Expression &updE, const std::string &hintAlias) override;
- virtual IFwdIteratorIR* getFwdIterator() override;
+ virtual llvm::Value* keys(llvm::Value* aggrRaw, const std::string &hintAlias = "") override;
+
llvm::Value *get(llvm::Value *aggrRaw, std::vector<llvm::Value *> idxL, const std::string &hintAlias);
+ virtual IFwdIteratorIR* getFwdIterator() override;
static llvm::PointerType *getRawType(const ExpandedType& aggrT, const typehints::ArrayHint& hint, LLVMLayer* llvm);
/** \brief `loop map` statement compilation*/
llvm::Value* operatorMap(const Expression& expr, const std::string& hintAlias);
private:
compilation::Context __context;
ExpandedType __aggrT;
typehints::ArrayHint __hint;
};
template<>
class FwdIteratorIR<SOLID>: public IFwdIteratorIR {
public:
FwdIteratorIR(const ArrayIR& arraysIR): __compiler(arraysIR) {};
virtual llvm::Value* begin(llvm::Value* aggrRaw) override;
virtual llvm::Value* end(llvm::Value* aggrRaw) override;
virtual llvm::Value* get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintAlias="") override;
virtual llvm::Value* advance(llvm::Value* idxRaw, const std::string& hintAlias="") override;
private:
ArrayIR __compiler;
};
}} // xreate::containers
#endif //XREATE_ARRAYSIR_H
diff --git a/cpp/src/compilation/intrinsics.cpp b/cpp/src/compilation/intrinsics.cpp
index c8582ba..1ca85b6 100644
--- a/cpp/src/compilation/intrinsics.cpp
+++ b/cpp/src/compilation/intrinsics.cpp
@@ -1,58 +1,75 @@
//March 2020
#include "compilation/intrinsics.h"
+#include "compilation/containers.h"
#include "analysis/utils.h"
#include "llvmlayer.h"
using namespace std;
namespace xreate{ namespace compilation{
llvm::Value*
IntrinsicCompiler::compile(const Expression& e, const Context& context, const std::string& hintAlias){
switch ((IntrinsicFn) e.getValueDouble()){
case IntrinsicFn::ARR_INIT:{
return nullptr;
// const ExpandedType& typAggr = context.pass->man->root->getType(e);
// llvm::Type* typAggrRaw = context.pass->man->llvm->toLLVMType(typAggr);
// llvm::Value* lengthRaw = context.scope->process(e.operands.at(0));
//
// ContainerInst engine(context);
// return engine.array_init(lengthRaw, typAggrRaw);
}
+ case IntrinsicFn::CON_KEYS:
+ return con_keys(e, context, hintAlias);
+
default: break;
}
assert(false);
return nullptr;
}
Expression
IntrinsicCompiler::interpret(const Expression& e){
switch ((IntrinsicFn) e.getValueDouble()){
case IntrinsicFn::REC_FIELDS: {
return rec_fields(e);
}
default: break;
}
assert(false);
return Expression();
}
Expression
IntrinsicCompiler::rec_fields(const Expression& e){
TypesHelper helper(__man->llvm);
assert(e.operands.size() == 1);
const Expression argTypeE = e.operands.at(0);
assert(argTypeE.__state == Expression::STRING);
const string& argTypeS = argTypeE.getValueString();
const ExpandedType argTypeT = __man->root->findType(argTypeS);
const auto& fields = helper.getRecordFields(argTypeT);
return analysis::representVecStr(fields);
}
+llvm::Value*
+IntrinsicCompiler::con_keys(const Expression& e, const Context& context, const std::string& hintAlias){
+ const Expression& aggrE = e.operands.at(0);
+ const ExpandedType& aggrT = context.pass->man->root->getType(aggrE);
+ llvm::Value* aggrRaw = context.scope->process(aggrE);
+
+ std::unique_ptr<containers::IContainersIR> compiler(containers::IContainersIR::create(
+ aggrE, aggrT.get(), context
+ ));
+
+ return compiler->keys(aggrRaw, hintAlias);
+}
+
}}
\ No newline at end of file
diff --git a/cpp/src/compilation/intrinsics.h b/cpp/src/compilation/intrinsics.h
index 98f3c42..78f235d 100644
--- a/cpp/src/compilation/intrinsics.h
+++ b/cpp/src/compilation/intrinsics.h
@@ -1,26 +1,27 @@
//March 2020
#ifndef XREATE_INTRINSICS_H
#define XREATE_INTRINSICS_H
#include "ast.h"
#include "pass/compilepass.h"
namespace llvm {
class Value;
}
namespace xreate{ namespace compilation{
class IntrinsicCompiler{
public:
IntrinsicCompiler(PassManager* manager): __man(manager){};
llvm::Value* compile(const Expression& e, const Context& context, const std::string& hintAlias);
Expression interpret(const Expression& e);
private:
PassManager* __man;
Expression rec_fields(const Expression& e);
+ llvm::Value* con_keys(const Expression& e, const Context& context, const std::string& hintAlias);
};
}}
#endif //XREATE_INTRINSICS_H
diff --git a/cpp/src/compilation/targetinterpretation.cpp b/cpp/src/compilation/targetinterpretation.cpp
index d6f93b9..90e7491 100644
--- a/cpp/src/compilation/targetinterpretation.cpp
+++ b/cpp/src/compilation/targetinterpretation.cpp
@@ -1,646 +1,646 @@
/* 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->getBruteScope(scopeResult)->compile();
return result;
}
case SWITCH_INTERPRET_CONDITION:
{
CodeScope* scopeResult = processOperatorSwitch(expression);
llvm::Value* result = context.function->getBruteScope(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->getBruteScope(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:
const ExpandedType& typeVariant = function->__pass->man->root->getType(condCrudeE);
int conditionIndex = condE.getValueDouble();
ScopedSymbol symbolInternal = scopeResult->findSymbolByAlias(identCondition);
scopeResult->__declarations[symbolInternal].bindType(typeVariant->__operands.at(conditionIndex));
}
llvm::Value* result = context.function->getBruteScope(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->getBruteScope(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();
}
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);
+ 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->getASTFn(), this);
__dictFunctionsByUnit.emplace(unit, f);
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) { }
virtual std::string
prepareName() override {
return BruteFunction::prepareName() + "_" + std::to_string(__id);
}
protected:
std::vector<llvm::Type*>
prepareSignature() override {
LLVMLayer* llvm = BruteFunction::pass->man->llvm;
AST* ast = BruteFunction::pass->man->root;
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 = IBruteFunction::__entry;
IBruteScope* entryCompilation = BruteFunction::getBruteScope(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;
}
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/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp
index 4ab33f7..60d53ec 100644
--- a/cpp/src/pass/compilepass.cpp
+++ b/cpp/src/pass/compilepass.cpp
@@ -1,909 +1,911 @@
/* 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 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 "compilation/intrinsics.h"
#include "analysis/resources.h"
+
#ifdef XREATE_ENABLE_EXTERN
#include "ExternLayer.h"
#endif
#include "compilation/containers.h"
#include "compilation/containers/arrays.h"
#ifndef XREATE_CONFIG_MIN
#include "query/containers.h"
#include "pass/versionspass.h"
#include "compilation/targetinterpretation.h"
#endif
#include <boost/optional.hpp>
#include <memory>
using namespace std;
using namespace llvm;
using namespace xreate::typehints;
using namespace xreate::containers;
namespace xreate{
namespace compilation{
#define DEFAULT(x) (hintAlias.empty()? x: hintAlias)
std::string
BasicBruteFunction::prepareName() {
AST* ast = IBruteFunction::pass->man->root;
string name = ast->getFnSpecializations(__function->__name).size() > 1 ?
__function->__name + std::to_string(__function.id()) :
__function->__name;
return name;
}
std::vector<llvm::Type*>
BasicBruteFunction::prepareSignature() {
CodeScope* entry = __function->__entry;
return getScopeSignature(entry);
}
llvm::Type*
BasicBruteFunction::prepareResult() {
LLVMLayer* llvm = IBruteFunction::pass->man->llvm;
AST* ast = IBruteFunction::pass->man->root;
CodeScope* entry = __function->__entry;
const Expression retE = entry->__declarations.at(ScopedSymbol::RetSymbol);
const ExpandedType& retT = ast->getType(retE);
return llvm->toLLVMType(retT, retE);
}
llvm::Function::arg_iterator
BasicBruteFunction::prepareBindings() {
CodeScope* entry = __function->__entry;
IBruteScope* entryCompilation = IBruteFunction::getBruteScope(entry);
llvm::Function::arg_iterator fargsI = IBruteFunction::raw->arg_begin();
for (std::string &arg : entry->__bindings) {
ScopedSymbol argid{entry->__identifiers[arg], versions::VERSION_NONE};
entryCompilation->bindArg(&*fargsI, argid);
fargsI->setName(arg);
++fargsI;
}
return fargsI;
}
void
BasicBruteFunction::applyAttributes(){}
IBruteScope::IBruteScope(const CodeScope * const codeScope, IBruteFunction* f, CompilePass* compilePass)
: pass(compilePass), function(f), scope(codeScope), lastBlockRaw(nullptr) { }
llvm::Value*
BruteFnInvocation::operator()(std::vector<llvm::Value *>&& args, const std::string& hintDecl) {
if (__calleeTy) {
auto argsFormalT = __calleeTy->params();
size_t sizeArgsF = __calleeTy->getNumParams();
assert(args.size() >= sizeArgsF);
assert(__calleeTy->isVarArg() || args.size() == sizeArgsF);
auto argFormalT = argsFormalT.begin();
for(size_t argId = 0; argId < args.size(); ++argId){
if(argFormalT != argsFormalT.end()){
args[argId] = typeinference::doAutomaticTypeConversion(
args.at(argId), *argFormalT, llvm->irBuilder);
++argFormalT;
}
}
}
//Do not name function call that returns Void.
std::string hintName = (!__calleeTy->getReturnType()->isVoidTy()) ? hintDecl : "";
return llvm->irBuilder.CreateCall(__calleeTy, __callee, args, hintName);
}
llvm::Value*
HiddenArgsFnInvocation::operator() (std::vector<llvm::Value *>&& args, const std::string& hintDecl) {
args.insert(args.end(), __args.begin(), __args.end());
return __parent->operator ()(std::move(args), hintDecl);
}
class CallStatementInline : public IFnInvocation{
public:
CallStatementInline(IBruteFunction* caller, IBruteFunction* callee, LLVMLayer* l)
: __caller(caller), __callee(callee), llvm(l) { }
llvm::Value* operator()(std::vector<llvm::Value *>&& args, const std::string& hintDecl) {
return nullptr;
}
private:
IBruteFunction* __caller;
IBruteFunction* __callee;
LLVMLayer* llvm;
bool
isInline() {
// Symbol ret = Symbol{0, function->__entry};
// bool flagOnTheFly = SymbolAttachments::get<IsImplementationOnTheFly>(ret, false);
//TODO consider inlining
return false;
}
} ;
BasicBruteScope::BasicBruteScope(const CodeScope * const codeScope, IBruteFunction* f, CompilePass* compilePass)
: IBruteScope(codeScope, f, compilePass) { }
llvm::Value*
BasicBruteScope::processSymbol(const Symbol& s, std::string hintRetVar) {
Expression declaration = CodeScope::getDefinition(s);
const CodeScope* scopeExternal = s.scope;
IBruteScope* scopeBruteExternal = IBruteScope::function->getBruteScope(scopeExternal);
assert(scopeBruteExternal->lastBlockRaw);
llvm::Value* resultRaw;
llvm::BasicBlock* blockOwn = pass->man->llvm->irBuilder.GetInsertBlock();
if (scopeBruteExternal->lastBlockRaw == blockOwn) {
resultRaw = scopeBruteExternal->process(declaration, hintRetVar);
scopeBruteExternal->lastBlockRaw = lastBlockRaw =
pass->man->llvm->irBuilder.GetInsertBlock();
} else {
pass->man->llvm->irBuilder.SetInsertPoint(scopeBruteExternal->lastBlockRaw);
resultRaw = scopeBruteExternal->processSymbol(s, hintRetVar);
pass->man->llvm->irBuilder.SetInsertPoint(blockOwn);
}
return resultRaw;
}
IFnInvocation*
BasicBruteScope::findFunction(const Expression& opCall) {
const std::string& calleeName = opCall.getValueString();
LLVMLayer* llvm = pass->man->llvm;
const std::list<ManagedFnPtr>& specializations = pass->man->root->getFnSpecializations(calleeName);
#ifdef XREATE_ENABLE_EXTERN
//if no specializations registered - check external function
if (specializations.size() == 0) {
llvm::Function* external = llvm->layerExtern->lookupFunction(calleeName);
llvm::outs() << "Debug/External function: " << calleeName;
external->getType()->print(llvm::outs(), true);
llvm::outs() << "\n";
return new BruteFnInvocation(external, llvm);
}
#endif
//There should be only one specialization without any valid guards at this point
return new BruteFnInvocation(pass->getBruteFn(
pass->man->root->findFunction(calleeName))->compile(),
llvm);
}
//DISABLEDFEATURE transformations
// if (pass->transformations->isAcceptable(expr)){
// return pass->transformations->transform(expr, result, ctx);
// }
llvm::Value*
BasicBruteScope::process(const Expression& expr, const std::string& hintAlias, const TypeAnnotation& expectedT) {
llvm::Value *leftRaw;
llvm::Value *rightRaw;
LLVMLayer& l = *pass->man->llvm;
Context ctx{this, function, pass};
xreate::compilation::ControlIR controlIR = xreate::compilation::ControlIR({this, function, pass});
switch (expr.op) {
case Operator::ADD:
case Operator::SUB: case Operator::MUL: case Operator::MOD:
case Operator::DIV: case Operator::EQU: case Operator::LSS:
case Operator::GTR: case Operator::NE: case Operator::LSE:
case Operator::GTE:
assert(expr.__state == Expression::COMPOUND);
assert(expr.operands.size() == 2);
leftRaw = process(expr.operands.at(0));
rightRaw = process(expr.operands.at(1));
break;
default:;
}
switch (expr.op) {
case Operator::AND:
{
assert(expr.operands.size());
llvm::Value* resultRaw = process(expr.operands.at(0));
if (expr.operands.size() == 1) return resultRaw;
for(size_t i=1; i< expr.operands.size()-1; ++i){
resultRaw = l.irBuilder.CreateAnd(resultRaw, process(expr.operands.at(i)));
}
return l.irBuilder.CreateAnd(resultRaw, process(expr.operands.at(expr.operands.size()-1)), hintAlias);
}
case Operator::OR:
{
assert(expr.operands.size());
llvm::Value* resultRaw = process(expr.operands.at(0));
if (expr.operands.size() == 1) return resultRaw;
for(size_t i=1; i< expr.operands.size()-1; ++i){
resultRaw = l.irBuilder.CreateOr(resultRaw, process(expr.operands.at(i)));
}
return l.irBuilder.CreateOr(resultRaw, process(expr.operands.at(expr.operands.size()-1)), hintAlias);
}
case Operator::ADD:
{
return l.irBuilder.CreateAdd(leftRaw, rightRaw, hintAlias);
}
case Operator::SUB:
return l.irBuilder.CreateSub(leftRaw, rightRaw, hintAlias);
break;
case Operator::MUL:
return l.irBuilder.CreateMul(leftRaw, rightRaw, hintAlias);
break;
case Operator::DIV:
if (leftRaw->getType()->isIntegerTy()) return l.irBuilder.CreateSDiv(leftRaw, rightRaw, hintAlias);
if (leftRaw->getType()->isFloatingPointTy()) return l.irBuilder.CreateFDiv(leftRaw, rightRaw, hintAlias);
break;
case Operator::MOD:{
return l.irBuilder.CreateSRem(leftRaw, rightRaw, hintAlias);
}
case Operator::EQU: {
if (leftRaw->getType()->isIntegerTy()) return l.irBuilder.CreateICmpEQ(leftRaw, rightRaw, hintAlias);
if (leftRaw->getType()->isFloatingPointTy()) return l.irBuilder.CreateFCmpOEQ(leftRaw, rightRaw, hintAlias);
const ExpandedType& leftT = pass->man->root->getType(expr.operands[0]);
const ExpandedType& rightT = pass->man->root->getType(expr.operands[1]);
if(leftT->__operator == TypeOperator::VARIANT && rightT->__operator == TypeOperator::VARIANT){
llvm::Type* selectorT = llvm::cast<llvm::StructType>(leftRaw->getType())->getElementType(0);
llvm::Value* leftUnwapped = typeinference::doAutomaticTypeConversion(leftRaw, selectorT, l.irBuilder);
llvm::Value* rightUnwapped = typeinference::doAutomaticTypeConversion(rightRaw, selectorT, l.irBuilder);
return l.irBuilder.CreateICmpEQ(leftUnwapped, rightUnwapped, hintAlias);
}
break;
}
case Operator::NE:
return l.irBuilder.CreateICmpNE(leftRaw, rightRaw, hintAlias);
break;
case Operator::LSS:
return l.irBuilder.CreateICmpSLT(leftRaw, rightRaw, hintAlias);
break;
case Operator::LSE:
return l.irBuilder.CreateICmpSLE(leftRaw, rightRaw, hintAlias);
break;
case Operator::GTR:
return l.irBuilder.CreateICmpSGT(leftRaw, rightRaw, hintAlias);
break;
case Operator::GTE:
return l.irBuilder.CreateICmpSGE(leftRaw, rightRaw, hintAlias);
break;
case Operator::NEG:
{
leftRaw = process(expr.operands[0]);
ExpandedType leftTy = pass->man->root->getType(expr.operands[0]);
if (leftTy->__value == TypePrimitive::Bool){
return l.irBuilder.CreateNot(leftRaw, hintAlias);
} else {
return l.irBuilder.CreateNeg(leftRaw, hintAlias);
}
break;
}
case Operator::CALL:
{
assert(expr.__state == Expression::COMPOUND);
shared_ptr<IFnInvocation> callee(findFunction(expr));
const std::string& nameCallee = expr.getValueString();
//prepare arguments
std::vector<llvm::Value *> args;
args.reserve(expr.operands.size());
std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()),
[this](const Expression & operand) {
return process(operand);
}
);
return (*callee)(move(args), hintAlias);
}
case Operator::IF:
{
return controlIR.compileIf(expr, hintAlias);
}
case Operator::SWITCH:
{
return controlIR.compileSwitch(expr, hintAlias);
}
case Operator::LOGIC_AND:
{
assert(expr.operands.size() == 1);
return process(expr.operands[0]);
}
case Operator::LIST: //init record or array
{
ExpandedType exprT = l.ast->getType(expr, expectedT);
TypesHelper helper(pass->man->llvm);
enum {RECORD, ARRAY} kind;
if (helper.isArrayT(exprT)){
kind = ARRAY;
} else if (helper.isRecordT(exprT)){
kind = RECORD;
} else {
assert(false && "Inapproriate type");
}
#ifdef XREATE_ENABLE_EXTERN
if (exprT->__operator == TypeOperator::ALIAS){
if (l.layerExtern->isArrayType(exprT->__valueCustom)){
flagIsArray = true;
break;
}
if (l.layerExtern->isRecordType(exprT->__valueCustom)){
flagIsArray = false;
break;
}
assert(false && "Inapproriate external type");
}
#endif
switch(kind){
case RECORD:{
const std::vector<string> fieldsFormal = helper.getRecordFields(exprT);
containers::RecordIR irRecords(ctx);
llvm::StructType *recordTRaw = llvm::cast<llvm::StructType>(l.toLLVMType(exprT));
llvm::Value *resultRaw = irRecords.init(recordTRaw);
return irRecords.update(resultRaw, exprT, expr);
}
case ARRAY: {
std::unique_ptr<containers::IContainersIR> containerIR(
containers::IContainersIR::create(expr, expectedT, ctx));
llvm::Value* aggrRaw = containerIR->init(hintAlias);
return containerIR->update(aggrRaw, expr, hintAlias);
}
}
break;
};
case Operator::LIST_RANGE:
{
containers::RangeIR compiler(ctx);
const ExpandedType& aggrT = pass->man->root->getType(expr);
return compiler.init(expr, aggrT, hintAlias);
};
case Operator::MAP:
{
assert(expr.blocks.size());
containers::ImplementationType implType = containers::IContainersIR::getImplementation(expr, pass->man->root);
switch(implType){
case containers::ImplementationType::SOLID: {
ExpandedType exprT = pass->man->root->getType(expr, expectedT);
ArrayHint hint = find(expr, ArrayHint{});
containers::ArrayIR compiler(exprT, hint, ctx);
return compiler.operatorMap(expr, hintAlias);
}
case containers::ImplementationType::ON_THE_FLY:{
FlyHint hint = find<FlyHint>(expr, {});
containers::FlyIR compiler(hint, ctx);
return compiler.operatorMap(expr, hintAlias);
}
default:
break;
}
assert(false && "Operator MAP does not support this container impl");
return nullptr;
};
case Operator::FOLD:
{
return controlIR.compileFold(expr, hintAlias);
};
case Operator::FOLD_INF:
{
return controlIR.compileFoldInf(expr, hintAlias);
};
case Operator::INDEX:
{
assert(expr.operands.size() > 1);
const Expression& aggrE = expr.operands[0];
const ExpandedType& aggrT = pass->man->root->getType(aggrE);
llvm::Value* aggrRaw = process(aggrE);
switch (aggrT->__operator) {
case TypeOperator::RECORD:
{
list<string> fieldsList;
for(auto opIt = ++expr.operands.begin(); opIt!=expr.operands.end(); ++opIt){
fieldsList.push_back(getIndexStr(*opIt));
}
return controlIR.compileStructIndex(aggrRaw, aggrT, fieldsList);
};
case TypeOperator::ARRAY:
{
std::vector<llvm::Value*> indexes;
std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()),
[this] (const Expression & op) {
return process(op);
}
);
std::unique_ptr<containers::IContainersIR> containersIR(
containers::IContainersIR::create(aggrE, expectedT, ctx)
);
containers::ArrayIR* arraysIR = static_cast<containers::ArrayIR*>(containersIR.get());
return arraysIR->get(aggrRaw, indexes, hintAlias);
};
default:
assert(false);
}
};
- case Operator::CALL_INTRINSIC:
- {
+ case Operator::CALL_INTRINSIC:{
+ IntrinsicCompiler compiler(this->pass->man);
+ return compiler.compile(expr, ctx, hintAlias);
+ }
+
// const std::string op = expr.getValueString();
//
// if (op == "copy") {
// llvm::Value* result = process(expr.getOperands().at(0));
//
// auto decoratorVersions = Decorators<VersionsScopeDecoratorTag>::getInterface(this);
// llvm::Value* storage = decoratorVersions->processIntrinsicInit(result->getType());
// decoratorVersions->processIntrinsicCopy(result, storage);
//
// return l.irBuilder.CreateLoad(storage, hintAlias);
// }
- assert(false && "undefined intrinsic");
- }
-
case Operator::QUERY:
case Operator::QUERY_LATE:
{
assert(false && "Should be processed by interpretation");
}
case Operator::VARIANT:
{
const ExpandedType& typResult = pass->man->root->getType(expr);
llvm::Type* typResultRaw = l.toLLVMType(typResult);
llvm::Type* typIdRaw = llvm::cast<llvm::StructType>(typResultRaw)->getElementType(0);
uint64_t id = expr.getValueDouble();
llvm::Value* resultRaw = llvm::UndefValue::get(typResultRaw);
resultRaw = l.irBuilder.CreateInsertValue(resultRaw, llvm::ConstantInt::get(typIdRaw, id), llvm::ArrayRef<unsigned>({0}));
const ExpandedType& typVariant = ExpandedType(typResult->__operands.at(id));
llvm::Type* typVariantRaw = l.toLLVMType(typVariant);
llvm::Value* variantRaw = llvm::UndefValue::get(typVariantRaw);
assert(expr.operands.size() == typVariant->__operands.size() && "Wrong variant arguments count");
if (!typVariant->__operands.size()) return resultRaw;
for (unsigned int fieldId = 0; fieldId < expr.operands.size(); ++fieldId) {
const ExpandedType& typField = ExpandedType(typVariant->__operands.at(fieldId));
Attachments::put<TypeInferred>(expr.operands.at(fieldId), typField);
llvm::Value* fieldRaw = process(expr.operands.at(fieldId));
assert(fieldRaw);
variantRaw = l.irBuilder.CreateInsertValue(variantRaw, fieldRaw, llvm::ArrayRef<unsigned>({fieldId}));
}
llvm::Type* typStorageRaw = llvm::cast<llvm::StructType>(typResultRaw)->getElementType(1);
llvm::Value* addrAsStorage = l.irBuilder.CreateAlloca(typStorageRaw);
llvm::Value* addrAsVariant = l.irBuilder.CreateBitOrPointerCast(addrAsStorage, typVariantRaw->getPointerTo());
l.irBuilder.CreateStore(variantRaw, addrAsVariant);
llvm::Value* storageRaw = l.irBuilder.CreateLoad(typStorageRaw, addrAsStorage);
resultRaw = l.irBuilder.CreateInsertValue(resultRaw, storageRaw, llvm::ArrayRef<unsigned>({1}));
return resultRaw;
}
case Operator::SWITCH_VARIANT:
{
return controlIR.compileSwitchVariant(expr, hintAlias);
}
case Operator::SWITCH_LATE:
{
assert(false && "Instruction's compilation should've been redirected to interpretation");
return nullptr;
}
case Operator::SEQUENCE:
{
return controlIR.compileSequence(expr);
}
case Operator::UNDEF:
{
llvm::Type* typExprUndef = l.toLLVMType(pass->man->root->getType(expr, expectedT));
return llvm::UndefValue::get(typExprUndef);
}
case Operator::UPDATE:
{
TypesHelper helper(pass->man->llvm);
containers::RecordIR irRecords(ctx);
const Expression& aggrE = expr.operands.at(0);
const Expression& updE = expr.operands.at(1);
const ExpandedType& aggrT = pass->man->root->getType(aggrE);
llvm::Value* aggrRaw = process(aggrE);
if (helper.isRecordT(aggrT)){
return irRecords.update(aggrRaw, aggrT, updE);
}
if (helper.isArrayT(aggrT)){
if (updE.op == Operator::LIST_INDEX){
std::unique_ptr<containers::IContainersIR> containersIR(
containers::IContainersIR::create(aggrE, TypeAnnotation(), ctx
));
return containersIR->update(aggrRaw, updE, hintAlias);
}
}
assert(false);
return nullptr;
}
case Operator::INVALID:
assert(expr.__state != Expression::COMPOUND);
switch (expr.__state) {
case Expression::IDENT:
{
Symbol s = Attachments::get<IdentifierSymbol>(expr);
return processSymbol(s, expr.getValueString());
}
case Expression::NUMBER:
{
llvm::Type* typConst = l.toLLVMType(pass->man->root->getType(expr, expectedT));
int literal = expr.getValueDouble();
if (typConst->isFloatingPointTy()) return llvm::ConstantFP::get(typConst, literal);
if (typConst->isIntegerTy()) return llvm::ConstantInt::get(typConst, literal);
assert(false && "Can't compile literal");
}
case Expression::STRING:
{
return controlIR.compileConstantStringAsPChar(expr.getValueString(), hintAlias);
};
default:
{
break;
}
};
break;
default: break;
}
assert(false && "Can't compile expression");
return 0;
}
llvm::Value*
BasicBruteScope::compile(const std::string& hintBlockDecl) {
LLVMLayer* llvm = pass->man->llvm;
if (!hintBlockDecl.empty()) {
llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm->llvmContext, hintBlockDecl, function->raw);
pass->man->llvm->irBuilder.SetInsertPoint(block);
}
lastBlockRaw = pass->man->llvm->irBuilder.GetInsertBlock();
Symbol symbScope = Symbol{ScopedSymbol::RetSymbol, scope};
//set hint for an entry scope
string retAlias = (scope->__parent)? "" : function->prepareName();
return processSymbol(symbScope, retAlias);
}
IBruteScope::~IBruteScope() { }
IBruteFunction::~IBruteFunction() { }
llvm::Function*
IBruteFunction::compile() {
if (raw != nullptr) return raw;
LLVMLayer* llvm = pass->man->llvm;
llvm::IRBuilder<>& builder = llvm->irBuilder;
string&& functionName = prepareName();
std::vector<llvm::Type*>&& types = prepareSignature();
llvm::Type* expectedResultType = prepareResult();
llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false);
raw = llvm::cast<llvm::Function>(llvm->module->getOrInsertFunction(functionName, ft));
prepareBindings();
applyAttributes();
const std::string& blockName = "entry";
llvm::BasicBlock* blockCurrent = builder.GetInsertBlock();
llvm::Value* result = getBruteScope(__entry)->compile(blockName);
assert(result);
//SECTIONTAG types/convert function ret value
builder.CreateRet(typeinference::doAutomaticTypeConversion(result, expectedResultType, llvm->irBuilder));
if (blockCurrent) {
builder.SetInsertPoint(blockCurrent);
}
llvm->moveToGarbage(ft);
return raw;
}
IBruteScope*
IBruteFunction::getBruteScope(const CodeScope * const scope) {
if (__scopes.count(scope)) {
auto result = __scopes.at(scope).lock();
if (result) {
return result.get();
}
}
std::shared_ptr<IBruteScope> unit(pass->buildCodeScopeUnit(scope, this));
if (scope->__parent != nullptr) {
auto parentUnit = Decorators<CachedScopeDecoratorTag>::getInterface(getBruteScope(scope->__parent));
parentUnit->registerChildScope(unit);
} else {
__orphanedScopes.push_back(unit);
}
if (!__scopes.emplace(scope, unit).second) {
__scopes[scope] = unit;
}
return unit.get();
}
IBruteScope*
IBruteFunction::getScopeUnit(ManagedScpPtr scope) {
return getBruteScope(&*scope);
}
IBruteScope*
IBruteFunction::getEntry() {
return getBruteScope(__entry);
}
std::vector<llvm::Type*>
IBruteFunction::getScopeSignature(CodeScope* scope){
LLVMLayer* llvm = IBruteFunction::pass->man->llvm;
AST* ast = IBruteFunction::pass->man->root;
std::vector<llvm::Type*> result;
std::transform(scope->__bindings.begin(), scope->__bindings.end(), std::inserter(result, result.end()),
[llvm, ast, scope](const std::string & argAlias)->llvm::Type* {
assert(scope->__identifiers.count(argAlias));
ScopedSymbol argS{scope->__identifiers.at(argAlias), versions::VERSION_NONE};
const Expression& argE = scope->__declarations.at(argS);
const ExpandedType& argT = ast->expandType(argE.type);
return llvm->toLLVMType(argT, argE);
});
if(scope->trackExternalSymbs){
std::transform(scope->boundExternalSymbs.begin(), scope->boundExternalSymbs.end(), std::inserter(result, result.end()),
[llvm, ast](const Symbol& argS){
const Expression& argE = CodeScope::getDefinition(argS);
const ExpandedType& argT = ast->expandType(argE.type);
return llvm->toLLVMType(argT, argE);
});
}
return result;
}
template<>
compilation::IBruteFunction*
CompilePassCustomDecorators<void, void>
::buildFunctionUnit(const ManagedFnPtr& function) {
return new BruteFunctionDefault(function, this);
}
template<>
compilation::IBruteScope*
CompilePassCustomDecorators<void, void>
::buildCodeScopeUnit(const CodeScope * const scope, IBruteFunction* function) {
return new DefaultCodeScopeUnit(scope, function, this);
}
std::string
BasicBruteScope::getIndexStr(const Expression& index){
switch(index.__state){
//named struct field
case Expression::STRING:
return index.getValueString();
break;
//anonymous struct field
case Expression::NUMBER:
return to_string((int) index.getValueDouble());
break;
default:
assert(false && "Wrong index for a struct");
}
return "";
}
} // end of compilation
compilation::IBruteFunction*
CompilePass::getBruteFn(const ManagedFnPtr& function) {
unsigned int id = function.id();
if (!functions.count(id)) {
compilation::IBruteFunction* unit = buildFunctionUnit(function);
functions.emplace(id, unit);
return unit;
}
return functions.at(id);
}
void
CompilePass::prepare(){
//Initialization:
#ifndef XREATE_CONFIG_MIN
#endif
managerTransformations = new xreate::compilation::TransformationsManager();
targetInterpretation = new interpretation::TargetInterpretation(man, this);
}
void
CompilePass::run() {
prepare();
//Determine entry function:
StaticModel modelEntry = man->transcend->query(analysis::FN_ENTRY_PREDICATE);
if (man->options.requireEntryFn){
assert(modelEntry.size() && "Error: No entry function found");
assert(modelEntry.size() == 1 && "Error: Ambiguous entry function");
}
if(modelEntry.size()){
string fnEntryName = std::get<0>(TranscendLayer::parse<std::string>(modelEntry.begin()->second));
compilation::IBruteFunction* fnEntry = getBruteFn(man->root->findFunction(fnEntryName));
__fnEntryRaw = fnEntry->compile();
}
//Compile exterior functions:
StaticModel modelExterior = man->transcend->query(analysis::FN_EXTERIOR_PREDICATE);
for(const auto entry: modelExterior){
- const string& fnName = std::get<0>(TranscendLayer::parse<std::string>(entry.second));
+ string fnName = std::get<0>(TranscendLayer::parse<std::string>(entry.second));
getBruteFn(man->root->findFunction(fnName))->compile();
}
}
llvm::Function*
CompilePass::getEntryFunction() {
return __fnEntryRaw;
}
void
CompilePass::prepareQueries(TranscendLayer* transcend) {
#ifndef XREATE_CONFIG_MIN
transcend->registerQuery(new latex::LatexQuery(), QueryId::LatexQuery);
#endif
transcend->registerQuery(new containers::Query(), QueryId::ContainersQuery);
transcend->registerQuery(new demand::DemandQuery(), QueryId::DemandQuery);
transcend->registerQuery(new polymorph::PolymorphQuery(), QueryId::PolymorphQuery);
}
} //end of namespace xreate
/**
* \class xreate::CompilePass
* \brief The owner of the compilation process. Performs fundamental compilation activities along with the xreate::compilation's routines
*
* xreate::CompilePass traverses over xreate::AST tree and produces executable code.
* The pass performs compilation using the following data sources:
* - %Attachments: the data gathered by the previous passes. See \ref xreate::Attachments.
* - Transcend solutions accessible via queries. See \ref xreate::IQuery, \ref xreate::TranscendLayer.
*
* The pass generates a bytecode by employing \ref xreate::LLVMLayer(wrapper over LLVM toolchain).
* Many compilation activities are delegated to more specific routines. Most notable delegated compilation aspects are:
* - Containers support. See \ref xreate::containers.
* - Latex compilation. See \ref xreate::latex.
* - Interpretation support. See \ref xreate::interpretation.
* - Loop saturation support. See \ref xreate::compilation::TransformationsScopeDecorator.
* - External code interaction support. See \ref xreate::ExternLayer (wrapper over Clang library).
*
* \section adaptability_sect Adaptability
* xreate::CompilePass's behaviour can be adapted in several ways:
* - %Function Decorators to alter function-level compilation. See \ref xreate::compilation::IBruteFunction
* - Code Block Decorators to alter code block level compilation. See \ref xreate::compilation::ICodeScopeUnit.
* Default functionality defined by \ref xreate::compilation::DefaultCodeScopeUnit
* - Targets to allow more versitile extensions.
* Currently only xreate::interpretation::TargetInterpretation use Targets infrastructure. See \ref xreate::compilation::Target.
* - Altering %function invocation. See \ref xreate::compilation::IFnInvocation.
*
* Clients are free to construct a compiler instantiation with the desired decorators by using \ref xreate::compilation::CompilePassCustomDecorators.
* As a handy alias, `CompilePassCustomDecorators<void, void>` constructs the default compiler.
*
- */
\ No newline at end of file
+ */
diff --git a/cpp/tests/containers.cpp b/cpp/tests/containers.cpp
index ebc9a09..a960a2d 100644
--- a/cpp/tests/containers.cpp
+++ b/cpp/tests/containers.cpp
@@ -1,340 +1,365 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* containers.cpp
*
* Created on: Jun 9, 2015
* Author: pgess <v.melnychenko@xreate.org>
*/
#include "xreatemanager.h"
#include "query/containers.h"
#include "main/Parser.h"
#include "pass/compilepass.h"
#include "llvmlayer.h"
#include "supplemental/docutils.h"
#include "supplemental/basics.h"
#include "gtest/gtest.h"
using namespace std;
using namespace xreate::grammar::main;
using namespace xreate::containers;
using namespace xreate;
struct Tuple2 {intmax_t a; intmax_t b;};
typedef Tuple2 (*FnTuple2)();
struct Tuple4 {intmax_t a; intmax_t b; intmax_t c; intmax_t d;};
typedef Tuple4 (*FnTuple4)();
TEST(Containers, RecInitByList1){
string code = R"(
Rec = type {x:: int, y:: int}.
test = function(a:: int, b::int):: Rec; entry() {
{x = a + b, y = 2}
}
)";
auto man = XreateManager::prepare(move(code));
man->run();
}
TEST(Containers, RecInitByList2){
string code = R"(
Rec = type {x:: int, y:: int}.
test = function(a:: int, b::int):: Rec; entry() {
{a + b, y = 2}
}
)";
auto man = XreateManager::prepare(move(code));
man->run();
}
TEST(Containers, RecUpdateByList1){
string code = R"(
Rec = type {x:: int, y:: int}.
test = function(a:: int, b::int):: Rec; entry() {
r = {0, y = 2}:: Rec.
r : {a + b}
}
)";
auto man = XreateManager::prepare(move(code));
man->run();
}
TEST(Containers, RecUpdateByListIndex1){
string code = R"(
Rec = type {x:: int, y:: int}.
test = function(a:: int, b::int):: int; entry() {
r1 = undef:: Rec.
r2 = r1 : {[1] = b, [0] = a}:: Rec.
r2["x"]
}
)";
auto man = XreateManager::prepare(move(code));
Fn2Args program = (Fn2Args) man->run();
ASSERT_EQ(10, program(10, 11));
}
TEST(Containers, RecUpdateInLoop1){
- FILE* code = fopen("scripts/containers/RecUpdateInLoop1.xreate", "r");
+ FILE* code = fopen("scripts/containers/containers-tests.xreate", "r");
assert(code != nullptr);
- auto man = XreateManager::prepare(code);
- Fn1Args program = (Fn1Args) man->run();
- ASSERT_EQ(11, program(10));
+ std::unique_ptr<XreateManager> man(XreateManager::prepare(code));
+ man->transcend->addRawScript("select(function(\"fn-RecUpdateInLoop1\")).");
+ man->options.requireEntryFn = false;
+ man->run();
+
+ {
+ Fn1Args fn = (Fn1Args) man->getExteriorFn("fn-RecUpdateInLoop1");
+ ASSERT_EQ(11, fn(10));
+ }
}
TEST(Containers, ArrayInit1){
XreateManager* man = XreateManager::prepare(
R"Code(
main = function(x:: int):: int; entry() {
a = {1, 2, 3}:: [int].
a[x]
}
)Code");
void* mainPtr = man->run();
Fn1Args main = (Fn1Args) mainPtr;
ASSERT_EQ(2, main(1));
delete man;
}
TEST(Containers, ArrayUpdate1){
XreateManager* man = XreateManager::prepare(R"(
main = function(x::int):: int; entry()
{
a = {1, 2, 3}:: [int]; csize(5).
b = a : {[1] = x}:: [int]; csize(5).
b[1]
}
)");
void* mainPtr = man->run();
Fn1Args main = (Fn1Args) mainPtr;
ASSERT_EQ(2, main(2));
delete man;
}
TEST(Containers, FlyMap1){
std::unique_ptr<XreateManager> man(XreateManager::prepare(R"(
main = function:: int; entry()
{
x = {1, 2, 3, 4}:: [int].
y = loop map(x->el::int)::[int]; fly(csize(4))
{2 * el:: int }.
loop fold((y::[int]; fly(csize(4)))->el:: int, 0->sum):: int {sum + el}-20
}
)"));
FnNoArgs mainFn = (FnNoArgs) man->run();
intmax_t valueMain = mainFn();
ASSERT_EQ(0, valueMain);
}
TEST(Containers, ArrayArg1){
FILE* code = fopen("scripts/containers/containers-tests.xreate", "r");
assert(code != nullptr);
std::unique_ptr<XreateManager> man(XreateManager::prepare(code));
+ man->transcend->addRawScript("select(function(\"fn-ArrayArg1\")).");
man->options.requireEntryFn = false;
man->run();
FnNoArgs fnTested = (FnNoArgs) man->getExteriorFn("fn-ArrayArg1");
ASSERT_EQ(1, fnTested());
}
TEST(Containers, FlyArg1){
FILE* code = fopen("scripts/containers/containers-tests.xreate", "r");
assert(code != nullptr);
std::unique_ptr<XreateManager> man(XreateManager::prepare(code));
+ man->transcend->addRawScript("select(function(\"fn-FlyArg1\")).");
man->options.requireEntryFn = false;
man->run();
FnNoArgs fnTested = (FnNoArgs) man->getExteriorFn("fn-FlyArg1");
ASSERT_EQ(8, fnTested());
}
TEST(Containers, Range1){
FILE* code = fopen("scripts/containers/containers-tests.xreate", "r");
assert(code != nullptr);
std::unique_ptr<XreateManager> man(XreateManager::prepare(code));
+ man->transcend->addRawScript("select(function(\"fn-Range1\"; \"fn-Range2\")).");
man->options.requireEntryFn = false;
man->run();
{
FnNoArgs fnRange1 = (FnNoArgs) man->getExteriorFn("fn-Range1");
ASSERT_EQ(10, fnRange1());
}
{
FnNoArgs fnRange2 = (FnNoArgs) man->getExteriorFn("fn-Range2");
ASSERT_EQ(20, fnRange2());
}
}
TEST(Containers, RetRange1){
FILE* code = fopen("scripts/containers/containers-tests.xreate", "r");
assert(code != nullptr);
std::unique_ptr<XreateManager> man(XreateManager::prepare(code));
+ man->transcend->addRawScript("select(function(\"fn-RetRange1\")).");
man->options.requireEntryFn = false;
man->run();
{
FnNoArgs fnRange1 = (FnNoArgs) man->getExteriorFn("fn-RetRange1");
ASSERT_EQ(10, fnRange1());
}
}
+TEST(Containers, IntrinsicKeys1){
+ FILE* code = fopen("scripts/containers/containers-tests.xreate", "r");
+ assert(code != nullptr);
+
+ std::unique_ptr<XreateManager> man(XreateManager::prepare(code));
+ man->transcend->addRawScript("select(function(\"fn-Keys1\")).");
+ man->options.requireEntryFn = false;
+ man->run();
+
+ {
+ FnNoArgs fn = (FnNoArgs) man->getExteriorFn("fn-Keys1");
+ ASSERT_EQ(6, fn());
+ }
+}
+
//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->findSymbolByAlias("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/transcend.cpp b/cpp/tests/transcend.cpp
index e5d6436..91433f3 100644
--- a/cpp/tests/transcend.cpp
+++ b/cpp/tests/transcend.cpp
@@ -1,102 +1,119 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on June 7, 2018, 3:35 PM
*
* \file transcend.cpp
* \brief Transcend's tests
*/
#include "xreatemanager.h"
#include "transcendlayer.h"
+#include "analysis/resources.h"
#include "supplemental/docutils.h"
#include <gtest/gtest.h>
using namespace xreate;
using namespace std;
TEST(Transcend, Parse1) {
std::string script =
R"Code(
)Code";
std::unique_ptr<details::tier1::XreateManager> man(details::tier1::XreateManager::prepare(std::move(script)));
std::string scriptTranscend =
R"Code(
test1((1)).
test2((1, 2)).
test3(1, "a").
)Code";
man->transcend->addRawScript(move(scriptTranscend));
man->analyse();
StaticModel solution = man->transcend->query("test1");
Gringo::Symbol symbTest1 = solution.begin()->second;
auto answer1 = man->transcend->parse<list<int>>(symbTest1);
ASSERT_EQ(1, get<0>(answer1).size());
solution = man->transcend->query("test2");
Gringo::Symbol symbTest2 = solution.begin()->second;
auto answer2 = get<0>(man->transcend->parse<list<int>>(symbTest2));
ASSERT_EQ(2, answer2.size());
typedef std::tuple<int, string> Predicate3;
solution = man->transcend->query("test3");
Gringo::Symbol symbTest3 = solution.begin()->second;
auto answer3a = get<0>(man->transcend->parse(schemeT<Predicate3>(), symbTest3));
auto answer3b = get<1>(man->transcend->parse(schemeT<Predicate3>(), symbTest3));
ASSERT_EQ(1, answer3a);
ASSERT_STREQ("a", answer3b.c_str());
}
+TEST(Transcend, ClaspBug1){
+ std::string scriptTranscend =
+ R"Code(
+ exterior("fn-RecUpdateInLoop1").
+ )Code";
+
+ std::unique_ptr<details::tier1::XreateManager> man(details::tier1::XreateManager::prepare(""));
+ man->transcend->addRawScript(move(scriptTranscend));
+ man->analyse();
+ StaticModel solution = man->transcend->query(analysis::FN_EXTERIOR_PREDICATE);
+
+ auto entry = *solution.begin();
+ string answer = std::get<0>(TranscendLayer::parse<std::string>(entry.second));
+ ASSERT_STREQ("fn-RecUpdateInLoop1", answer.c_str());
+}
+
TEST(Transcend, Doc_Expressions1) {
string code = getDocumentationExampleById("documentation/Transcend/transcend.xml", "Expressions1");
XreateManager* man = XreateManager::prepare(move(code));
man->run();
delete man;
ASSERT_TRUE(true);
}
TEST(Transcend, Doc_SlaveTypes1){
string code = getDocumentationExampleById("documentation/Transcend/transcend.xml", "Codeblocks1");
XreateManager::prepare(move(code));
ASSERT_TRUE(true);
}
TEST(Transcend, Doc_Codeblocks1) {
string code = getDocumentationExampleById("documentation/Transcend/transcend.xml", "Codeblocks1");
XreateManager::prepare(move(code));
ASSERT_TRUE(true);
}
TEST(Transcend, Doc_Diagnostics1) {
string code = getDocumentationExampleById("documentation/Transcend/transcend.xml", "Diagnostics1");
string scriptTranscend = getDocumentationExampleById("documentation/Transcend/transcend.xml", "Diagnostics1_Rules");
string scriptSupport =
R"Code(
scope_func_dict(S, Fn):-
cfa_parent(S, function(Fn)).
scope_func_dict(S1, Fn):-
cfa_parent(S1, scope(S2));
scope_func_dict(S2, Fn).
)Code";
auto man = XreateManager::prepare(move(code));
man->transcend->addRawScript(move(scriptTranscend));
man->transcend->addRawScript(move(scriptSupport));
testing::internal::CaptureStdout();
man->run();
delete man;
std::string outputActual = testing::internal::GetCapturedStdout();
std::cout << outputActual << std::endl;
string outputExpected = "warning(\"Visibility violation\",\"test\",\"sum\")";
ASSERT_NE(std::string::npos, outputActual.find(outputExpected));
}
\ No newline at end of file
diff --git a/scripts/containers/RecUpdateInLoop1.xreate b/scripts/containers/RecUpdateInLoop1.xreate
deleted file mode 100644
index 18f677e..0000000
--- a/scripts/containers/RecUpdateInLoop1.xreate
+++ /dev/null
@@ -1,12 +0,0 @@
-Rec = type {x:: int, y:: int}.
-
-test = function(base:: int):: int; entry() {
- fields = intrinsic rec_fields("Rec"):: [string]; i12n(on()).
-
- result = loop fold(fields->field:: string, {undef, 0}->ctx):: {rec:: Rec, id:: int}
- {
- { (ctx["rec"]::Rec) : {[field] = base + ctx["id"] }, ctx["id"]+1 }:: {rec:: Rec, id:: int}
- }.
-
- result["rec"]["y"]
-}
diff --git a/scripts/containers/containers-tests.assembly.lp b/scripts/containers/containers-tests.assembly.lp
index a9e3d97..c0c6b76 100644
--- a/scripts/containers/containers-tests.assembly.lp
+++ b/scripts/containers/containers-tests.assembly.lp
@@ -1,9 +1,6 @@
-select(test(common)).
-%select(function("fn-RetRange1")).
-
bind_func(Fn, exterior):-
select(test(Template));
bind_func(Fn, test(Template)).
bind_func(FnName, exterior):-
select(function(FnName)).
diff --git a/scripts/containers/containers-tests.xreate b/scripts/containers/containers-tests.xreate
index 79bc100..2a617fc 100644
--- a/scripts/containers/containers-tests.xreate
+++ b/scripts/containers/containers-tests.xreate
@@ -1,88 +1,110 @@
import raw ("scripts/containers/containers-tests.assembly.lp").
Test = type predicate{
common
}.
FnAnns = type predicate{
test(kind:: Test)
}
min = function(x:: [int]; csize(5)):: int
{
loop fold((x:: [int]; csize(5))->el:: int, 1000->min):: int
{
if (el < min):: int { el } else { min }
}
}
min2 = function(x:: [int]; fly(csize(5))):: int
{
loop fold((x:: [int]; fly(csize(5)))->el:: int, 1000->min):: int
{
if (el < min):: int { el } else { min }
}
}
+Rec = type {x:: int, y:: int}.
+
+fn-RecUpdateInLoop1 = function(base:: int):: int {
+ fields = intrinsic fields("Rec"):: [string]; i12n(on()).
+
+ result = loop fold(fields->field:: string, {undef, 0}->ctx):: {rec:: Rec, id:: int}
+ {
+ { (ctx["rec"]::Rec) : {[field] = base + ctx["id"] }, ctx["id"]+1 }:: {rec:: Rec, id:: int}
+ }.
+
+ result["rec"]["y"]
+}
+
+fn-Keys1 = function:: int
+{
+ data = {16, 3, 2, 5}:: [int]; csize(4).
+ keys = intrinsic keys(data):: [int]; range().
+
+ loop fold(keys-> key:: int, 0->sum):: int
+ { sum + key }
+}
+
fn-ArrayArg1 = function:: int; test(common())
{
a = {3, 2, 1, 4, 5}:: [int]; csize(5).
min(a)
}
fn-FlyArg1 = function:: int; test(common())
{
a = {3, 2, 1, 4, 5}:: [int]; csize(5).
b = loop map(a->x:: int):: [int]; fly(csize(5))
{
8 * x :: int
}.
min2(b)
}
fn-Range1 = function:: int; test(common())
{
range = [1..5]:: [int]; range().
loop fold(range->x:: int, 0->sum):: int {sum + x}
}
fn-Range2 = function:: int; test(common())
{
range1 = [1..5]:: [int]; range().
range2 = loop map (range1->x:: int):: [int]; fly(range()) {2 * x:: int}.
loop fold(range2->x:: int, 0->sum):: int {sum + x}
}
fn-GenRange1 = function:: [int]; range()
{
[1..5]:: [int]; range()
}
fn-RetRange1 = function:: int; test(common())
{
loop fold((fn-GenRange1()::[int]; range()) -> x:: int, 0->sum):: int
{ sum + x }
}
/*
reorder = function(aggrSrc:: [int], idxs::[int]):: [int]
{
loop map(idxs->idx)::[int]
{
aggrSrc[idx])
}
}
reverse = function(aggrSrc::[int])::[int]
{
sizeDst = 5:: int.
idxsDst = intrinsic keys(aggrSrc):: [int].
idxsTnsf = loop map(idxsDst-> idx:: int):: [int]
{
sizeDst - idx - 1
}
reorder(aggrSrc, idxsTnsf)
}
*/
Event Timeline
Log In to Comment