No OneTemporary

File Metadata

Created
Sun, Feb 15, 5:15 PM
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/config/default.json b/config/default.json
index f3144c4..db18ff7 100644
--- a/config/default.json
+++ b/config/default.json
@@ -1,37 +1,39 @@
{
- "template": "problems",
+ "template": "containers",
"templates": {
- "bugs":"Containers.DONE_ArrayUpdate1",
+ "bugs":"Compilation.BUG_Minus1",
"default": "*-Colevels.*:Interpretation.*",
"documentation":"Modules.Doc_*:Modules_API.Doc_*:Interpretation.Doc_*:AST.Doc_*:Loop.Doc_*:LateReasoning.Doc_*:Latex.Doc_*:Polymorphs.Doc_*:Transcend.Doc_*:ASTCorrespondence.Doc_*:Virtualization.Doc_*:Exploitation.Doc_*:Communication.Doc_*:Introduction.*",
"ast": "AST.*",
"effects": "Effects.*",
"basic": "Attachments.*",
"dimensions": "Dimensions.CompileDeepAnn1",
- "compilation": "Compilation.*",
+ "compilation": "Compilation.LLVMAliases",
"communication": "Communication.*",
"cfa": "CFA.*",
- "containers": "Containers.DONE_*",
+ "containers": "Compilation.Lambda*:Compilation.MM*:Containers.*:Problems.*",
"dfa": "DFA.*",
"diagnostic": "Diagnostic.*",
"dsl": "Interpretation.*:Association.*",
"exploitation": "Exploitation.*",
"ExpressionSerializer": "ExpressionSerializer.*",
"externc": "InterfaceExternC.*",
"loops": "Loop.*",
"latereasoning": "LateReasoning.*",
"latex": "Latex.*",
+ "lambdas": "AST.Lambda*:Compilation.Lambda*",
"modules": "Modules.*",
"polymorphs": "PDT.BuildDTTable1",
"problems": "Problems.MinMax1",
+ "mm": "Compilation.MM*",
"arithmetics": "Arithmetics.*",
"intrinsic-query": "Types.SlaveTypes*:Association.TypedQuery*",
"types": "Types.*",
"universal": "Universal.*",
"virtualization": "Virtualization.*",
"vendorsAPI/clang": "ClangAPI.*",
"vendorsAPI/xml2": "libxml2.*"
}
}
diff --git a/cpp/Configurations.cmake b/cpp/Configurations.cmake
index 2c732b0..65cff38 100644
--- a/cpp/Configurations.cmake
+++ b/cpp/Configurations.cmake
@@ -1,161 +1,164 @@
cmake_minimum_required(VERSION 2.8.11)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -fprofile-arcs -ftest-coverage -O0")
set(XREATE_DEFINITIONS_COMMON
-D_GNU_SOURCE
-D__STDC_CONSTANT_MACROS
-D__STDC_FORMAT_MACROS
-D__STDC_LIMIT_MACROS
-DWITH_THREADS=1
)
#------------------------------------------------------
# CONFIGURATION: Min
set(XREATE_SOURCE_FILES_MIN
- compilation/resources.cpp
- analysis/typeinference.cpp
- xreatemanager.cpp
- transcendlayer.cpp
- llvmlayer.cpp
- pass/compilepass.cpp
- analysis/utils.cpp
- ast.cpp
- aux/xreatemanager-decorators.cpp
- compilation/transformations.cpp
- compilation/transformersaturation.cpp
- attachments.cpp
- compilation/control.cpp
- utils.cpp
- pass/abstractpass.cpp
- aux/serialization/expressionserializer.cpp
- analysis/transcendtarget.cpp analysis/resources.cpp
- query/containers.cpp
- modules.cpp
- compilation/containers.cpp
- compilation/containers/arrays.cpp
- aux/kludges.cpp
+ compilation/resources.cpp
+ analysis/typeinference.cpp
+ xreatemanager.cpp
+ transcendlayer.cpp
+ llvmlayer.cpp
+ pass/compilepass.cpp
+ analysis/utils.cpp
+ ast.cpp
+ aux/xreatemanager-decorators.cpp
+ compilation/transformations.cpp
+ compilation/transformersaturation.cpp
+ attachments.cpp
+ compilation/control.cpp
+ utils.cpp
+ pass/abstractpass.cpp
+ aux/serialization/expressionserializer.cpp
+ analysis/transcendtarget.cpp analysis/resources.cpp
+ query/containers.cpp
+ modules.cpp
+ compilation/containers.cpp
+ compilation/containers/arrays.cpp
+ aux/kludges.cpp
)
set(XREATE_TEST_FILES_MIN
universal.cpp
introduction.cpp
unit-test-example.cpp
supplemental/docutils
transcend.cpp
association.cpp
main.cpp
attachments.cpp
ast.cpp
compilation.cpp
ExpressionSerializer.cpp
types.cpp
#vendorsAPI/clangAPI.cpp
#vendorsAPI/xml2.cpp
#vendorsAPI/json.cpp
loops.cpp
#supplemental/versions-algorithm-data_dependency.cpp
supplemental/basics.cpp
arithmetics.cpp
)
IF(XREATE_CONFIG STREQUAL "Min")
set(XREATE_SOURCE_FILES
${XREATE_SOURCE_FILES_MIN}
)
set(XREATE_TEST_FILES ${XREATE_TEST_FILES_MIN})
set(XREATE_DEFINITIONS ${XREATE_DEFINITIONS_COMMON}
-DXREATE_CONFIG_MIN
)
ENDIF()
#------------------------------------------------------
# CONFIGURATION: Default
set(XREATE_SOURCE_FILES_DEFAULT ${XREATE_SOURCE_FILES_MIN}
compilation/targetinterpretation.cpp
analysis/temporalseqgraph.cpp
pass/cfatemporalseqpass.cpp
analysis/cfagraph.cpp
pass/cfapass.cpp
compilation/interpretation-instructions.cpp
ExternLayer.cpp
analysis/cfagraph.cpp
compilation/latetranscend.cpp
query/latex.cpp
aux/latereasoning.cpp
analysis/dfagraph.cpp
pass/dfapass.cpp
pass/interpretationpass.cpp
pass/versionspass.cpp
contextrule.cpp
compilation/demand.cpp
analysis/predefinedanns.cpp
)
set(XREATE_TEST_FILES_DEFAULT ${XREATE_TEST_FILES_MIN}
interpretation.cpp
transcend-ast.cpp
cfa.cpp
latetranscend.cpp
latex.cpp
polymorph.cpp
virtualization.cpp
exploitation.cpp
effects-communication.cpp
modules.cpp
dfa.cpp
effects-versions.cpp
containers.cpp
externc.cpp
aux/expressions.cpp
polymorphism-dt.cpp
)
IF(XREATE_CONFIG STREQUAL "Default")
set(XREATE_SOURCE_FILES
${XREATE_SOURCE_FILES_DEFAULT}
)
set(XREATE_TEST_FILES ${XREATE_TEST_FILES_DEFAULT})
set(XREATE_DEFINITIONS ${XREATE_DEFINITIONS_COMMON}
XREATE_ENABLE_EXTERN
)
ENDIF()
#------------------------------------------------------
# CONFIGURATION: Dimensions
IF(XREATE_CONFIG STREQUAL "Dimensions")
set(XREATE_SOURCE_FILES ${XREATE_SOURCE_FILES_MIN}
+ query/contextalloc.cpp
+ compilation/context.cpp
compilation/lambdas.cpp
query/demand.cpp
compilation/demand.cpp
query/polymorph.cpp
compilation/polymorph.cpp
aux/expressions.cpp
pass/interpretationpass.cpp
compilation/targetinterpretation.cpp
compilation/intrinsics.cpp
# compilation/containerinst.cpp
analysis/predefinedanns.cpp
analysis/typehints.cpp
+ compilation/mm.cpp
)
set(XREATE_TEST_FILES ${XREATE_TEST_FILES_MIN}
interpretation.cpp
dimensions.cpp
polymorph.cpp
polymorphism-dt.cpp
containers.cpp
problems.cpp
)
set(XREATE_DEFINITIONS ${XREATE_DEFINITIONS_COMMON}
-DXREATE_CONFIG_MIN
)
ENDIF()
diff --git a/cpp/src/analysis/predefinedanns.cpp b/cpp/src/analysis/predefinedanns.cpp
index 807a633..fdcc9fa 100644
--- a/cpp/src/analysis/predefinedanns.cpp
+++ b/cpp/src/analysis/predefinedanns.cpp
@@ -1,88 +1,102 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: predefinedanns.cpp
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on 19/03/2020
*/
#include "analysis/predefinedanns.h"
#include "analysis/resources.h"
namespace xreate{ namespace analysis{
PredefinedAnns
PredefinedAnns::__instance = PredefinedAnns();
PredefinedAnns::PredefinedAnns(){
fnAnnsT = TypeAnnotation(TypeOperator::VARIANT, {});
exprAnnsT = TypeAnnotation(TypeOperator::VARIANT, {});
//Function annotations
- fnAnnsT.__operands.push_back(TypePrimitive::Invalid);
fnAnnsT.fields.push_back(FN_ENTRY_PREDICATE);
fnAnnsT.__operands.push_back(TypePrimitive::Invalid);
+
fnAnnsT.fields.push_back(FN_EXTERIOR_PREDICATE);
+ fnAnnsT.__operands.push_back(TypePrimitive::Invalid);
+
+ fnAnnsT.fields.push_back(FN_ALLOCAPAD_P);
+ fnAnnsT.__operands.push_back(TypePrimitive::Invalid);
//interpretation
i12nModeT = TypeAnnotation(TypeOperator::VARIANT, {
TypePrimitive::Invalid,
TypePrimitive::Invalid
});
i12nModeT.fields.push_back("on");
i12nModeT.fields.push_back("off");
exprAnnsT.__operands.push_back(i12nModeT);
exprAnnsT.fields.push_back("i12n");
//Int
hintsIntT = TypeAnnotation(TypeOperator::VARIANT, {
TypePrimitive ::Int
});
hintsIntT.fields.push_back("size");
//Containers
hintsContT = TypeAnnotation(TypeOperator::VARIANT, {
TypePrimitive::Int,
TypeAnnotation(TypeOperator::REF, {TypeAnnotation::alias("hintsContT")}),
TypePrimitive ::Invalid
});
hintsContT.fields.push_back(CONTAINERS_IMPL_ARRAY_PREDICATE);
hintsContT.fields.push_back(CONTAINERS_IMPL_FLY_PREDICATE);
hintsContT.fields.push_back(CONTAINERS_IMPL_RANGE_PREDICATE);
+
+ allocaT = TypeAnnotation(TypeOperator::VARIANT, {
+ TypePrimitive ::String
+ });
+ allocaT.fields.push_back(VAR_ALLOCA_P);
}
void
PredefinedAnns::registerVariants(std::map<std::string, std::pair<TypeAnnotation, int>> &__registry) const{
//annotation; type; variant id;
__registry = {
+
//Functions:
{FN_ENTRY_PREDICATE, {fnAnnsT, (unsigned) FnAnnotations::ENTRY}},
{FN_EXTERIOR_PREDICATE, {fnAnnsT, (unsigned) FnAnnotations::EXTERIOR}},
+ {FN_ALLOCAPAD_P, {fnAnnsT, (unsigned) FnAnnotations::ALLOCAPAD}},
//Expressions:
{"i12n", {exprAnnsT, (unsigned) ExprAnnotations::I12N}},
//Interpretation:
{"on", {i12nModeT, (unsigned) I12ModeTag::ON}},
{"off", {i12nModeT, (unsigned) I12ModeTag::OFF}},
//Int:
{"size", {hintsIntT, (unsigned) IntHints::SIZE}},
//Containers
{CONTAINERS_IMPL_ARRAY_PREDICATE, {hintsContT, (unsigned) ContHints::ARRAY}},
{CONTAINERS_IMPL_FLY_PREDICATE, {hintsContT, (unsigned) ContHints::FLY}},
{CONTAINERS_IMPL_RANGE_PREDICATE, {hintsContT, (unsigned) ContHints::RANGE}},
+
+ //Alloca:
+ {VAR_ALLOCA_P, {allocaT, (unsigned) AllocaAnns::ALLOCA}},
};
}
void
PredefinedAnns::registerAliases(std::map<std::string, TypeAnnotation> &__registry) const{
__registry = {
{"hintsContT", hintsContT}
};
}
}}
\ No newline at end of file
diff --git a/cpp/src/analysis/predefinedanns.h b/cpp/src/analysis/predefinedanns.h
index 2cbad67..56f0865 100644
--- a/cpp/src/analysis/predefinedanns.h
+++ b/cpp/src/analysis/predefinedanns.h
@@ -1,55 +1,60 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: predefinedanns.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on 19/03/2020
*/
#ifndef XREATE_PREDEFINEDANNS_H
#define XREATE_PREDEFINEDANNS_H
#include "ast.h"
namespace xreate{ namespace analysis{
class PredefinedAnns{
public:
enum class FnAnnotations{
- ENTRY, EXTERIOR
+ ENTRY, EXTERIOR, ALLOCAPAD
};
enum class ExprAnnotations{
I12N
};
enum class I12ModeTag{
ON, OFF
};
enum class IntHints{
SIZE
};
+ enum class AllocaAnns{
+ ALLOCA
+ };
+
enum class ContHints{
ARRAY, FLY, RANGE
};
TypeAnnotation fnAnnsT;
TypeAnnotation exprAnnsT;
+ TypeAnnotation allocaT;
TypeAnnotation hintsIntT;
TypeAnnotation hintsContT;
//Interpretation
TypeAnnotation i12nModeT;
PredefinedAnns();
static const PredefinedAnns& instance(){ return __instance; }
void registerVariants(std::map<std::string, std::pair<TypeAnnotation, int>> &__registry) const;
void registerAliases(std::map<std::string, TypeAnnotation>& __registry) const;
private:
static PredefinedAnns __instance;
};
}} // end of xreate::analysis
#endif //XREATE_PREDEFINEDANNS_H
diff --git a/cpp/src/analysis/resources.cpp b/cpp/src/analysis/resources.cpp
index 69c22cd..c328d10 100644
--- a/cpp/src/analysis/resources.cpp
+++ b/cpp/src/analysis/resources.cpp
@@ -1,27 +1,30 @@
#include "analysis/resources.h"
namespace xreate{namespace analysis{
const char *VAR_ANN_PREDICATE_TPL = "bind(%1%, %2%)";
const char *VAR_ANN_PREDICATE = "bind";
const char *SCOPE_ANN_PREDICATE_TPL = "bind_scope(%1%, %2%)";
const char *SCOPE_ANN_PREDICATE = "bind_scope";
const char *FUNCTION_ANN_PREDICATE_TPL = "bind_func(\"%1%\", %2%)";
const char *FUNCTION_ANN_PREDICATE = "bind_func";
const char *TRANSCEND_PASS_SECTION = "% == STATIC ANALYSIS: ANNOTATIONS ==";
const char *FUNCTION_PREDICATE_TPL = "function(\"%1%\")";
const char *SITE_SYMBOL_PREDICATE = "s";
const char *SITE_ANON_PREDICATE = "a";
const char *DEMAND_FORMAL_PREDICATE = "func_demand";
const char *DEMAND_ACTUAL_PREDICATE = "func_supply";
const char *FN_ENTRY_PREDICATE = "entry";
const char *FN_EXTERIOR_PREDICATE = "exterior";
const char *POLYMORPH_SUPPLY_PREDICATE = "func_supply_guard";
-extern const char *CONTAINERS_IMPL_ARRAY_PREDICATE = "csize";
-extern const char *CONTAINERS_IMPL_FLY_PREDICATE = "fly";
-extern const char *CONTAINERS_IMPL_RANGE_PREDICATE = "range";
+const char *CONTAINERS_IMPL_ARRAY_PREDICATE = "csize";
+const char *CONTAINERS_IMPL_FLY_PREDICATE = "fly";
+const char *CONTAINERS_IMPL_RANGE_PREDICATE = "range";
const char *CONTAINERS_ID_IMPL_PREDICATE = "containers_impl";
const char *CONTAINERS_ID_LINKLIST_PREDICATE = "linkedlist";
+
+const char *VAR_ALLOCA_P = "alloca";
+const char *FN_ALLOCAPAD_P = "allocapad";
}}
\ No newline at end of file
diff --git a/cpp/src/analysis/resources.h b/cpp/src/analysis/resources.h
index 3d4a9df..6335f8a 100644
--- a/cpp/src/analysis/resources.h
+++ b/cpp/src/analysis/resources.h
@@ -1,40 +1,44 @@
//
// Created by pgess on 15/01/2020.
//
-#ifndef XREATE_RESOURCES_H
-#define XREATE_RESOURCES_H
+
#include "transcendlayer.h"
-#include <tuple>
#include <string>
+#include <tuple>
+
+#ifndef XREATE_ANALYSIS_RESOURCES_H
+#define XREATE_ANALYSIS_RESOURCES_H
namespace xreate{namespace analysis {
extern const char *FUNCTION_PREDICATE_TPL;
extern const char *FUNCTION_ANN_PREDICATE_TPL;
extern const char *FUNCTION_ANN_PREDICATE;
extern const char *SCOPE_ANN_PREDICATE_TPL;
extern const char *SCOPE_ANN_PREDICATE;
extern const char *VAR_ANN_PREDICATE_TPL;
extern const char *VAR_ANN_PREDICATE;
extern const char *TRANSCEND_PASS_SECTION;
extern const char *SITE_SYMBOL_PREDICATE;
extern const char *SITE_ANON_PREDICATE;
extern const char *DEMAND_FORMAL_PREDICATE;
extern const char *DEMAND_ACTUAL_PREDICATE;
extern const char *POLYMORPH_SUPPLY_PREDICATE;
extern const char *FN_ENTRY_PREDICATE;
extern const char *FN_EXTERIOR_PREDICATE;
-
extern const char *CONTAINERS_IMPL_ARRAY_PREDICATE;
extern const char *CONTAINERS_IMPL_FLY_PREDICATE;
extern const char *CONTAINERS_IMPL_RANGE_PREDICATE;
+extern const char *VAR_ALLOCA_P;
+extern const char *FN_ALLOCAPAD_P;
extern const char *CONTAINERS_ID_IMPL_PREDICATE;
extern const char *CONTAINERS_ID_LINKLIST_PREDICATE;
typedef std::tuple<std::string, std::string, std::string> DEMAND_FORMAL_SCHEME; //fn, key, type-alias
typedef std::tuple<xreate::ASTSitePacked, std::string, Gringo::Symbol> DEMAND_ACTUAL_SCHEME; //fn, key, type-alias
typedef std::tuple<xreate::ASTSitePacked, Gringo::Symbol, std::string> POLYMORPH_SUPPLY_SCHEME; //site, data, type-variant
-
+typedef std::tuple<std::string> FN_ALLOCAPAD_SCHEME;
+typedef std::tuple<std::string> VAR_ALLOCA_SCHEME;
}}
#endif //XREATE_RESOURCES_H
diff --git a/cpp/src/analysis/typehints.cpp b/cpp/src/analysis/typehints.cpp
index 3bba26d..d0a31ff 100644
--- a/cpp/src/analysis/typehints.cpp
+++ b/cpp/src/analysis/typehints.cpp
@@ -1,74 +1,88 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: typehints.cpp
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on 24/03/2020
*/
#include "analysis/typehints.h"
#include "analysis/predefinedanns.h"
#include "analysis/utils.h"
#include "aux/expressions.h"
namespace xreate{namespace typehints{
namespace impl {
template<class Hint>
inline Hint getHint(const Expression& e, const Hint& def, unsigned annId, const ExpandedType& hintT){
const std::list<Expression>& hintsL = getAnnotations(e);
auto predefined = analysis::PredefinedAnns::instance();
const Expression& hintActual = analysis::findAnnById(annId, hintT, hintsL);
if (!hintActual.isValid()){
return def;
}
return parse<Hint>(hintActual);
}
}
template<> IntBits
parse(const Expression& e){
return {(unsigned) e.operands.at(0).getValueDouble()};
}
template<> ArrayHint
parse(const Expression& e){
return {(unsigned) e.operands.at(0).getValueDouble()};
}
template<> FlyHint
parse(const Expression& e){
return {e.operands.at(0)};
}
+template<> ContextAllocHint
+parse(const Expression& e){
+ return {e.operands.at(0).getValueString()};
+}
+
template<> IntBits
find(const Expression& e, const IntBits& def){
auto predefined = analysis::PredefinedAnns::instance();
return impl::getHint<IntBits>(e, def,
(unsigned) analysis::PredefinedAnns::IntHints::SIZE,
ExpandedType(predefined.hintsIntT)
);
}
template<> ArrayHint
find(const Expression& e, const ArrayHint& def){
auto predefined = analysis::PredefinedAnns::instance();
return impl::getHint<ArrayHint>(e, def,
(unsigned) analysis::PredefinedAnns::ContHints::ARRAY,
ExpandedType(predefined.hintsContT)
);
}
template<> FlyHint
find(const Expression& e, const FlyHint& def){
auto predefined = analysis::PredefinedAnns::instance();
return impl::getHint<FlyHint>(e, def,
(unsigned) analysis::PredefinedAnns::ContHints::FLY,
ExpandedType(predefined.hintsContT));
}
+template<> ContextAllocHint
+find(const Expression& e, const ContextAllocHint& def){
+ auto predefined = analysis::PredefinedAnns::instance();
+
+ return impl::getHint<ContextAllocHint>(e, def,
+ (unsigned) analysis::PredefinedAnns::AllocaAnns::ALLOCA,
+ ExpandedType(predefined.allocaT));
+}
+
}}
\ No newline at end of file
diff --git a/cpp/src/analysis/typehints.h b/cpp/src/analysis/typehints.h
index 33a7880..2b5a15c 100644
--- a/cpp/src/analysis/typehints.h
+++ b/cpp/src/analysis/typehints.h
@@ -1,53 +1,61 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* typehints.h
*
* Author: pgess <v.melnychenko@xreate.org>
*/
/**
* \file typehints.h
* \brief Type inference hints
*/
#ifndef XREATE_TYPEHINTS_H
#define XREATE_TYPEHINTS_H
#include "ast.h"
namespace xreate{namespace typehints{
struct IntBits{
unsigned int size;
};
struct ArrayHint{
size_t size;
};
struct FlyHint{
Expression hintSrc;
};
+struct ContextAllocHint{
+ std::string pad;
+};
+
template<class Typ>
Typ find(const Expression& e, const Typ& def);
template<>
IntBits find(const Expression& e, const IntBits& def);
template<>
ArrayHint find(const Expression& e, const ArrayHint& def);
+template<>
+ContextAllocHint find(const Expression& e, const ContextAllocHint& def);
+
template<>
FlyHint find(const Expression& e, const FlyHint& def);
template<class Typ>
Typ parse(const Expression& e);
template<> IntBits parse(const Expression& e);
template<> ArrayHint parse(const Expression& e);
+template<> ContextAllocHint parse(const Expression& e);
}}
#endif //XREATE_TYPEHINTS_H
diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp
index f313cff..4c25f9e 100644
--- a/cpp/src/ast.cpp
+++ b/cpp/src/ast.cpp
@@ -1,973 +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},
{"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){
+ if (bindExternalArgs && result){
Symbol identS = Attachments::get<IdentifierSymbol>(identE);
- boundExternalSymbs.insert(identS);
+ boundArgs.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)){
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 20f7ea9..4cfba9e 100644
--- a/cpp/src/ast.h
+++ b/cpp/src/ast.h
@@ -1,755 +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;
+ bool bindExternalArgs = false;
+ std::set<Symbol> boundArgs;
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,
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/attachments.h b/cpp/src/attachments.h
index 8b9c0cb..3243f01 100644
--- a/cpp/src/attachments.h
+++ b/cpp/src/attachments.h
@@ -1,184 +1,183 @@
/* 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: attachments.h
* Date: 3/15/15
*/
/**
* \file attachments.h
* \brief The attachments support: a mechanism to attach additional data to AST nodes
*/
#ifndef _XREATE_ATTACHMENTS_H_
#define _XREATE_ATTACHMENTS_H_
#include <unordered_map>
#include <vector>
#include <assert.h>
#include <type_traits>
namespace xreate
{
/** \brief Attachments dictionary */
- template<class Tag>
- struct AttachmentsDict
- {
- // typedef void Data;
- // static const unsigned int key (next vacant id - 12);
-
// Defined attachments:
-//-----------------------------------------------------
+//-----------------------------------------------------
// 1 containers::Implementation
// 3 interpretation::InterpretationData
// 5 interpretation::I12nFunctionSpec
// 6 VariableVersion
// 7 IdentifierSymbol
// 8 versions::VersionImposedDependency
// 9 ExprAlias_A
// 11 TypeInferred
// 12 ExprId_A
+ template<class Tag>
+ struct AttachmentsDict
+ {
+ // typedef void Data;
+ // static const unsigned int key (next vacant id - 13);
};
-
+
template<class Object>
struct AttachmentsId{
//static unsigned int getId(const Object& object);
};
template<class Data>
class IAttachmentsContainer{
protected:
virtual bool __exists(const unsigned int object)=0;
virtual Data& __get(const unsigned int object)=0;
virtual void __put(const unsigned int object, Data data)=0;
public:
template<class Id>
bool exists(const Id& object){
unsigned int id = AttachmentsId<Id>::getId(object);
return __exists(id);
}
template<class Id>
Data& get(const Id& object){
unsigned int id = AttachmentsId<Id>::getId(object);
return __get(id);
}
template<class Id>
Data get(const Id& object, const Data& dataDefault){
unsigned int id = AttachmentsId<Id>::getId(object);
if (! __exists(id)){
return dataDefault;
}
return __get(id);
}
template<class Id>
void put(const Id& object, Data data){
unsigned int id = AttachmentsId<Id>::getId(object);
__put(id, data);
}
virtual ~IAttachmentsContainer(){};
};
template<class Data>
class AttachmentsContainerDefault: public IAttachmentsContainer<Data>{
private:
std::unordered_map<unsigned int, Data> __data;
virtual bool __exists(const unsigned int id){
return __data.count(id);
}
virtual Data& __get(const unsigned int id){
return __data.at(id);
}
virtual void __put(const unsigned int id, Data data){
auto result = __data.emplace(id, data);
assert(result.second);
}
public:
std::unordered_map<unsigned int, Data>& getRawStorage() {
return __data;
}
};
/** \brief Implements %AST attachments mechanism to facilitate data sharing among different analyzers and compilation phases */
class Attachments{
private:
static std::vector<void*> __storage;
template<class Tag>
using Data = typename AttachmentsDict<Tag>::Data;
public:
template<class Tag, class Id>
static bool exists(const Id& object) {
assert(AttachmentsDict<Tag>::key < __storage.size());
assert(__storage.at(AttachmentsDict<Tag>::key));
IAttachmentsContainer<Data<Tag>>* self = reinterpret_cast<IAttachmentsContainer<Data<Tag>>*>(__storage.at(AttachmentsDict<Tag>::key));
return self->exists(object);
}
template<class Tag, class Id>
static Data<Tag>& get(const Id& object){
assert(AttachmentsDict<Tag>::key < __storage.size());
assert(__storage.at(AttachmentsDict<Tag>::key));
IAttachmentsContainer<Data<Tag>>* self = reinterpret_cast<IAttachmentsContainer<Data<Tag>>*>(__storage.at(AttachmentsDict<Tag>::key));
return self->get(object);
}
template<class Tag, class Id>
static Data<Tag> get(const Id& object, const Data<Tag>& dataDefault){
assert(AttachmentsDict<Tag>::key < __storage.size());
assert(__storage.at(AttachmentsDict<Tag>::key));
IAttachmentsContainer<Data<Tag>>* self = reinterpret_cast<IAttachmentsContainer<Data<Tag>>*>(__storage.at(AttachmentsDict<Tag>::key));
return self->get(object, dataDefault);
}
template<class Tag, class Id>
static void put(const Id& object, Data<Tag> data){
assert(AttachmentsDict<Tag>::key < __storage.size());
assert(__storage.at(AttachmentsDict<Tag>::key));
IAttachmentsContainer<Data<Tag>>* self = reinterpret_cast<IAttachmentsContainer<Data<Tag>>*>(__storage.at(AttachmentsDict<Tag>::key));
self->put(object, data);
}
template<class Tag>
static void init(){
unsigned int keyStorage = AttachmentsDict<Tag>::key;
if (keyStorage+1 > __storage.size()){
__storage.resize(keyStorage + 1, nullptr);
}
__storage[keyStorage] = new AttachmentsContainerDefault<Data<Tag>>();
}
template<class Tag>
static void init(IAttachmentsContainer<Data<Tag>>* container){
unsigned int keyStorage = AttachmentsDict<Tag>::key;
if (keyStorage+1 > __storage.size()){
__storage.resize(keyStorage + 1, nullptr);
}
__storage[keyStorage] = container;
}
};
}
#endif //_XREATE_ATTACHMENTS_H_
diff --git a/cpp/src/aux/xreatemanager-decorators.cpp b/cpp/src/aux/xreatemanager-decorators.cpp
index e882b7a..5a5f5f6 100644
--- a/cpp/src/aux/xreatemanager-decorators.cpp
+++ b/cpp/src/aux/xreatemanager-decorators.cpp
@@ -1,103 +1,103 @@
/* 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/.
*
* xreatemanager-decorators.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on July 16, 2017, 4:40 PM
*/
/**
* \file xreatemanager-decorators.h
* \brief \ref xreate::XreateManager decorators to provide various functionality
*/
#include "aux/xreatemanager-decorators.h"
#include "main/Parser.h"
#include "pass/compilepass.h"
#include "transcendlayer.h"
#include "analysis/transcendtarget.h"
#include "pass/interpretationpass.h"
#ifndef XREATE_CONFIG_MIN
#include "pass/cfapass.h"
#include "pass/dfapass.h"
#include "pass/versionspass.h"
#include "pass/cfatemporalseqpass.h"
#endif
namespace xreate{
void
XreateManagerDecoratorBase::initPasses() { }
void
XreateManagerDecoratorBase::prepareCode(std::string&& code) {
grammar::main::Scanner scanner(reinterpret_cast<const unsigned char*> (code.c_str()), code.size());
grammar::main::Parser parser(&scanner);
parser.Parse();
assert(!parser.errors->count && "Parser errors");
PassManager::prepare(parser.root->finalize());
}
void
XreateManagerDecoratorBase::prepareCode(FILE* code){
grammar::main::Scanner scanner(code);
grammar::main::Parser parser(&scanner);
parser.Parse();
assert(!parser.errors->count && "Parser errors");
PassManager::prepare(parser.root->finalize());
}
void
XreateManagerDecoratorBase::analyse() {
- CompilePass::prepareQueries(transcend);
- transcend->run();
+ CompilePass::prepareQueries(transcend);
+ transcend->run();
}
void
XreateManagerDecoratorFull::initPasses() {
#ifndef XREATE_CONFIG_MIN
cfa::CFAPass* passCFG = new cfa::CFAPass(this);
registerPass(new dfa::DFAPass(this), PassId::DFAPass);
registerPass(passCFG, PassId::CFAPass);
registerPass(new versions::VersionsPass(this), PassId::VersionsPass);
registerPass(new cfa::CFATemporalSeqPass(this), PassId::CFATemporalSeqPass);
#endif
registerPass(new interpretation::InterpretationPass(this), PassId::InterpretationPass);
registerPass(new TranscendPass(this), PassId::TranscendPass);
}
void*
XreateManagerDecoratorFull::run() {
transcend->deleteReports();
__compiler = new compilation::CompilePassCustomDecorators<>(this);
__compiler->run();
llvm->print();
llvm->initJit();
if (options.requireEntryFn){
assert(__compiler->getEntryFunction());
}
if (__compiler->getEntryFunction())
return llvm->getFunctionPointer(__compiler->getEntryFunction());
return nullptr;
}
void*
XreateManagerDecoratorFull::getExteriorFn(const string& fnName){
ManagedFnPtr fnTarget = root->findFunction(fnName);
assert(fnTarget);
compilation::IBruteFunction* fnBrute = __compiler->getBruteFn(fnTarget);
llvm::Function* fnRaw = fnBrute->compile();
return llvm->getFunctionPointer(fnRaw);
}
} //namespace xreate
diff --git a/cpp/src/compilation/containers.cpp b/cpp/src/compilation/containers.cpp
index f71c4fd..6f7860c 100644
--- a/cpp/src/compilation/containers.cpp
+++ b/cpp/src/compilation/containers.cpp
@@ -1,374 +1,401 @@
/* 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 xreate::compilation;
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;
}
+uint64_t
+IContainersIR::getAllocSize(const Expression& aggrE, LLVMLayer* llvm){
+ switch( getImplementation(aggrE, llvm->ast)){
+ case ON_THE_FLY: {
+ return FlyIR::getAllocSize(aggrE, llvm);
+ }
+
+ case SOLID:{
+ typehints::ArrayHint hint = typehints::find<typehints::ArrayHint>(aggrE, {});
+ return ArrayIR::getAllocSize(llvm->ast->getType(aggrE), hint, llvm);
+ }
+
+ default: break;
+ }
+
+ return 0;
+}
+
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){
+RecordIR::update(llvm::Value *aggrRaw, const ExpandedType &aggrT, const Expression &updE, const std::string& hintAlias){
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);
+ aggrRaw,
+ valueRaw,
+ keyId);
}
+ aggrRaw->setName(hintAlias);
return aggrRaw;
}
+uint64_t
+FlyIR::getAllocSize(const Expression& expr, LLVMLayer* llvm){
+ assert(expr.op == Operator::MAP);
+ return LambdaIR::getAllocSize(expr.blocks.front(), llvm);
+}
+
llvm::Value*
-FlyIR::init(llvm::Value* sourceRaw, CodeScope* body, const std::string& hintAlias){
+FlyIR::init(llvm::Value* sourceRaw, CodeScope* body, Allocator* allocator, const std::string& hintAlias){
RecordIR recordIR(__context);
- compilation::LambdaIR lambdaIR(__context.pass);
- llvm::Function* fnTransform = lambdaIR.compile(body, hintAlias);
+ compilation::LambdaIR lambdaIR(__context);
+ llvm::Value* lambdaTransform = lambdaIR.compile(body, allocator, hintAlias);
llvm::Value* resultRaw = recordIR.init({
sourceRaw->getType(),
- fnTransform->getFunctionType()->getPointerTo()
+ lambdaTransform->getType()
});
resultRaw = __context.pass->man->llvm->irBuilder.CreateInsertValue(
resultRaw, sourceRaw, 0);
resultRaw = __context.pass->man->llvm->irBuilder.CreateInsertValue(
- resultRaw, fnTransform, 1);
+ resultRaw, lambdaTransform, 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* elRawT = llvm->toLLVMType(ExpandedType(aggrT->__operands.at(0)));
- llvm::Type* fnTnsfTRaw = llvm::FunctionType::get(resultTRaw, llvm::ArrayRef<llvm::Type*>(elTRaw), false);
+ //ERROR: !!LOST INFO ON ARG TYPE !
+ llvm::Type* lmbdTnsfRawT = LambdaIR::getRawType(elRawT, {elRawT}, llvm);
std::vector<llvm::Type*> fieldsVec = {
sourceTRaw,
- fnTnsfTRaw->getPointerTo()
+ lmbdTnsfRawT
};
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){
+FlyIR::getTransformLambda(llvm::Value* aggrRaw){
LLVMLayer* llvm = __context.pass->man->llvm;
- llvm::Value* fnRaw = llvm->irBuilder.CreateExtractValue(aggrRaw, llvm::ArrayRef<unsigned>{1});
+ llvm::Value* lambdaRaw = llvm->irBuilder.CreateExtractValue(aggrRaw, llvm::ArrayRef<unsigned>{1});
- return fnRaw;
+ return lambdaRaw;
}
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();
+ CodeScope* loopSc = expr.blocks.front();
+ std::unique_ptr<Allocator> allocator(Allocator::create(expr, __context));
- return init(sourceRaw, loopS, hintAlias);
+ return init(sourceRaw, loopSc, allocator.get(), 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);
+ compilation::LambdaIR lambdaIR(__context);
+
+ llvm::Value* aggrSrcRaw = flyIR.getSourceAggr(aggrRaw);
+ llvm::Value* valueSrcRaw = srcIterIR->get(aggrSrcRaw, idxRaw);
+ llvm::Value* lambdaTnsfRaw = flyIR.getTransformLambda(aggrRaw);
+ std::unique_ptr<compilation::IFnInvocation> fnTnsfInvoc(lambdaIR.getFnInvocation(lambdaTnsfRaw));
+
+ return (*fnTnsfInvoc)({valueSrcRaw}, hintAlias);
}
llvm::Value*
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));
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 1c919ed..d942330 100644
--- a/cpp/src/compilation/containers.h
+++ b/cpp/src/compilation/containers.h
@@ -1,141 +1,148 @@
/* 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"
+#include "mm.h"
+
+namespace xreate {namespace compilation {
+ class Allocator;
+}};
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 IFwdIteratorIR* getFwdIterator() = 0;
+ static uint64_t getAllocSize(const Expression& aggrE, LLVMLayer* llvm);
- virtual llvm::Value *init(const std::string &hintAlias = "") = 0;
+ virtual IFwdIteratorIR* getFwdIterator() = 0;
+ virtual llvm::Value *init(compilation::Allocator* allocator, 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);
+ llvm::Value* update(llvm::Value* aggrRaw, const ExpandedType& aggrT, const Expression& updE, const std::string& hintAlias);
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* init(llvm::Value* sourceRaw, CodeScope* body, compilation::Allocator* allocator, const std::string& hintAlias);
llvm::Value* getSourceAggr(llvm::Value* aggrRaw);
- llvm::Value* getTransformFn(llvm::Value* aggrRaw);
+ llvm::Value* getTransformLambda(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);
+ static uint64_t getAllocSize(const Expression& expr, 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 5cd0ce7..3d94bf0 100644
--- a/cpp/src/compilation/containers/arrays.cpp
+++ b/cpp/src/compilation/containers/arrays.cpp
@@ -1,179 +1,185 @@
/* 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"
+#include "compilation/mm.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();
}
+uint64_t
+ArrayIR::getAllocSize(const ExpandedType& aggrT, const typehints::ArrayHint& hint, LLVMLayer* llvm){
+ llvm::PointerType* aggrRawT = getRawType(aggrT, hint, llvm);
+
+ return llvm->module->getDataLayout().getTypeStoreSize(aggrRawT->getElementType());
+}
+
llvm::Value*
-ArrayIR::init(const string& hintAlias){
+ArrayIR::init(compilation::Allocator* allocator, 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);
+ llvm::Value* aggrRaw = allocator->allocate(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 77c6586..d4919cb 100644
--- a/cpp/src/compilation/containers/arrays.h
+++ b/cpp/src/compilation/containers/arrays.h
@@ -1,65 +1,66 @@
/* 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 *init(compilation::Allocator* allocator, const std::string &hintAlias = "") override;
virtual llvm::Value *update(llvm::Value *aggrRaw, const Expression &updE, const std::string &hintAlias) 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);
+ static uint64_t getAllocSize(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/context.cpp b/cpp/src/compilation/context.cpp
new file mode 100644
index 0000000..db5aa1d
--- /dev/null
+++ b/cpp/src/compilation/context.cpp
@@ -0,0 +1,64 @@
+/* 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: context.cpp
+ * Author: pgess <v.melnychenko@xreate.org>
+ *
+ * Created on 25/05/2020
+ */
+
+#include "query/contextalloc.h"
+#include "compilation/context.h"
+#include "llvmlayer.h"
+#include "llvm/IR/GlobalVariable.h"
+
+namespace xreate { namespace compilation{
+
+AllocContext*
+ContextManager::getContext(const std::string& id){
+ if(__contexts.count(id)) return __contexts.at(id);
+
+ AllocContext* context = new AllocContext(id, this, nullptr);
+ __contexts.emplace(id, context);
+ return context;
+}
+
+void
+AllocContext::set(const ASTSite& varS, llvm::Value* varRaw){
+ LLVMLayer* llvm = __man->__pass->man->llvm;
+ GlobalContextTable* tableGlobal = __man->__pass->getGlobalContextTable();
+
+ llvm::Value* varStorage = tableGlobal->getVariable(varS);
+ llvm->irBuilder.CreateStore(varRaw, varStorage);
+}
+
+llvm::Value*
+AllocContext::get(const ASTSite& varS){
+ LLVMLayer* llvm = __man->__pass->man->llvm;
+ GlobalContextTable* tableGlobal = __man->__pass->getGlobalContextTable();
+
+ llvm::Value* varStorage = tableGlobal->getVariable(varS);
+ return llvm->irBuilder.CreateLoad(varStorage);
+}
+
+void
+GlobalContextTable::compile(){
+ LLVMLayer* llvm = __pass->man->llvm;
+ TranscendLayer* transcend = __pass->man->transcend;
+ ContextAllocQuery* query = dynamic_cast<ContextAllocQuery*>(transcend->getQuery(QueryId::ContextAllocQuery));
+ llvm::Type* int8PT = llvm::PointerType::getInt8PtrTy(llvm->llvmContext);
+
+ ContextAllocQuery::Model model = query->getModel();
+ for(const auto& entry: model){
+ llvm::GlobalVariable* varRaw = new llvm::GlobalVariable(
+ *(llvm->module.get()), int8PT, false,
+ llvm::GlobalValue::PrivateLinkage,
+ llvm::UndefValue::get(int8PT)
+ );
+
+ __table.emplace(entry.second, varRaw);
+ }
+}
+
+}} // xreate::compilation
\ No newline at end of file
diff --git a/cpp/src/compilation/context.h b/cpp/src/compilation/context.h
new file mode 100644
index 0000000..a7d1cf5
--- /dev/null
+++ b/cpp/src/compilation/context.h
@@ -0,0 +1,61 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * File: context.h
+ * Author: pgess <v.melnychenko@xreate.org>
+ *
+ * Created on 25/05/2020
+ */
+#ifndef XREATE_CONTEXT_H
+#define XREATE_CONTEXT_H
+
+#include "ast.h"
+#include "pass/compilepass.h"
+
+namespace llvm {
+ class Value;
+ class GlobalVariable;
+}
+
+namespace xreate { namespace compilation{
+class AllocContext {
+public:
+ AllocContext(std::string id, ContextManager* man, AllocContext* parent)
+ : __id(id), __man(man), __parent(parent){}
+
+ void set(const ASTSite& varS, llvm::Value* varRaw);
+ llvm::Value* get(const ASTSite& varS);
+
+private:
+ std::string __id;
+ ContextManager* __man;
+ AllocContext* __parent;
+};
+
+class ContextManager{
+ friend class AllocContext;
+
+public:
+ ContextManager(CompilePass* pass): __pass(pass){};
+ AllocContext* getContext(const std::string& id);
+
+private:
+ std::map<std::string, AllocContext*> __contexts;
+ CompilePass* __pass;
+};
+
+class GlobalContextTable{
+public:
+ GlobalContextTable(CompilePass* pass): __pass(pass){}
+
+ void compile();
+ llvm::GlobalVariable* getVariable(const ASTSite& site){return __table.at(site);}
+
+private:
+ CompilePass* __pass;
+ std::map<ASTSite, llvm::GlobalVariable*> __table;
+};
+
+}} // xreate::compilation
+#endif //XREATE_CONTEXT_H
diff --git a/cpp/src/compilation/contextalloc.h b/cpp/src/compilation/contextalloc.h
new file mode 100644
index 0000000..c455ec3
--- /dev/null
+++ b/cpp/src/compilation/contextalloc.h
@@ -0,0 +1,56 @@
+/* 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: preallocation.h
+ * Author: pgess <v.melnychenko@xreate.org>
+ *
+ * Created on 08/05/2020
+ */
+#ifndef XREATE_PREALLOCATION_H
+#define XREATE_PREALLOCATION_H
+
+#include "query/contextalloc.h"
+#include "compilation/context.h"
+#include "compilation/containers.h"
+#include "compilation/resources.h"
+
+namespace xreate {
+
+template<class Parent>
+class ContextAllocBruteFnDec: public Parent{
+public:
+ ContextAllocBruteFnDec(ManagedFnPtr f, CompilePass* p): Parent(f, p){}
+
+protected:
+ virtual void compileProlog() override {
+ LLVMLayer* llvm = Parent::pass->man->llvm;
+ llvm::IRBuilder<>& builder = llvm->irBuilder;
+ llvm::Type* int8T = llvm::Type::getInt8Ty(llvm->llvmContext);
+ llvm::Type* int32T = llvm::Type::getInt32Ty(llvm->llvmContext);
+ ContextAllocQuery* query = dynamic_cast<ContextAllocQuery*>(Parent::pass->man->transcend->getQuery(QueryId::ContextAllocQuery));
+ Parent::compileProlog();
+
+ std::string pad = query->getContextPad(Parent::__function);
+ const std::list<ASTSite>& symbols = query->getSymbols(pad);
+ if (!symbols.size()) return;
+
+ LLVMBlockLocker locker(llvm, true);
+ llvm::BasicBlock *blockProlog = llvm::BasicBlock::Create(
+ llvm->llvmContext,
+ compilation::FN_BLOCK_PREALLOC,
+ Parent::raw,
+ llvm->irBuilder.GetInsertBlock());
+ builder.SetInsertPoint(blockProlog);
+
+ compilation::AllocContext* context = Parent::pass->getContextManager()->getContext(pad);
+ for(ASTSite varS: symbols){
+ const Expression& varE = varS.getDefinition();
+ uint64_t varSize = containers::IContainersIR::getAllocSize(varE, llvm);
+ llvm::Value* varRaw = llvm->irBuilder.CreateAlloca(int8T, llvm::ConstantInt::get(int32T, varSize));
+ context->set(varS, varRaw);
+ }
+ };
+};
+} // xreate
+#endif //XREATE_CONTEXTALLOC_H
diff --git a/cpp/src/compilation/control.cpp b/cpp/src/compilation/control.cpp
index 7780fa9..bb79410 100644
--- a/cpp/src/compilation/control.cpp
+++ b/cpp/src/compilation/control.cpp
@@ -1,393 +1,394 @@
/* 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: control.cpp
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on June 26, 2016, 6:00 PM
*/
#include "analysis/typeinference.h"
#include "compilation/control.h"
#include "compilation/containers.h"
#include "compilation/transformersaturation.h"
#include "query/containers.h"
#include "llvmlayer.h"
#include "ast.h"
using namespace std;
using namespace llvm;
using namespace xreate;
using namespace xreate::containers;
using namespace xreate::compilation;
#define NAME(x) (hintRetVar.empty()? x : hintRetVar)
#define UNUSED(x) (void)(x)
#define EXPAND_CONTEXT \
LLVMLayer* llvm = context.pass->man->llvm; \
compilation::IBruteScope* scope = context.scope; \
compilation::IBruteFunction* function = context.function;
ControlIR::ControlIR(compilation::Context ctx)
: context(ctx), tyNum(static_cast<llvm::IntegerType*> (ctx.pass->man->llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::Int))))) {
}
Value*
-ControlIR::compileStructIndex(llvm::Value* aggregate, ExpandedType aggrT, const list<string>& indices) {
+ControlIR::compileStructIndex(llvm::Value* aggregate, ExpandedType aggrT, const list<string>& indices, const std::string& hintAlias) {
EXPAND_CONTEXT UNUSED(scope); UNUSED(function);
TypesHelper types(llvm);
llvm::Value* result = aggregate;
assert(indices.size());
for (const string& indexField: indices){
const std::vector<std::string>& tyfields = types.getRecordFields(aggrT);
unsigned idx = -1; bool flagFound = false;
for (unsigned i = 0, size = tyfields.size(); i < size; ++i) {
if (tyfields.at(i) == indexField) {
idx = i; flagFound = true; break;
}
}
if (flagFound){
result = llvm->irBuilder.CreateExtractValue(result, llvm::ArrayRef<unsigned>{idx});
aggrT = typeinference::getSubtype(aggrT, indexField);
} else {
assert(false && "not found required struct field");
}
}
+ result->setName(hintAlias);
return result;
//dereference pointer
//if (types.isPointerT(t)) {
// llvm::Value* addr = llvm->irBuilder.CreateConstGEP2_32(nullptr, aggregate, 0, i);
// return llvm->irBuilder.CreateLoad(addr);
//}
}
llvm::Value*
ControlIR::compileFold(const Expression& loopE, const std::string& hintAlias) {
EXPAND_CONTEXT
assert(loopE.op == Operator::FOLD);
AST* ast = context.pass->man->root;
//initialization:
const Expression aggrE = loopE.getOperands().at(0);
const ExpandedType& aggrT = ast->getType(aggrE);
llvm::Value* aggrRaw = context.scope->process(aggrE);
IFwdIteratorIR* aggrItIR = IFwdIteratorIR::create(aggrE, aggrT, context);
llvm::Value* idxBeginRaw = aggrItIR->begin(aggrRaw);
llvm::Value* idxEndRaw = aggrItIR->end(aggrRaw);
ExpandedType loopT = ast->getType(loopE);
std::string elAlias = loopE.bindings[0];
std::string accumAlias = loopE.bindings[1];
const Expression& accumE = loopE.getOperands().at(1);
ExpandedType accumT = ast->getType(accumE, loopT.get());
- llvm::Type* accumRawT = llvm->toLLVMType(accumT);
+ llvm::Type* accumRawT = llvm->toLLVMType(accumT, accumE);
llvm::Value* accumInitRaw = scope->process(accumE, accumAlias, accumT.get());
llvm::BasicBlock *blockProlog = llvm::BasicBlock::Create(llvm->llvmContext, "fold_prlg", function->raw);
llvm::BasicBlock *blockHeader = llvm::BasicBlock::Create(llvm->llvmContext, "fold_hdr", function->raw);
llvm::BasicBlock *blockBody = llvm::BasicBlock::Create(llvm->llvmContext, "fold", function->raw);
llvm::BasicBlock *blockFooter = llvm::BasicBlock::Create(llvm->llvmContext, "fold_ftr", function->raw);
llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "fold_eplg", function->raw);
std::unique_ptr<TransformerSaturation> transformerSaturation(new TransformerSaturation(blockProlog, context.pass->managerTransformations));
//Header:
// * create phi
llvm->irBuilder.SetInsertPoint(blockHeader);
llvm::PHINode *accum = llvm->irBuilder.CreatePHI(accumRawT, 2, accumAlias);
accum->addIncoming(accumInitRaw, blockProlog);
llvm::PHINode *idxCurrentRaw = llvm->irBuilder.CreatePHI(idxBeginRaw->getType(), 2, "foldIt");
idxCurrentRaw->addIncoming(idxBeginRaw, blockProlog);
// * loop checks
Value* condRange = llvm->irBuilder.CreateICmpNE(idxCurrentRaw, idxEndRaw);
llvm->irBuilder.CreateCondBr(condRange, blockBody, blockEpilog);
//Body:
llvm->irBuilder.SetInsertPoint(blockBody);
CodeScope* scopeLoop = loopE.blocks.front();
compilation::IBruteScope* loopUnit = function->getBruteScope(scopeLoop);
Value* elIn = aggrItIR->get(aggrRaw, idxCurrentRaw);
loopUnit->bindArg(accum, move(accumAlias));
loopUnit->bindArg(elIn, move(elAlias));
Value* accumNext = loopUnit->compile();
// * Loop saturation checks
bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockFooter, blockEpilog, context);
llvm::BasicBlock* blockSaturation = llvm->irBuilder.GetInsertBlock();
if (!flagSaturationTriggered){
llvm->irBuilder.CreateBr(blockFooter);
}
//Footer:
// * computing next iteration state
llvm->irBuilder.SetInsertPoint(blockFooter);
Value *itLoopNext = aggrItIR->advance(idxCurrentRaw);
accum->addIncoming(accumNext, llvm->irBuilder.GetInsertBlock());
idxCurrentRaw->addIncoming(itLoopNext, llvm->irBuilder.GetInsertBlock());
llvm->irBuilder.CreateBr(blockHeader);
//Prolog:
llvm->irBuilder.SetInsertPoint(context.scope->lastBlockRaw);
llvm->irBuilder.CreateBr(blockProlog);
llvm->irBuilder.SetInsertPoint(blockProlog);
llvm->irBuilder.CreateBr(blockHeader);
// Epilog:
llvm->irBuilder.SetInsertPoint(blockEpilog);
if (!flagSaturationTriggered){
return accum;
}
llvm::PHINode* result = llvm->irBuilder.CreatePHI(accumRawT, 2, hintAlias);
result->addIncoming(accum, blockHeader);
result->addIncoming(accumNext, blockSaturation);
return result;
}
llvm::Value*
ControlIR::compileFoldInf(const Expression& fold, const std::string& hintRetVar) {
EXPAND_CONTEXT
assert(fold.op == Operator::FOLD_INF);
std::string accumName = fold.bindings[0];
llvm::Value* accumInit = scope->process(fold.getOperands()[0]);
llvm::BasicBlock *blockBeforeLoop = llvm->irBuilder.GetInsertBlock();
llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm->llvmContext, "foldinf", function->raw);
llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm->llvmContext, "foldinf_next", function->raw);
llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm->llvmContext, "foldinf_post", function->raw);
std::unique_ptr<TransformerSaturation> transformerSaturation(new TransformerSaturation(blockBeforeLoop, context.pass->managerTransformations));
llvm->irBuilder.CreateBr(blockLoop);
// * create phi
llvm->irBuilder.SetInsertPoint(blockLoop);
llvm::PHINode *accum = llvm->irBuilder.CreatePHI(accumInit->getType(), 2, accumName);
accum->addIncoming(accumInit, blockBeforeLoop);
// * loop body
CodeScope* scopeLoop = fold.blocks.front();
compilation::IBruteScope* unitLoop = function->getBruteScope(scopeLoop);
unitLoop->bindArg(accum, move(accumName));
Value* accumNext = unitLoop->compile();
// * Loop saturation checks
bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockNext, blockAfterLoop, context);
assert(flagSaturationTriggered);
// * computing next iteration state
llvm->irBuilder.SetInsertPoint(blockNext);
accum->addIncoming(accumNext, llvm->irBuilder.GetInsertBlock());
llvm->irBuilder.CreateBr(blockLoop);
// finalization:
llvm->irBuilder.SetInsertPoint(blockAfterLoop);
return accumNext;
}
llvm::Value*
ControlIR::compileIf(const Expression& exprIf, const std::string& hintRetVar) {
EXPAND_CONTEXT
const Expression& condExpr = exprIf.getOperands()[0];
llvm::IRBuilder<>& builder = llvm->irBuilder;
assert(builder.GetInsertBlock() == scope->lastBlockRaw);
//initialization:
llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "ifAfter", function->raw);
llvm::BasicBlock *blockTrue = llvm::BasicBlock::Create(llvm->llvmContext, "ifTrue", function->raw);
llvm::BasicBlock *blockFalse = llvm::BasicBlock::Create(llvm->llvmContext, "ifFalse", function->raw);
llvm::Value* cond = scope->process(condExpr);
builder.SetInsertPoint(blockTrue);
CodeScope* scopeTrue = exprIf.blocks.front();
llvm::Value* resultTrue = function->getBruteScope(scopeTrue)->compile();
llvm::BasicBlock * blockTrueEnd = builder.GetInsertBlock();
builder.CreateBr(blockEpilog);
builder.SetInsertPoint(blockFalse);
CodeScope* scopeFalse = exprIf.blocks.back();
llvm::Value* resultFalse = function->getBruteScope(scopeFalse)->compile();
llvm::BasicBlock * blockFalseEnd = builder.GetInsertBlock();
builder.CreateBr(blockEpilog);
builder.SetInsertPoint(scope->lastBlockRaw);
llvm->irBuilder.CreateCondBr(cond, blockTrue, blockFalse);
builder.SetInsertPoint(blockEpilog);
llvm::PHINode *ret = builder.CreatePHI(resultTrue->getType(), 2, hintRetVar);
ret->addIncoming(resultTrue, blockTrueEnd);
ret->addIncoming(resultFalse, blockFalseEnd);
return ret;
}
//TODO Switch: default variant no needed when all possible conditions are considered
llvm::Value*
ControlIR::compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar) {
EXPAND_CONTEXT UNUSED(function);
AST* root = context.pass->man->root;
llvm::IRBuilder<>& builder = llvm->irBuilder;
assert(exprSwitch.operands.size() >= 2);
assert(exprSwitch.operands[1].op == Operator::CASE_DEFAULT && "No default case in Switch Statement");
int countCases = exprSwitch.operands.size() - 1;
llvm::BasicBlock* blockProlog = builder.GetInsertBlock();
llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "switchAfter", function->raw);
builder.SetInsertPoint(blockEpilog);
llvm::Type* exprSwitchType = llvm->toLLVMType(root->getType(exprSwitch));
llvm::PHINode *ret = builder.CreatePHI(exprSwitchType, countCases, hintRetVar);
llvm::Type* typI8 = llvm::Type::getInt8Ty(llvm->llvmContext);
builder.SetInsertPoint(blockProlog);
llvm::Value * conditionSwitch = scope->process(exprSwitch.operands[0]);
llvm::BasicBlock *blockDefault = llvm::BasicBlock::Create(llvm->llvmContext, "caseDefault", function->raw);
llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(
typeinference::doAutomaticTypeConversion(conditionSwitch, typI8, builder),
blockDefault,
countCases);
for (int size = exprSwitch.operands.size(), i = 2; i < size; ++i) {
llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm->llvmContext, "case" + std::to_string(i), function->raw);
llvm::Value* condCase = function->getBruteScope(exprSwitch.operands[i].blocks.front())->compile();
builder.SetInsertPoint(blockCase);
llvm::Value* resultCase = function->getBruteScope(exprSwitch.operands[i].blocks.back())->compile();
builder.CreateBr(blockEpilog);
ret->addIncoming(resultCase, builder.GetInsertBlock());
builder.SetInsertPoint(blockProlog);
instructionSwitch->addCase(
dyn_cast<llvm::ConstantInt>(
typeinference::doAutomaticTypeConversion(condCase, typI8, builder)),
blockCase);
}
//compile default block:
builder.SetInsertPoint(blockDefault);
CodeScope* scopeDefault = exprSwitch.operands[1].blocks.front();
llvm::Value* resultDefault = function->getBruteScope(scopeDefault)->compile();
builder.CreateBr(blockEpilog);
ret->addIncoming(resultDefault, builder.GetInsertBlock());
builder.SetInsertPoint(blockEpilog);
return ret;
}
llvm::Value*
ControlIR::compileSwitchVariant(const Expression& exprSwitch, const std::string& hintRetVar) {
EXPAND_CONTEXT UNUSED(function);
AST* root = context.pass->man->root;
llvm::IRBuilder<>& builder = llvm->irBuilder;
llvm::Type* typI8= llvm::Type::getInt8Ty(llvm->llvmContext);
const ExpandedType& typVariant = root->getType(exprSwitch.operands.at(0));
llvm::Type* typVariantRaw = llvm->toLLVMType(typVariant);
assert(typVariant->__operands.size() == exprSwitch.operands.size() - 1 && "Ill-formed Switch Variant");
int casesCount = exprSwitch.operands.size();
llvm::BasicBlock* blockProlog = builder.GetInsertBlock();
llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "switchAfter", function->raw);
builder.SetInsertPoint(blockEpilog);
llvm::Type* resultType = llvm->toLLVMType(root->getType(exprSwitch));
llvm::PHINode *ret = builder.CreatePHI(resultType, casesCount, hintRetVar);
builder.SetInsertPoint(blockProlog);
llvm::Value * conditionSwitchRaw = scope->process(exprSwitch.operands.at(0));
llvm::Value* idRaw = builder.CreateExtractValue(conditionSwitchRaw, llvm::ArrayRef<unsigned>({0}));
//Dereference preparation
const bool flagPrepareDerefence = std::any_of(typVariant->__operands.begin(), typVariant->__operands.end(), [](const TypeAnnotation& op){
return op.isValid();
});
llvm::Value* addrAsStorage = nullptr;
if (flagPrepareDerefence){
assert(exprSwitch.bindings.size() && "Switch condition alias not found");
llvm::Type* typStorageRaw = llvm::cast<llvm::StructType>(typVariantRaw)->getElementType(1);
llvm::Value* storageRaw = builder.CreateExtractValue(conditionSwitchRaw, llvm::ArrayRef<unsigned>({1}));
addrAsStorage = llvm->irBuilder.CreateAlloca(typStorageRaw);
llvm->irBuilder.CreateStore(storageRaw, addrAsStorage);
}
llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(idRaw, nullptr, casesCount);
llvm::BasicBlock* blockDefaultUndefined;
std::list<CodeScope*>::const_iterator scopeCaseIt = exprSwitch.blocks.begin();
for (int instancesSize = exprSwitch.operands.size()-1, instId = 0; instId < instancesSize; ++instId) {
llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm->llvmContext, "case" + std::to_string(instId), function->raw);
builder.SetInsertPoint(blockCase);
IBruteScope* unitCase = function->getBruteScope(*scopeCaseIt);
const ExpandedType& instType = ExpandedType(typVariant->__operands.at(instId));
//Actual variant derefence
if (instType->isValid()) {
string identCondition = exprSwitch.bindings.front();
llvm::Type* instTypeRaw = llvm->toLLVMType(instType);
llvm::Value* addrAsInst = llvm->irBuilder.CreateBitOrPointerCast(addrAsStorage, instTypeRaw->getPointerTo());
llvm::Value* instRaw = llvm->irBuilder.CreateLoad(instTypeRaw, addrAsInst);
const Symbol& identSymb = unitCase->bindArg(instRaw, move(identCondition));
Attachments::put<TypeInferred>(identSymb, instType);
}
llvm::Value* resultCase = function->getBruteScope(*scopeCaseIt)->compile();
builder.CreateBr(blockEpilog);
ret->addIncoming(resultCase, blockDefaultUndefined = builder.GetInsertBlock());
builder.SetInsertPoint(blockProlog);
instructionSwitch->addCase(dyn_cast<llvm::ConstantInt>(llvm::ConstantInt::get(typI8, exprSwitch.operands.at(instId+1).getValueDouble())), blockCase);
++scopeCaseIt;
}
instructionSwitch->setDefaultDest(blockDefaultUndefined);
builder.SetInsertPoint(blockEpilog);
return ret;
}
llvm::Value*
ControlIR::compileConstantStringAsPChar(const string& data, const std::string& hintRetVar) {
EXPAND_CONTEXT UNUSED(function); UNUSED(scope);
Type* typPchar = PointerType::getUnqual(Type::getInt8Ty(llvm->llvmContext));
//ArrayType* typStr = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::I8, size+1))));
/*
std::vector<Constant *> chars;
chars.reserve(size+1);
for (size_t i=0; i< size; ++i){
chars[i] = ConstantInt::get(typI8, (unsigned char) data[i]);
}
chars[size] = ConstantInt::get(typI8, 0);
*/
Value* rawData = ConstantDataArray::getString(llvm->llvmContext, data);
Value* rawPtrData = llvm->irBuilder.CreateAlloca(rawData->getType(), ConstantInt::get(Type::getInt32Ty(llvm->llvmContext), 1, false));
llvm->irBuilder.CreateStore(rawData, rawPtrData);
return llvm->irBuilder.CreateCast(llvm::Instruction::BitCast, rawPtrData, typPchar, hintRetVar);
}
llvm::Value*
ControlIR::compileSequence(const Expression &expr){
EXPAND_CONTEXT UNUSED(scope); UNUSED(llvm);
llvm::Value* result;
for(CodeScope* scope: expr.blocks){
result = function->getBruteScope(scope)->compile();
}
return result;
}
diff --git a/cpp/src/compilation/control.h b/cpp/src/compilation/control.h
index d4b3e7d..4b29e37 100644
--- a/cpp/src/compilation/control.h
+++ b/cpp/src/compilation/control.h
@@ -1,73 +1,73 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: Control.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on June 26, 2016, 6:00 PM
*/
/**
* \file advancedinstructions.h
* \brief Compound statements compilation
*/
#ifndef INSTRUCTIONSADVANCED_H
#define INSTRUCTIONSADVANCED_H
#include "ast.h"
#include "llvmlayer.h"
#include "pass/compilepass.h"
#include <vector>
namespace xreate {
namespace compilation {
/** \brief Advanced compilation primitives */
class ControlIR {
public:
ControlIR(compilation::Context ctx);
/** \brief Struct field access operator compilation*/
- llvm::Value* compileStructIndex(llvm::Value* aggregate, ExpandedType aggrT, const std::list<std::string>& indices);
+ llvm::Value* compileStructIndex(llvm::Value* aggregate, ExpandedType aggrT, const std::list<std::string>& indices, const std::string& hintAlias);
/*
* - map Computation -> Llvm_Array: Prohibited, we do not know a result size
* - map Llvm_Array -> Computation: considered in `compileGetElement`
* - map Llvm_Array -> Llvm_Array considered by this method
*/
/** \brief `loop map` statement compilation*/
llvm::Value* compileMapSolidOutput(const Expression &expr, const std::string hintRetVar = "");
/** \brief `loop fold` statement compilation*/
llvm::Value* compileFold(const Expression& loopE, const std::string& hintAlias="");
/** \brief `loop` statement compilation*/
llvm::Value* compileFoldInf(const Expression& fold, const std::string& ident="");
/** \brief `if` statement compilation*/
llvm::Value* compileIf(const Expression& exprIf, const std::string& ident);
/** \brief `switch` statement compilation*/
llvm::Value* compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar);
/** \brief `switch` statement compilation*/
llvm::Value* compileSwitchVariant(const Expression& exprSwitch, const std::string& hintRetVar);
/** \brief `switch variant` statement compilation*/
llvm::Value* compileConstantStringAsPChar(const std::string &data, const std::string& hintRetVar);
/** \brief `seq` statement compilation */
llvm::Value* compileSequence(const Expression &expr);
private:
compilation::Context context;
llvm::IntegerType* const tyNum;
};
}}
#endif /* INSTRUCTIONSADVANCED_H */
diff --git a/cpp/src/compilation/decorators.h b/cpp/src/compilation/decorators.h
index 61b4f65..ae6802e 100644
--- a/cpp/src/compilation/decorators.h
+++ b/cpp/src/compilation/decorators.h
@@ -1,254 +1,257 @@
/* 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: scopedecorators.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on February 24, 2017, 11:35 AM
*/
/**
* \file scopedecorators.h
* \brief Basic code block compilation xreate::compilation::IBruteScope decorators
*/
#ifndef SCOPEDECORATORS_H
#define SCOPEDECORATORS_H
#include "ast.h"
#include "compilation/transformations.h"
#include "analysis/typeinference.h"
#include "compilation/demand.h"
#include "compilation/polymorph.h"
#include "compilation/targetinterpretation.h"
+#include "compilation/contextalloc.h"
#ifndef XREATE_CONFIG_MIN
#include "compilation/versions.h"
#include "compilation/polymorph.h"
#endif
#include <list>
namespace xreate {
class CompilePass;
namespace compilation {
class IBruteScope;
class IBruteFunction;
/**\brief Provides caching ability for code scope compilation
* \extends xreate::compilation::IBruteScope
*/
template<class Parent>
class CachedScopeDecorator: public Parent{
typedef CachedScopeDecorator<Parent> SELF;
public:
CachedScopeDecorator(const CodeScope* const codeScope, IBruteFunction* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){}
Symbol
bindArg(llvm::Value* value, std::string&& alias)
{
//ensure existence of an alias
assert(Parent::scope->__identifiers.count(alias));
//memorize new value for an alias
ScopedSymbol id{Parent::scope->__identifiers.at(alias), versions::VERSION_NONE};
__rawVars[id] = value;
return Symbol{id, Parent::scope};
}
void
bindArg(llvm::Value* value, const ScopedSymbol& s) override{
__rawVars[s] = value;
}
void
- bindExternalSymb(llvm::Value* value, const Symbol& s) override {
- __rawExternals[s] = value;
+ bindExternalArg(llvm::Value* argRaw, const Symbol& argS) override {
+ __rawExternals[argS] = argRaw;
}
llvm::Value*
- compile(const std::string& aliasBlock="") override{
+ compile() override{
if (__rawVars.count(ScopedSymbol::RetSymbol)){
return __rawVars[ScopedSymbol::RetSymbol];
}
- return Parent::compile(aliasBlock);
+ return Parent::compile();
}
llvm::Value*
processSymbol(const Symbol& s, std::string hintRetVar) override{
if (Parent::function->isLambda){
SELF* self = dynamic_cast<SELF*>(Parent::function->getEntry());
if (self->__rawExternals.count(s)){
return self->__rawExternals.at(s);
}
}
const CodeScope* scope = s.scope;
SELF* self = dynamic_cast<SELF*>(Parent::function->getBruteScope(scope));
if (self->__rawVars.count(s.identifier)){
return self->__rawVars.at(s.identifier);
}
//Declaration could be overriden
/*
Expression declaration = CodeScope::getDefinition(s, true);
if (!declaration.isDefined()){
assert(__declarationsOverriden.count(s.identifier));
declaration = __declarationsOverriden[s.identifier];
} else {
(false); //in case of binding there should be raws provided.
}
}
*/
llvm::Value* resultRaw = Parent::processSymbol(s, hintRetVar);
self->__rawVars.emplace(s.identifier, resultRaw);
return resultRaw;
}
void
overrideDeclarations(std::list<std::pair<Symbol, Expression>> bindings){
reset();
for (auto entry: bindings){
SELF* self = dynamic_cast<SELF*>(Parent::function->getBruteScope(entry.first.scope));
assert(self == this);
self->__declarationsOverriden.emplace(entry.first.identifier, entry.second);
}
}
void registerChildScope(std::shared_ptr<IBruteScope> scope){
__childScopes.push_back(scope);
}
void reset(){
__rawVars.clear();
__declarationsOverriden.clear();
__childScopes.clear();
__rawExternals.clear();
}
private:
std::unordered_map<ScopedSymbol, Expression> __declarationsOverriden;
std::unordered_map<ScopedSymbol,llvm::Value*> __rawVars;
std::unordered_map<Symbol,llvm::Value*> __rawExternals;
std::list<std::shared_ptr<IBruteScope>> __childScopes;
};
/** \brief Provides automatic type conversion
* \extends xreate::compilation::IBruteScope
*/
template<class Parent>
class TypeConversionScopeDecorator: public Parent {
public:
TypeConversionScopeDecorator(const CodeScope* const codeScope, IBruteFunction* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){}
llvm::Value* process(const Expression& expr, const std::string& hintVarDecl="", const TypeAnnotation& expectedT = TypeAnnotation()) override {
llvm::Value* resultR = Parent::process(expr, hintVarDecl, expectedT);
if(!expr.type.isValid()) {
return resultR;
}
ExpandedType exprT = Parent::pass->man->root->getType(expr);
llvm::Type* exprTR = Parent::pass->man->llvm->toLLVMType(exprT, expr);
return typeinference::doAutomaticTypeConversion(resultR, exprTR, Parent::pass->man->llvm->irBuilder);
}
};
#ifndef XREATE_CONFIG_MIN
/**\brief The default code scope compilation implementation
* \extends xreate::compilation::IBruteScope
*/
typedef
CachedScopeDecorator<
- TypeConversionScopeDecorator<
- latex::LatexBruteScopeDecorator<
- polymorph::PolymorphBruteScopeDecorator<
- compilation::TransformationsScopeDecorator<
- interpretation::InterpretationScopeDecorator<
- versions::VersionsScopeDecorator<
- compilation::BasicBruteScope
- >>>>>>>
- DefaultCodeScopeUnit;
+ TypeConversionScopeDecorator<
+ latex::LatexBruteScopeDecorator<
+ polymorph::PolymorphBruteScopeDecorator<
+ compilation::TransformationsScopeDecorator<
+ interpretation::InterpretationScopeDecorator<
+ versions::VersionsScopeDecorator<
+ compilation::BasicBruteScope >>>>>>>
+
+ DefaultCodeScopeUnit;
} //end of compilation namespace
struct CachedScopeDecoratorTag;
struct VersionsScopeDecoratorTag;
template<>
struct DecoratorsDict<CachedScopeDecoratorTag>{
typedef compilation::CachedScopeDecorator<
compilation::TypeConversionScopeDecorator<
latex::LatexBruteScopeDecorator<
polymorph::PolymorphBruteScopeDecorator<
compilation::TransformationsScopeDecorator<
interpretation::InterpretationScopeDecorator<
versions::VersionsScopeDecorator<
compilation::BasicBruteScope
>>>>>>>
result;
};
template<>
struct DecoratorsDict<VersionsScopeDecoratorTag>{
typedef
versions::VersionsScopeDecorator<
compilation::BasicBruteScope
>
result;
};
#else
/**\brief The default code scope compilation implementation
* \extends xreate::compilation::IBruteScope
*/
typedef
CachedScopeDecorator<
TypeConversionScopeDecorator<
interpretation::InterpretationScopeDecorator<
demand::DemandBruteScopeDecorator<
polymorph::PolymorphBruteScopeDecorator<
compilation::BasicBruteScope
>>>>>
DefaultCodeScopeUnit;
} //end of compilation namespacef
struct CachedScopeDecoratorTag;
template<>
struct DecoratorsDict<CachedScopeDecoratorTag>{
typedef compilation::CachedScopeDecorator<
compilation::TypeConversionScopeDecorator<
interpretation::InterpretationScopeDecorator<
demand::DemandBruteScopeDecorator<
polymorph::PolymorphBruteScopeDecorator<
compilation::BasicBruteScope
>>>>>
result;
};
typedef
demand::DemandBruteFnDecorator<
//polymorph::PolymorphBruteFnDecorator<
+ ContextAllocBruteFnDec<
compilation::BasicBruteFunction
- > BruteFunctionDefault;
+ >>
+ BruteFunctionDefault;
#endif
} //end of xreate
#endif /* SCOPEDECORATORS_H */
diff --git a/cpp/src/compilation/intrinsics.cpp b/cpp/src/compilation/intrinsics.cpp
index 1ca85b6..004229c 100644
--- a/cpp/src/compilation/intrinsics.cpp
+++ b/cpp/src/compilation/intrinsics.cpp
@@ -1,75 +1,74 @@
//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/lambdas.cpp b/cpp/src/compilation/lambdas.cpp
index 0bed041..0572549 100644
--- a/cpp/src/compilation/lambdas.cpp
+++ b/cpp/src/compilation/lambdas.cpp
@@ -1,71 +1,223 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: lambdas.cpp
* Author: pgess <v.melnychenko@xreate.org>
*
* Created in April, 2020
*/
#include "compilation/lambdas.h"
+#include "compilation/containers.h"
#include "llvmlayer.h"
#include "compilation/resources.h"
+#include <llvm/Support/raw_ostream.h>
using namespace xreate::compilation;
using namespace std;
-unsigned LambdaBruteFn::__counter = 0;
+unsigned LambdaFn::__counter = 0;
std::string
-LambdaBruteFn::prepareName(){
+LambdaFn::prepareName(){
return string(LAMBDA_PREFIX) + "_" + __hintAlias + "_" + to_string(__counter++);
}
std::vector<llvm::Type*>
-LambdaBruteFn::prepareSignature(){
- return getScopeSignature(IBruteFunction::__entry);
+LambdaFn::prepareSignature(){
+ LLVMLayer* llvm = IBruteFunction::pass->man->llvm;
+ llvm::Type* lmbBoundArgsRawT = llvm::Type::getInt8PtrTy(llvm->llvmContext);
+ auto result = getScopeSignature(IBruteFunction::__entry);
+ result.push_back(lmbBoundArgsRawT);
+
+ return result;
}
llvm::Type*
-LambdaBruteFn::prepareResult(){
+LambdaFn::prepareResult(){
LLVMLayer* llvm = IBruteFunction::pass->man->llvm;
AST* ast = IBruteFunction::pass->man->root;
return llvm->toLLVMType(ast->getType(__entry->getBody()));
}
llvm::Function::arg_iterator
-LambdaBruteFn::prepareBindings(){
+LambdaFn::prepareBindings(){
CodeScope* entrySc = IBruteFunction::__entry;
IBruteScope* entryBruteSc = IBruteFunction::getBruteScope(entrySc);
llvm::Function::arg_iterator fargsI = IBruteFunction::raw->arg_begin();
for (std::string &arg : entrySc->__bindings) {
ScopedSymbol argid{entrySc->__identifiers[arg], versions::VERSION_NONE};
entryBruteSc->bindArg(&*fargsI, argid);
fargsI->setName(arg);
++fargsI;
}
- for (Symbol symbExtern: entrySc->boundExternalSymbs){
- entryBruteSc->bindExternalSymb(&*fargsI, symbExtern);
- //fargsI->setName(arg);
- ++fargsI;
+ __boundArgsRaw = &*fargsI;
+
+ return ++fargsI;
+}
+
+void
+LambdaFn::compileProlog(){
+ LLVMLayer* llvm = IBruteFunction::pass->man->llvm;
+ CodeScope* entrySc = IBruteFunction::__entry;
+ IBruteScope* entryBruteSc = IBruteFunction::getBruteScope(entrySc);
+ TypesHelper helper(llvm);
+ llvm::IntegerType* intT = helper.getPreferredIntTy();
+ llvm::Value* constZero = llvm::ConstantInt::get(intT, 0);
+
+ LLVMBlockLocker locker(llvm, true);
+
+ llvm::BasicBlock *blockProlog = llvm::BasicBlock::Create(
+ llvm->llvmContext,
+ compilation::FN_BLOCK_PROLOG,
+ IBruteFunction::raw,
+ llvm->irBuilder.GetInsertBlock());
+ llvm->irBuilder.SetInsertPoint(blockProlog);
+
+ llvm::StructType* boundArgsRawT = getBoundArgsRawType(entrySc, llvm);
+ llvm::Value* boundArgsRaw2;
+ if (entrySc->boundArgs.size()){
+ llvm::Value* boundArgsRaw = llvm->irBuilder.CreateCast(
+ llvm::Instruction::BitCast,
+ __boundArgsRaw, boundArgsRawT->getPointerTo());
+ //llvm::Value* boundArgsP = llvm->irBuilder.CreateGEP(boundArgsRaw, {constZero} /*, llvm::ConstantInt::get(intT, argId++)*/);
+ boundArgsRaw2 = llvm->irBuilder.CreateLoad(boundArgsRaw);
+ boundArgsRaw2->getType()->print(llvm::outs());
}
- return fargsI;
+ unsigned argId = 0;
+ for (Symbol symbExtern: entrySc->boundArgs){
+ llvm::Value* argRaw = llvm->irBuilder.CreateExtractValue(boundArgsRaw2, {argId++});
+ entryBruteSc->bindExternalArg(
+ argRaw,
+ symbExtern);
+ }
}
void
-LambdaBruteFn::applyAttributes(){
+LambdaFn::applyAttributes(){
raw->addFnAttr(llvm::Attribute::AlwaysInline);
}
+llvm::StructType*
+LambdaFn::getBoundArgsRawType(CodeScope* body, LLVMLayer* llvm){
+ std::vector<llvm::Type*> argsBoundRawTVec;
+ argsBoundRawTVec.reserve(body->boundArgs.size());
+
+ for (const Symbol& argS: body->boundArgs){
+ const Expression& argE = CodeScope::getDefinition(argS);
+ const ExpandedType& argT = llvm->ast->getType(argE);
+ argsBoundRawTVec.push_back(llvm->toLLVMType(argT, argE));
+ }
+
+ return llvm::StructType::get(
+ llvm->llvmContext,
+ argsBoundRawTVec
+ );
+}
+
+llvm::Value*
+LambdaIR::compile(CodeScope* body, Allocator* allocator, const std::string& hintAlias){
+ LLVMLayer* llvm = __context.pass->man->llvm;
+ containers::RecordIR recordIR(__context);
+ LambdaFn fnLmb(body, __context.pass, hintAlias);
+
+ llvm::Value* fnLmbRaw = fnLmb.compile();
+ llvm::Type* lmbBoundArgsRawT = llvm::Type::getInt8PtrTy(llvm->llvmContext);
+ llvm::Type* lmbRawT = llvm::StructType::get(
+ fnLmbRaw->getType(),
+ lmbBoundArgsRawT);
+
+ llvm::Value* argsCastedRaw;
+ if (body->boundArgs.size()){
+ llvm::StructType* argsRawT = LambdaFn::getBoundArgsRawType(body, llvm);
+ vector<llvm::Value*> argsRawVec(body->boundArgs.size());
+ size_t boundArgIdx = 0;
+ for (const Symbol& argBoundS: body->boundArgs){
+ argsRawVec[boundArgIdx++] = __context.scope->processSymbol(argBoundS);
+ }
+
+ llvm::Value* argsRawP = allocator->allocate(argsRawT, nullptr, "");
+ llvm::Value* argsRaw = llvm::UndefValue::get(argsRawT);
+ unsigned fieldId = 0;
+ for(llvm::Value* fieldRaw: argsRawVec){
+ argsRaw = llvm->irBuilder.CreateInsertValue(
+ argsRaw,
+ fieldRaw,
+ fieldId++);
+ }
+
+ llvm->irBuilder.CreateStore(argsRaw, argsRawP);
+
+ argsCastedRaw = llvm->irBuilder.CreateCast(
+ llvm::Instruction::BitCast,
+ argsRawP, llvm::Type::getInt8PtrTy(llvm->llvmContext));
+
+ } else {
+ argsCastedRaw = llvm::UndefValue::get(llvm::Type::getInt8PtrTy(llvm->llvmContext));
+ }
+
+ llvm::Value* lmbRaw = llvm::UndefValue::get(lmbRawT);
+ lmbRaw = llvm->irBuilder.CreateInsertValue(lmbRaw, fnLmbRaw, 0);
+ lmbRaw = llvm->irBuilder.CreateInsertValue(lmbRaw, argsCastedRaw, 1);
+ lmbRaw->setName(hintAlias);
+
+ lmbRaw->getType()->print(llvm::outs());
+
+ return lmbRaw;
+}
+
+uint64_t
+LambdaIR::getAllocSize(CodeScope* body, LLVMLayer* llvm){
+ llvm::StructType* argsRawT = LambdaFn::getBoundArgsRawType(body, llvm);
+
+ return llvm->module->getDataLayout().getTypeStoreSize(argsRawT);
+}
+
+IFnInvocation*
+LambdaIR::getFnInvocation(llvm::Value* lambdaRaw){
+ LLVMLayer* llvm = __context.pass->man->llvm;
+
+ lambdaRaw->getType()->print(llvm::outs());
+ llvm::StructType* lambdaStructRawT = llvm::cast<llvm::StructType>(lambdaRaw->getType());
+ llvm::Value* calleeRaw = llvm->irBuilder.CreateExtractValue(lambdaRaw, 0);
+
+ calleeRaw->getType()->print(llvm::outs());
+ llvm::Type* calleeRawPtrT = llvm::cast<llvm::PointerType>(calleeRaw->getType())->getElementType();
+ llvm::FunctionType* calleeRawT = llvm::cast<llvm::FunctionType>(calleeRawPtrT);
+
+ size_t argsCount = lambdaStructRawT->getNumElements() - 1;
+ IFnInvocation* calleeInvocBase = new BruteFnInvocation(calleeRaw, calleeRawT, llvm);
+ vector<llvm::Value*> argsExternal(argsCount);
+ for(unsigned argId=0; argId < argsCount; ++argId){
+ argsExternal[argId] = llvm->irBuilder.CreateExtractValue(lambdaRaw, argId+1);
+ }
+
+ return new HiddenArgsFnInvocation(argsExternal, calleeInvocBase);
+}
+
llvm::Function*
-LambdaIR::compile(CodeScope* body, const std::string& hintAlias){
- LambdaBruteFn fnLambda(body, __pass, hintAlias);
+LambdaIR::getRawFn(llvm::Value* lambdaRaw){
+ LLVMLayer* llvm = __context.pass->man->llvm;
+
+ llvm::Value* calleeRaw = llvm->irBuilder.CreateExtractValue(lambdaRaw, 0);
+ return llvm::cast<llvm::Function>(calleeRaw);
+}
+
+llvm::Type*
+LambdaIR::getRawType(llvm::Type* resultRawT, std::vector<llvm::Type*> argsRawT, LLVMLayer* llvm){
+ llvm::Type* lmbBoundArgsRawT = llvm::Type::getInt8PtrTy(llvm->llvmContext);
+ argsRawT.push_back(lmbBoundArgsRawT);
- return fnLambda.compile();
+ llvm::FunctionType* fnRawT = llvm::FunctionType::get(resultRawT, llvm::ArrayRef<llvm::Type*>(argsRawT), false);
+ llvm::Type* lmbdRawT = llvm::StructType::get(llvm->llvmContext, {fnRawT->getPointerTo(), lmbBoundArgsRawT}, false);
+
+ return lmbdRawT;
}
+
+
diff --git a/cpp/src/compilation/lambdas.h b/cpp/src/compilation/lambdas.h
index 2f3f355..1f52bee 100644
--- a/cpp/src/compilation/lambdas.h
+++ b/cpp/src/compilation/lambdas.h
@@ -1,55 +1,63 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: lambdas.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created in April, 2020
*/
#ifndef XREATE_LAMBDAS_H
#define XREATE_LAMBDAS_H
#include "pass/compilepass.h"
namespace llvm {
class Function;
}
namespace xreate { namespace compilation {
-class LambdaBruteFn: public IBruteFunction {
+class Allocator;
+
+class LambdaFn: public IBruteFunction {
public:
- LambdaBruteFn(CodeScope* entry, CompilePass* p, const std::string& hintAlias)
+ LambdaFn(CodeScope* entry, CompilePass* p, const std::string& hintAlias)
: IBruteFunction(entry, p), __hintAlias(hintAlias) {
IBruteFunction::isLambda = true;
}
virtual std::string prepareName() override;
+ static llvm::StructType* getBoundArgsRawType(CodeScope* body, LLVMLayer* llvm);
protected:
virtual std::vector<llvm::Type*> prepareSignature() override;
virtual llvm::Function::arg_iterator prepareBindings() override;
virtual llvm::Type* prepareResult() override;
virtual void applyAttributes() override;
+ virtual void compileProlog() override;
private:
std::string __hintAlias;
+ llvm::Value* __boundArgsRaw;
static unsigned __counter;
};
class LambdaIR{
public:
- LambdaIR(CompilePass* p): __pass(p){}
- llvm::Function* compile(CodeScope* body, const std::string& hintAlias);
+ LambdaIR(compilation::Context context): __context(context){}
+
+ llvm::Value* compile(CodeScope* body, Allocator* allocator, const std::string& hintAlias);
+ IFnInvocation* getFnInvocation(llvm::Value* lambdaRaw);
+ llvm::Function* getRawFn(llvm::Value* lambdaRaw);
+ static llvm::Type* getRawType(llvm::Type* resultRawT, std::vector<llvm::Type*> argsRawT, LLVMLayer* llvm);
+ static uint64_t getAllocSize(CodeScope* body, LLVMLayer* llvm);
private:
compilation::Context __context;
- CompilePass* __pass;
-
};
}}
#endif //XREATE_LAMBDAS_H
diff --git a/cpp/src/compilation/mm.cpp b/cpp/src/compilation/mm.cpp
new file mode 100644
index 0000000..6470d82
--- /dev/null
+++ b/cpp/src/compilation/mm.cpp
@@ -0,0 +1,67 @@
+/* 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: ...
+ * Author: pgess <v.melnychenko@xreate.org>
+ *
+ * Created on 27/05/2020
+ */
+
+#include "analysis/typehints.h"
+#include "analysis/predefinedanns.h"
+#include "analysis/utils.h"
+#include "query/contextalloc.h"
+#include "compilation/mm.h"
+#include "compilation/context.h"
+#include "llvmlayer.h"
+
+namespace xreate {namespace compilation{
+
+AllocatorType
+Allocator::getType(const Expression& expr, AST* ast){
+ auto manPredefined = analysis::PredefinedAnns::instance();
+
+ const Expression& hintE = analysis::findAnnByType(expr, ExpandedType(manPredefined.allocaT), ast);
+ if (!hintE.isValid()) return AllocatorType::DEFAULT;
+
+ return (AllocatorType ) hintE.getValueDouble();
+}
+
+Allocator*
+Allocator::create(const Expression& expr, const Context& ctx){
+ switch(getType(expr, ctx.pass->man->root)){
+ case AllocatorType::LOCAL: {
+ return new LocalAllocator(ctx.pass->man->llvm);
+ }
+
+ case AllocatorType::CONTEXTPAD: {
+ return ContextAllocator::create(expr, ctx);
+ }
+ }
+
+ return nullptr;
+}
+
+ContextAllocator*
+ContextAllocator::create(const Expression& expr, const Context& ctx){
+ typehints::ContextAllocHint hint = typehints::find(expr, typehints::ContextAllocHint{});
+ assert(!hint.pad.empty());
+ AllocContext* context = ctx.pass->getContextManager()->getContext(hint.pad);
+ llvm::Value* memRaw = context->get(ASTSite{expr.id});
+
+ return new ContextAllocator(memRaw, ctx.pass->man->llvm);
+}
+
+llvm::Value*
+ContextAllocator::allocate(llvm::Type* elRawT, llvm::Value* sizeRaw, const std::string& hintAlias){
+ return Allocator::llvm->irBuilder.CreateCast(llvm::Instruction::BitCast, __mem, elRawT->getPointerTo());
+}
+
+llvm::Value*
+LocalAllocator::allocate(llvm::Type* elRawT,
+ llvm::Value* sizeRaw,
+ const std::string& hintAlias){
+ return Allocator::llvm->irBuilder.CreateAlloca(elRawT, sizeRaw, hintAlias);
+}
+}} //xreate::compilation
\ No newline at end of file
diff --git a/cpp/src/compilation/mm.h b/cpp/src/compilation/mm.h
new file mode 100644
index 0000000..dd2cece
--- /dev/null
+++ b/cpp/src/compilation/mm.h
@@ -0,0 +1,52 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * File: memory.h
+ * Author: pgess <v.melnychenko@xreate.org>
+ *
+ * Created on 27/05/2020
+ */
+#ifndef XREATE_MEMORY_H
+#define XREATE_MEMORY_H
+
+#include "pass/compilepass.h"
+
+namespace xreate {namespace compilation{
+
+enum class AllocatorType{
+ CONTEXTPAD,
+ LOCAL, // local allocation
+ DEFAULT = LOCAL
+};
+
+class Allocator{
+public:
+ static Allocator* create(const Expression& expr, const Context& ctx);
+ static AllocatorType getType(const Expression& expr, AST* ast);
+
+ Allocator(LLVMLayer* l): llvm(l){}
+ virtual llvm::Value* allocate(llvm::Type* elRawT, llvm::Value* sizeRaw, const std::string& hintAlias) = 0;
+
+protected:
+ LLVMLayer* llvm;
+};
+
+class ContextAllocator: public Allocator{
+public:
+ static ContextAllocator* create(const Expression& expr, const Context& ctx);
+ ContextAllocator(llvm::Value* mem, LLVMLayer* l): Allocator(l), __mem(mem){}
+ virtual llvm::Value* allocate(llvm::Type* elRawT, llvm::Value* sizeRaw, const std::string& hintAlias) override;
+
+private:
+ llvm::Value* __mem;
+};
+
+class LocalAllocator: public Allocator{
+public:
+ LocalAllocator(LLVMLayer* l): Allocator(l){}
+ virtual llvm::Value* allocate(llvm::Type* elRawT, llvm::Value* sizeRaw, const std::string& hintAlias) override;
+};
+
+}} //xreate::compilation
+#endif //XREATE_MEMORY_H
diff --git a/cpp/src/compilation/resources.cpp b/cpp/src/compilation/resources.cpp
index f7c6b43..4cf462b 100644
--- a/cpp/src/compilation/resources.cpp
+++ b/cpp/src/compilation/resources.cpp
@@ -1,15 +1,18 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Author: pgess <v.melnychenko@xreate.org>
* File: resources.h
*
* Created in April, 2020
*/
#include "compilation/resources.h"
namespace xreate{namespace compilation {
const char *LAMBDA_PREFIX = ".lmd";
+const char *FN_BLOCK_ENTRY = "entry";
+const char *FN_BLOCK_PREALLOC = "prealloc";
+const char *FN_BLOCK_PROLOG = "prolog";
}} // end of xreate::compilation
\ No newline at end of file
diff --git a/cpp/src/compilation/resources.h b/cpp/src/compilation/resources.h
index 319714a..dd9f262 100644
--- a/cpp/src/compilation/resources.h
+++ b/cpp/src/compilation/resources.h
@@ -1,20 +1,23 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Author: pgess <v.melnychenko@xreate.org>
* File: resources.h
*
* Created in April, 2020
*/
#ifndef XREATE_RESOURCES_H
#define XREATE_RESOURCES_H
#include <string>
namespace xreate{namespace compilation{
extern const char *LAMBDA_PREFIX;
+extern const char *FN_BLOCK_ENTRY;
+extern const char *FN_BLOCK_PREALLOC;
+extern const char *FN_BLOCK_PROLOG;
}} // end of xreate::compilation
#endif //XREATE_RESOURCES_H
diff --git a/cpp/src/llvmlayer.cpp b/cpp/src/llvmlayer.cpp
index 1474b50..b0ff434 100644
--- a/cpp/src/llvmlayer.cpp
+++ b/cpp/src/llvmlayer.cpp
@@ -1,295 +1,309 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* llvmlayer.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
*/
/**
* \file llvmlayer.h
* \brief Bytecode generation
*/
#include "ast.h"
#include "llvmlayer.h"
#include "analysis/typehints.h"
#ifdef XREATE_ENABLE_EXTERN
#include "ExternLayer.h"
#endif
#include <compilation/containers.h>
#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/Support/TargetSelect.h"
#include <iostream>
#include <cmath>
using namespace llvm;
using namespace xreate;
using namespace xreate::typehints;
using namespace std;
LLVMLayer::LLVMLayer(AST *root)
: llvmContext(),
irBuilder(llvmContext),
ast(root),
module(new llvm::Module(root->getModuleName(), llvmContext)){
llvm::InitializeNativeTarget();
llvm::InitializeNativeTargetAsmPrinter();
llvm::EngineBuilder builder;
TargetMachine *target = builder.selectTarget();
module->setDataLayout(target->createDataLayout());
#ifdef XREATE_ENABLE_EXTERN
layerExtern = new ExternLayer(this);
layerExtern->init(root);
#endif
}
void *
LLVMLayer::getFunctionPointer(llvm::Function *function){
uint64_t entryAddr = jit->getFunctionAddress(function->getName().str());
return (void *) entryAddr;
}
void
LLVMLayer::initJit(){
std::string ErrStr;
llvm::EngineBuilder builder(std::unique_ptr<llvm::Module>(module.release()));
jit.reset(builder
.setEngineKind(llvm::EngineKind::JIT)
.setTargetOptions(optsTarget)
.setOptLevel(optsLevel)
.setErrorStr(&ErrStr)
.setVerifyModules(true)
.create()
);
}
void
LLVMLayer::print(){
llvm::PassManager<llvm::Module> PM;
PM.addPass(llvm::PrintModulePass(llvm::outs(), "banner"));
llvm::AnalysisManager<llvm::Module> aman;
PM.run(*module.get(), aman);
}
void
LLVMLayer::moveToGarbage(void *o){
__garbage.push_back(o);
}
llvm::Type*
LLVMLayer::toLLVMType(const ExpandedType &ty, const Expression& expr){
TypeAnnotation t = ty.get();
switch(t.__operator){
case TypeOperator::ARRAY:{
if (expr.tags.size() == 0) return nullptr; //TODO shouldn't be invalid
return containers::IContainersIR::getRawType(expr, ty, this);
}
case TypeOperator::RECORD:{
std::vector<llvm::Type *> packVec;
packVec.reserve(t.__operands.size());
std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(packVec, packVec.end()),
[this](const TypeAnnotation &t){
return toLLVMType(ExpandedType(TypeAnnotation(t)));
});
llvm::ArrayRef<llvm::Type *> packArr(packVec);
return llvm::StructType::get(llvmContext, packArr, false);
};
case TypeOperator::REF:{
TypeAnnotation tyRef = t.__operands.at(0);
assert(tyRef.__operator == TypeOperator::ALIAS);
llvm::StructType *tyOpaqRaw = llvm::StructType::create(llvmContext, tyRef.__valueCustom);
llvm::PointerType *tyRefRaw = llvm::PointerType::get(tyOpaqRaw, 0);
return tyRefRaw;
};
case TypeOperator::ALIAS:{
#ifdef XREATE_ENABLE_EXTERN
//Look in extern types
clang::QualType qt = layerExtern->lookupType(t.__valueCustom);
return layerExtern->toLLVMType(qt);
#else
assert(false);
#endif
};
//DEBT omit ID field in case of single variant.
case TypeOperator::VARIANT:{
/* Variant Type Layout:
* {
* id :: i8, Holds stored variant id
* storage:: type of biggest variant
* }
*/
uint64_t sizeStorage = 0;
llvm::Type *typStorageRaw = llvm::Type::getVoidTy(llvmContext);
for(const TypeAnnotation &subtype : t.__operands){
llvm::Type *subtypeRaw = toLLVMType(ExpandedType(subtype));
if(subtypeRaw->isVoidTy()) continue;
uint64_t sizeSubtype = module->getDataLayout().getTypeStoreSize(subtypeRaw);
if(sizeSubtype > sizeStorage){
sizeStorage = sizeSubtype;
typStorageRaw = subtypeRaw;
}
}
std::vector<llvm::Type *> layout;
layout.push_back(llvm::Type::getInt8Ty(llvmContext)); //id
const bool flagHoldsData = sizeStorage > 0;
if(flagHoldsData){
layout.push_back(typStorageRaw); //storage
}
return llvm::StructType::get(llvmContext, llvm::ArrayRef<llvm::Type *>(layout));
}
case TypeOperator::NONE:{
switch(t.__value){
case TypePrimitive::Bool:
return llvm::Type::getInt1Ty(llvmContext);
case TypePrimitive::I8:
return llvm::Type::getInt8Ty(llvmContext);
case TypePrimitive::I32:
return llvm::Type::getInt32Ty(llvmContext);
case TypePrimitive::I64:
return llvm::Type::getInt64Ty(llvmContext);
case TypePrimitive::Int: {
// IntBits hintSize;
// if (existsSize(hintSize)){
// return llvm::IntegerType::getIntNTy(llvmContext, hintSize.n);
// }
TypesHelper helper(this);
return helper.getPreferredIntTy();
}
case TypePrimitive::Float:
return llvm::Type::getDoubleTy(llvmContext);
case TypePrimitive::String:
return llvm::Type::getInt8PtrTy(llvmContext);
case TypePrimitive::Invalid:
return llvm::Type::getVoidTy(llvmContext);
default:
assert(false);
}
}
default:
assert(false);
}
assert(false);
return nullptr;
}
bool
TypesHelper::isRecordT(const ExpandedType &ty){
const TypeAnnotation &t = ty.get();
if(t.__operator == TypeOperator::RECORD){
return true;
}
if(t.__operator != TypeOperator::ALIAS){
return false;
}
#ifdef XREATE_ENABLE_EXTERN
clang::QualType tqual = llvm->layerExtern->lookupType(t.__valueCustom);
const clang::Type * raw = tqual.getTypePtr();
// TODO skip ALL the pointers until non-pointer type found
if (raw->isStructureType()) return true;
if (!raw->isAnyPointerType()) return false;
clang::QualType pointee = raw->getPointeeType();
return pointee->isStructureType();
#else
assert(false);
return false;
#endif
}
bool
TypesHelper::isArrayT(const Expanded<TypeAnnotation>& ty){
const TypeAnnotation &t = ty.get();
if(t.__operator == TypeOperator::ARRAY){
return true;
}
return false;
}
bool
TypesHelper::isPointerT(const ExpandedType &ty){
if(ty.get().__operator != TypeOperator::ALIAS) return false;
#ifdef XREATE_ENABLE_EXTERN
clang::QualType qt = llvm->layerExtern->lookupType(ty.get().__valueCustom);
return llvm->layerExtern->isPointer(qt);
#else
assert(false);
return false;
#endif
}
bool
TypesHelper::isIntegerT(const Expanded<TypeAnnotation>& ty){
return
(ty->__operator == TypeOperator::NONE) &&
((ty->__value == TypePrimitive::Bool) ||
(ty->__value == TypePrimitive::I8) ||
(ty->__value == TypePrimitive::I32) ||
(ty->__value == TypePrimitive::I64) ||
(ty->__value == TypePrimitive::Int));
}
std::vector<std::string>
TypesHelper::getRecordFields(const ExpandedType &t){
#ifdef XREATE_ENABLE_EXTERN
return (t.get().__operator == TypeOperator::RECORD)
? t.get().fields
: llvm->layerExtern->getStructFields(
llvm->layerExtern->lookupType(t.get().__valueCustom));
#else
assert(t.get().__operator == TypeOperator::RECORD);
return t.get().fields;
#endif
}
llvm::IntegerType *
TypesHelper::getPreferredIntTy() const{
unsigned sizePreferred = llvm->module->getDataLayout().getLargestLegalIntTypeSizeInBits();
return llvm::IntegerType::getIntNTy(llvm->llvmContext, sizePreferred);
+}
+
+LLVMBlockLocker::LLVMBlockLocker(LLVMLayer *llvm, bool jumpBack):
+__llvm(llvm), __jumpBack(jumpBack){
+ __blockLocked = __llvm->irBuilder.GetInsertBlock();
+}
+
+LLVMBlockLocker::~LLVMBlockLocker(){
+ if (__jumpBack){
+ assert(__blockLocked);
+ __llvm->irBuilder.CreateBr(__blockLocked);
+ }
+
+ __llvm->irBuilder.SetInsertPoint(__blockLocked);
}
\ No newline at end of file
diff --git a/cpp/src/llvmlayer.h b/cpp/src/llvmlayer.h
index 61738ec..0cdf615 100644
--- a/cpp/src/llvmlayer.h
+++ b/cpp/src/llvmlayer.h
@@ -1,69 +1,79 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* llvmlayer.h
*
* Author: pgess <v.melnychenko@xreate.org>
*/
#ifndef LLVMLAYER_H
#define LLVMLAYER_H
#include "ast.h"
#include "utils.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Target/TargetOptions.h"
namespace llvm {
class ExecutionEngine;
}
namespace xreate {
class ExternLayer;
/** \brief A wrapper over LLVM toolchain to generate and execute bytecode */
class LLVMLayer {
public:
LLVMLayer(AST* rootAST);
mutable llvm::LLVMContext llvmContext;
llvm::IRBuilder<> irBuilder;
AST *ast = 0;
ExternLayer *layerExtern =0;
std::unique_ptr<llvm::Module> module;
std::unique_ptr<llvm::ExecutionEngine> jit;
llvm::TargetOptions optsTarget;
llvm::CodeGenOpt::Level optsLevel = llvm::CodeGenOpt::None;
void moveToGarbage(void *o);
llvm::Type* toLLVMType(const Expanded<TypeAnnotation>& ty, const Expression& expr = Expression());
void print();
void* getFunctionPointer(llvm::Function* function);
void initJit();
private:
llvm::Type* toLLVMType(const Expanded<TypeAnnotation>& ty, std::map<int, llvm::StructType*>& conjunctions) const;
std::vector<void *> __garbage;
};
class TypesHelper {
public:
bool isArrayT(const Expanded<TypeAnnotation>& ty);
bool isRecordT(const Expanded<TypeAnnotation>& ty);
bool isPointerT(const Expanded<TypeAnnotation>& ty);
bool isIntegerT(const Expanded<TypeAnnotation>& ty);
llvm::IntegerType* getPreferredIntTy() const;
std::vector<std::string> getRecordFields(const Expanded<TypeAnnotation>& t);
TypesHelper(const LLVMLayer* llvmlayer): llvm(llvmlayer){}
private:
const LLVMLayer* llvm;
};
+
+struct LLVMBlockLocker{
+ LLVMBlockLocker(LLVMLayer* llvm, bool jumpBack);
+ ~LLVMBlockLocker();
+
+private:
+ LLVMLayer* __llvm;
+ bool __jumpBack;
+ llvm::BasicBlock* __blockLocked;
+};
}
#endif // LLVMLAYER_H
diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp
index 60d53ec..f7f205f 100644
--- a/cpp/src/pass/compilepass.cpp
+++ b/cpp/src/pass/compilepass.cpp
@@ -1,911 +1,916 @@
/* 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"
+#include "compilation/context.h"
+#include <analysis/resources.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);
+ Expression retE = entry->__declarations.at(ScopedSymbol::RetSymbol);
const ExpandedType& retT = ast->getType(retE);
+
+ //Use fn tags as return type hints for now:
+ for (const auto tag: __function->getTags()){
+ retE.tags.emplace(tag.first, tag.second);
+ }
+
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);
+ 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);
+ return irRecords.update(resultRaw, exprT, expr, hintAlias);
}
case ARRAY: {
+ std::unique_ptr<Allocator> allocator(Allocator::create(expr, ctx));
std::unique_ptr<containers::IContainersIR> containerIR(
containers::IContainersIR::create(expr, expectedT, ctx));
- llvm::Value* aggrRaw = containerIR->init(hintAlias);
+ llvm::Value* aggrRaw = containerIR->init(allocator.get(), 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);
+ return controlIR.compileStructIndex(aggrRaw, aggrT, fieldsList, hintAlias);
};
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:{
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);
// }
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);
+ const ExpandedType& exprUndefT = pass->man->root->getType(expr, expectedT);
+ if (exprUndefT->__operator == TypeOperator ::ARRAY){
+ std::unique_ptr<IContainersIR> compiler(IContainersIR::create(expr, exprUndefT.get(), ctx));
+ std::unique_ptr<Allocator> allocator(Allocator::create(expr, ctx));
+ return compiler->init(allocator.get(), hintAlias);
+ }
+
+ llvm::Type* exprUndefRawT = l.toLLVMType(exprUndefT);
+ return llvm::UndefValue::get(exprUndefRawT);
}
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);
+ return irRecords.update(aggrRaw, aggrT, updE, hintAlias);
}
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);
- }
-
+BasicBruteScope::compile() {
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;
+ 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();
+ LLVMLayer* llvm = pass->man->llvm;
+ llvm::IRBuilder<>& builder = llvm->irBuilder;
- const std::string& blockName = "entry";
- llvm::BasicBlock* blockCurrent = builder.GetInsertBlock();
+ string&& functionName = prepareName();
+ std::vector<llvm::Type*>&& types = prepareSignature();
+ llvm::Type* expectedResultType = prepareResult();
- llvm::Value* result = getBruteScope(__entry)->compile(blockName);
- assert(result);
+ llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false);
+ raw = llvm::cast<llvm::Function>(llvm->module->getOrInsertFunction(functionName, ft));
+ prepareBindings();
+ applyAttributes();
- //SECTIONTAG types/convert function ret value
- builder.CreateRet(typeinference::doAutomaticTypeConversion(result, expectedResultType, llvm->irBuilder));
+ LLVMBlockLocker locker(llvm, false);
+ llvm::BasicBlock *blockEntry = llvm::BasicBlock::Create(llvm->llvmContext, FN_BLOCK_ENTRY, raw);
+ builder.SetInsertPoint(blockEntry);
+ compileProlog();
+ llvm::Value* result = getBruteScope(__entry)->compile();
+ assert(result);
- if (blockCurrent) {
- builder.SetInsertPoint(blockCurrent);
- }
+ builder.CreateRet(typeinference::doAutomaticTypeConversion(result, expectedResultType, llvm->irBuilder));
- llvm->moveToGarbage(ft);
- return raw;
+ 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);
+
+ __tableContext->compile();
}
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){
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);
+ transcend->registerQuery(new ContextAllocQuery(), QueryId::ContextAllocQuery);
}
+CompilePass::CompilePass(PassManager* manager)
+ : AbstractPass<void>(manager),
+ __contextMan(new compilation::ContextManager(this)),
+ __tableContext(new compilation::GlobalContextTable(this))
+{}
+
} //end of namespace xreate
/**
* \class xreate::CompilePass
* \brief The owner of the compilation process. Performs fundamental compilation activities along with the xreate::compilation's routines
*
* xreate::CompilePass traverses over xreate::AST tree and produces executable code.
* The pass performs compilation using the following data sources:
* - %Attachments: the data gathered by the previous passes. See \ref xreate::Attachments.
* - Transcend solutions accessible via queries. See \ref xreate::IQuery, \ref xreate::TranscendLayer.
*
* The pass generates a bytecode by employing \ref xreate::LLVMLayer(wrapper over LLVM toolchain).
* Many compilation activities are delegated to more specific routines. Most notable delegated compilation aspects are:
* - Containers support. See \ref xreate::containers.
* - Latex compilation. See \ref xreate::latex.
* - Interpretation support. See \ref xreate::interpretation.
* - Loop saturation support. See \ref xreate::compilation::TransformationsScopeDecorator.
* - External code interaction support. See \ref xreate::ExternLayer (wrapper over Clang library).
*
* \section adaptability_sect Adaptability
* xreate::CompilePass's behaviour can be adapted in several ways:
* - %Function Decorators to alter function-level compilation. See \ref xreate::compilation::IBruteFunction
* - Code Block Decorators to alter code block level compilation. See \ref xreate::compilation::ICodeScopeUnit.
* Default functionality defined by \ref xreate::compilation::DefaultCodeScopeUnit
* - Targets to allow more versitile extensions.
* Currently only xreate::interpretation::TargetInterpretation use Targets infrastructure. See \ref xreate::compilation::Target.
* - Altering %function invocation. See \ref xreate::compilation::IFnInvocation.
*
* Clients are free to construct a compiler instantiation with the desired decorators by using \ref xreate::compilation::CompilePassCustomDecorators.
* As a handy alias, `CompilePassCustomDecorators<void, void>` constructs the default compiler.
*
*/
diff --git a/cpp/src/pass/compilepass.h b/cpp/src/pass/compilepass.h
index d050a82..94e3dd7 100644
--- a/cpp/src/pass/compilepass.h
+++ b/cpp/src/pass/compilepass.h
@@ -1,236 +1,247 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Author: pgess <v.melnychenko@xreate.org>
*
* compilepass.h
*/
#ifndef COMPILEPASS_H
#define COMPILEPASS_H
#include "abstractpass.h"
#include "llvm/IR/Function.h"
namespace xreate {
class TranscendLayer;
class CompilePass;
class LLVMLayer;
namespace interpretation{
class TargetInterpretation;
}
+
+ namespace compilation{
+ class GlobalContextTable;
+ }
}
namespace xreate { namespace compilation {
class IBruteScope;
class IBruteFunction;
class TransformationsManager;
+class ContextManager;
/** \brief Holds current position in %AST while traversing*/
struct Context{
IBruteScope* scope;
IBruteFunction* function;
CompilePass* pass;
};
/** \brief Interface for custom function invocation operation compilation
* \details Default implementation is xreate::compilation::BruteFnInvocation
*/
class IFnInvocation {
public:
/** \brief Returns result of custom function invocation for the given arguments*/
virtual llvm::Value* operator() (std::vector<llvm::Value *>&& args, const std::string& hintDecl="") = 0;
};
/** \brief Default IFnInvocation implementation */
class BruteFnInvocation: public IFnInvocation{
public:
BruteFnInvocation(llvm::Function* callee, LLVMLayer* l)
: __callee(callee), __calleeTy(callee->getFunctionType()), llvm(l) {}
BruteFnInvocation(llvm::Value* callee, llvm::FunctionType* ty, LLVMLayer* l)
: __callee(callee), __calleeTy(ty), llvm(l) {}
/** \brief Makes type conversions and returns LLVM call statement with given arguments*/
llvm::Value* operator() (std::vector<llvm::Value *>&& args, const std::string& hintDecl="");
protected:
llvm::Value* __callee;
llvm::FunctionType* __calleeTy;
LLVMLayer* llvm;
};
/** \brief %Function invocation operator decorator to handle latex enabled functions with hidden extra arguments */
class HiddenArgsFnInvocation : public compilation::IFnInvocation{
public:
HiddenArgsFnInvocation(std::vector<llvm::Value *> args, compilation::IFnInvocation *parent)
: __args(args), __parent(parent){}
llvm::Value *operator()(std::vector<llvm::Value *> &&args, const std::string &hintDecl = "");
private:
std::vector<llvm::Value *> __args;
compilation::IFnInvocation *__parent;
};
/** \brief Interface to allow modification of CodeScope compilation
* \details Default implementation defined in xreate::compilation::DefaultCodeScopeUnit
*/
class IBruteScope{
public:
CompilePass* const pass;
IBruteFunction* const function;
const CodeScope* const scope;
llvm::BasicBlock* lastBlockRaw;
IBruteScope(const CodeScope* const codeScope, IBruteFunction* f, CompilePass* compilePass);
virtual ~IBruteScope();
- virtual llvm::Value* compile(const std::string& hintBlockDecl="")=0;
+ virtual llvm::Value* compile()=0;
virtual llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar="")=0;
virtual llvm::Value* process(const Expression& expr, const std::string& hintVarDecl="", const TypeAnnotation& expectedT = TypeAnnotation())=0;
virtual Symbol bindArg(llvm::Value* value, std::string&& alias)=0;
virtual void bindArg(llvm::Value* value, const ScopedSymbol& s)=0;
- virtual void bindExternalSymb(llvm::Value*, const Symbol& s) = 0;
+ virtual void bindExternalArg(llvm::Value*, const Symbol& s) = 0;
virtual void reset() = 0;
protected:
/** \brief For subclasses to implement this method to define a function name resolution*/
virtual IFnInvocation* findFunction(const Expression& opCall)=0;
};
/** \brief Minimal useful IBruteScope implementation suited for inheritance */
class BasicBruteScope: public IBruteScope{
public:
BasicBruteScope(const CodeScope* const codeScope, IBruteFunction* f, CompilePass* compilePass);
llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar="") override;
llvm::Value* process(const Expression& expr, const std::string& hintAlias="", const TypeAnnotation& expectedT = TypeAnnotation()) override;
- llvm::Value* compile(const std::string& hintBlockDecl="") override;
+ llvm::Value* compile() override;
protected:
IFnInvocation* findFunction(const Expression& opCall) override;
private:
std::string getIndexStr(const Expression& index);
};
/** \brief Interface to specify compilation of %Function */
class IBruteFunction{
public:
IBruteFunction(CodeScope* entry, CompilePass* p):
isLambda(false), pass(p), __entry(entry){}
virtual ~IBruteFunction();
llvm::Function* compile();
IBruteScope* getEntry();
virtual ManagedFnPtr getASTFn() const {return ManagedFnPtr();};
IBruteScope* getBruteScope(const CodeScope * const scope);
IBruteScope* getScopeUnit(ManagedScpPtr scope);
virtual std::string prepareName() = 0;
llvm::Function* raw = nullptr;
bool isLambda;
protected:
CompilePass* pass=nullptr;
CodeScope* __entry;
virtual std::vector<llvm::Type*> prepareSignature() = 0;
virtual llvm::Function::arg_iterator prepareBindings() = 0;
virtual llvm::Type* prepareResult() = 0;
virtual void applyAttributes() = 0;
+ virtual void compileProlog() = 0;
private:
std::map<const CodeScope * const, std::weak_ptr<IBruteScope>> __scopes;
std::list<std::shared_ptr<IBruteScope>> __orphanedScopes;
protected:
std::vector<llvm::Type*> getScopeSignature(CodeScope* scope);
};
/** \brief Minimal useful IBruteFunction implementation suited for inheritance */
class BasicBruteFunction: public IBruteFunction{
public:
BasicBruteFunction(ManagedFnPtr f, CompilePass* p)
: IBruteFunction(f->getEntryScope(), p), __function(f) {}
std::string prepareName() override;
protected:
- virtual std::vector<llvm::Type*> prepareSignature() override;
- virtual llvm::Type* prepareResult() override;
- virtual llvm::Function::arg_iterator prepareBindings() override;
- virtual void applyAttributes() override;
- virtual ManagedFnPtr getASTFn() const {return __function;};
+ virtual std::vector<llvm::Type*> prepareSignature() override;
+ virtual llvm::Type* prepareResult() override;
+ virtual llvm::Function::arg_iterator prepareBindings() override;
+ virtual void applyAttributes() override;
+ virtual ManagedFnPtr getASTFn() const {return __function;};
+ virtual void compileProlog() override {};
protected:
ManagedFnPtr __function;
};
} // end of namespace compilation
class CompilePass : public AbstractPass<void> {
- friend class compilation::BasicBruteScope;
- friend class compilation::IBruteFunction;
+ friend class compilation::BasicBruteScope;
+ friend class compilation::IBruteFunction;
public:
- compilation::TransformationsManager* managerTransformations;
- interpretation::TargetInterpretation* targetInterpretation;
-
- CompilePass(PassManager* manager): AbstractPass<void>(manager) {}
- /** \brief Executes compilation process */
- void run() override;
-
- /**\brief Returns compiled specified %Function
- * \details Executes function compilation or read cache if it's already done
- */
- compilation::IBruteFunction* getBruteFn(const ManagedFnPtr& function);
-
- /**\brief Returns compiled main(entry) %Function in program */
- llvm::Function* getEntryFunction();
-
- /** \brief Initializes queries required by compiler. See xreate::IQuery, xreate::TranscendLayer */
- static void prepareQueries(TranscendLayer* transcend);
- void prepare();
+ compilation::TransformationsManager* managerTransformations;
+ interpretation::TargetInterpretation* targetInterpretation;
+
+ CompilePass(PassManager* manager);
+ /** \brief Executes compilation process */
+ void run() override;
+
+ /**\brief Returns compiled specified %Function
+ * \details Executes function compilation or read cache if it's already done
+ */
+ compilation::IBruteFunction* getBruteFn(const ManagedFnPtr& function);
+
+ /**\brief Returns compiled main(entry) %Function in program */
+ llvm::Function* getEntryFunction();
+
+ /** \brief Initializes queries required by compiler. See xreate::IQuery, xreate::TranscendLayer */
+ static void prepareQueries(TranscendLayer* transcend);
+ void prepare();
+ compilation::ContextManager* getContextManager(){return __contextMan; }
+ compilation::GlobalContextTable* getGlobalContextTable(){return __tableContext;}
protected:
- virtual compilation::IBruteFunction* buildFunctionUnit(const ManagedFnPtr& function)=0;
- virtual compilation::IBruteScope* buildCodeScopeUnit(const CodeScope* const scope, compilation::IBruteFunction* function)=0;
+ virtual compilation::IBruteFunction* buildFunctionUnit(const ManagedFnPtr& function)=0;
+ virtual compilation::IBruteScope* buildCodeScopeUnit(const CodeScope* const scope, compilation::IBruteFunction* function)=0;
private:
- //TODO free `functions` in destructor
- std::map<unsigned int, compilation::IBruteFunction*> functions;
- llvm::Function* __fnEntryRaw = 0;
+ //TODO free `functions` in destructor
+ std::map<unsigned int, compilation::IBruteFunction*> functions;
+ llvm::Function* __fnEntryRaw = 0;
+ compilation::ContextManager* __contextMan;
+ compilation::GlobalContextTable* __tableContext;
};
namespace compilation{
/** \brief Constructs compiler with desired %Function and %Code Scope decorators. See adaptability in xreate::CompilePass*/
template<class FUNCTION_DECORATOR=void, class SCOPE_DECORATOR=void>
class CompilePassCustomDecorators: public ::xreate::CompilePass{
public:
CompilePassCustomDecorators(PassManager* manager): ::xreate::CompilePass(manager) {}
virtual compilation::IBruteFunction* buildFunctionUnit(const ManagedFnPtr& function) override{
return new FUNCTION_DECORATOR(function, this);
}
virtual compilation::IBruteScope* buildCodeScopeUnit(const CodeScope* const scope, IBruteFunction* function) override{
return new SCOPE_DECORATOR(scope, function, this);
}
};
template<>
compilation::IBruteFunction*
CompilePassCustomDecorators<void, void>::buildFunctionUnit(const ManagedFnPtr& function);
template<>
compilation::IBruteScope*
CompilePassCustomDecorators<void, void>::buildCodeScopeUnit(const CodeScope* const scope, IBruteFunction* function);
}} //end of namespace xreate::compilation
#endif // COMPILEPASS_H
diff --git a/cpp/src/query/contextalloc.cpp b/cpp/src/query/contextalloc.cpp
new file mode 100644
index 0000000..c7b11d5
--- /dev/null
+++ b/cpp/src/query/contextalloc.cpp
@@ -0,0 +1,58 @@
+/* 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: alloca.cpp
+ * Author: pgess <v.melnychenko@xreate.org>
+ *
+ * Created on 26/05/2020
+ */
+#include "contextalloc.h"
+#include "analysis/resources.h"
+
+namespace xreate{
+
+void
+ContextAllocQuery::init(TranscendLayer* transcend){
+ const StaticModel model1 = transcend->query(analysis::VAR_ALLOCA_P);
+ for (const auto& entry: model1){
+ ASTSitePacked symb;
+ Gringo::Symbol ann;
+
+ std::tie(symb, ann) = TranscendLayer::parse<ASTSitePacked, Gringo::Symbol>(entry.second);
+ std::string padS = std::get<0>(TranscendLayer::parse(schemeT<analysis::VAR_ALLOCA_SCHEME>(), ann));
+ __model.emplace(padS, transcend->unpack(symb));
+ }
+
+ const StaticModel& model2 = transcend->query(analysis::FN_ALLOCAPAD_P);
+ for (const auto& entry: model2){
+ std::string fnS;
+ Gringo::Symbol ann;
+
+ std::tie(fnS, ann) = TranscendLayer::parse<std::string, Gringo::Symbol>(entry.second);
+ std::string padS = std::get<0>(TranscendLayer::parse(schemeT<analysis::FN_ALLOCAPAD_SCHEME>(), ann));
+ ManagedFnPtr fn = transcend->ast->findFunction(fnS);
+ __modelPads.emplace(fn, padS);
+ }
+}
+
+std::list<ASTSite>
+ContextAllocQuery::getSymbols(const std::string& pad){
+ std::list<ASTSite> result;
+ auto range = __model.equal_range(pad);
+ for(auto entryIt = range.first; entryIt != range.second; ++entryIt){
+ result.push_back(entryIt->second);
+ }
+
+ return result;
+}
+
+std::string
+ContextAllocQuery::getContextPad(const ManagedFnPtr& fn){
+ if(!__modelPads.count(fn)){
+ return "";
+ }
+
+ return __modelPads.at(fn);;
+}
+}//xreate
\ No newline at end of file
diff --git a/cpp/src/query/contextalloc.h b/cpp/src/query/contextalloc.h
new file mode 100644
index 0000000..c998ff3
--- /dev/null
+++ b/cpp/src/query/contextalloc.h
@@ -0,0 +1,37 @@
+/* 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: alloca.h
+ * Author: pgess <v.melnychenko@xreate.org>
+ *
+ * Created on 26/05/2020
+ */
+#ifndef XREATE_CONTEXTALLOC_H
+#define XREATE_CONTEXTALLOC_H
+
+#include "transcendlayer.h"
+
+namespace xreate{
+
+namespace compilation {
+ class AllocContext;
+};
+
+class ContextAllocQuery : public IQuery{
+public:
+ typedef std::multimap<std::string, ASTSite> Model;
+
+ std::list<ASTSite> getSymbols(const std::string& pad);
+ std::string getContextPad(const ManagedFnPtr& fn);
+ const Model& getModel() const {return __model; }
+
+ virtual void init(TranscendLayer* transcend) override;
+
+private:
+ Model __model;
+ std::map<ManagedFnPtr, std::string> __modelPads;
+};
+
+} //xreate
+#endif //XREATE_CONTEXTALLOC_H
diff --git a/cpp/src/transcendlayer.h b/cpp/src/transcendlayer.h
index 59634cc..6367409 100644
--- a/cpp/src/transcendlayer.h
+++ b/cpp/src/transcendlayer.h
@@ -1,311 +1,328 @@
/* 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: transcendlayer.h
*/
#ifndef transcendLAYER_H
#define transcendLAYER_H
#include "ast.h"
#include "contextrule.h"
#include <clingo/clingocontrol.hh>
#include <string>
#include <climits>
#include <unordered_map>
#include <boost/bimap.hpp>
#include <boost/bimap/multiset_of.hpp>
#include <boost/optional.hpp>
#include <boost/scoped_ptr.hpp>
#include <list>
#include <limits>
namespace xreate {
typedef unsigned int ScopePacked;
const ScopePacked SCOPE_ABSTRACT_GLOBAL = std::numeric_limits<ScopePacked>::max();
struct SymbolPacked {
SymbolPacked(){}
SymbolPacked(ScopedSymbol i, ScopePacked s): identifier(i.id), version(i.version), scope(s){}
SymbolPacked(VNameId symbolId, versions::VariableVersion symbolVersion, ScopePacked symbolScope)
: identifier(symbolId), version(symbolVersion), scope(symbolScope){}
VNameId identifier;
versions::VariableVersion version;
ScopePacked scope;
};
bool operator==(const SymbolPacked& s1, const SymbolPacked& s2);
bool operator<(const SymbolPacked& s1, const SymbolPacked& s2);
struct ASTSitePacked {
union {
ASTSite site;
SymbolPacked symbol;
};
enum { SYMBOL, ANON } tag;
ASTSitePacked(){}
explicit ASTSitePacked(const ASTSite& data): site(data), tag(ASTSitePacked::ANON) {}
explicit ASTSitePacked(const SymbolPacked& data): symbol(data), tag(ASTSitePacked::SYMBOL){}
std::string str() const;
};
//bool operator==(const Site& s1, const Site& s2);
//template<>
//struct AttachmentsId<Site>{
// static unsigned int getId(const Site& symbol);
//};
} namespace std {
// template<>
// struct hash<xreate::SymbolNode> {
// std::size_t operator()(xreate::SymbolNode const& s) const noexcept;
// };
//
// template<>
// struct hash<xreate::Site> {
// std::size_t operator()(xreate::Site const& s) const noexcept;
// };
}
namespace xreate {
enum class DFGConnection {
STRONG, WEAK, PROTOTYPE
};
/** \brief Supplies \ref TranscendLayer with results of an analysis*/
class IAnalysisReport {
public:
/** \brief Composes a logic program to represent the analysis data in ASP format, and appends to a stream*/
virtual void print(std::ostringstream& output) const = 0;
virtual ~IAnalysisReport(){};
};
/** \brief Transcend solutions querying interface */
class IQuery {
public:
virtual void init(TranscendLayer* transcend) = 0;
virtual ~IQuery() {}
};
enum class QueryId {
ContainersQuery,
PolymorphQuery,
LatexQuery,
- DemandQuery
+ DemandQuery,
+ ContextAllocQuery
};
namespace dfa{
class DFAGraph;
}
namespace cfa {
class CFAGraph;
}
template<typename Tuple> struct schemeT{};
typedef std::multimap<std::string, Gringo::Symbol> StaticModel;
typedef StaticModel::const_iterator StaticModelIterator;
class TranscendLayer {
friend class ContextRule;
/**\name Data Providers Management */
///@{
public:
void registerReport(IAnalysisReport* report);
void printReports();
void deleteReports();
/** \brief Appends arbitrary string to a logic program
*/
void addRawScript(std::string&& script);
private:
std::list<IAnalysisReport*> __reports;
/** Includes external text files to a *logic program* */
void appendImport();
///@}
/**\name Queries Management */
///@{
public:
/** \brief Registers a query. See xreate::IQuery */
IQuery* registerQuery(IQuery* query, const QueryId& id);
/** \brief Returns a particular query. See xreate::IQuery */
IQuery* getQuery(const QueryId& id);
template<class ...Types>
static std::tuple<Types...> parse(const Gringo::Symbol& atom);
template<class ...Types>
static std::tuple<Types...> parse(schemeT<std::tuple<Types...>>, const Gringo::Symbol& atom);
+
+ template<class Scheme>
+ std::set<Scheme> queryByScheme(const std::string& predicate);
+
template<class Ret>
static Ret parseAtom(const Gringo::Symbol& atom);
StaticModel query(const std::string& atom) const;
size_t getScopesCount() const;
SymbolPacked pack(const Symbol& symbol, std::string hintSymbolName = "");
ScopePacked pack(const CodeScope * const scope);
Symbol unpack(const SymbolPacked& symbol) const;
// SymbolNode pack(const Site& symbol, const std::string& hintSymbolName);
// Site unpack(const SymbolNode& symbol) const;
std::string getHintForPackedSymbol(const SymbolPacked& symbol);
ASTSitePacked pack(const ASTSite& s);
ASTSite unpack(const ASTSitePacked& s);
///@}
private:
std::map<QueryId, IQuery*> __queries;
std::map<SymbolPacked, std::string> __indexSymbolNameHints;
std::unordered_map<const CodeScope*, unsigned int> __indexScopes;
std::vector<const CodeScope*> __registryScopes;
/**\name Diagnostic */
///@{
//TODO diagnostic move over to separate provider/query
public:
/** \brief Registers diagnostic rules */
void addRuleWarning(const RuleWarning &rule);
/** \brief Registers diagnostic messages */
unsigned int registerWarning(std::string &&message);
private:
std::map<unsigned int, std::string> __warnings;
void printWarnings(std::ostream& out);
///@}
///@{
public:
TranscendLayer();
/** \brief Executes reasoning */
void run();
///@}
AST *ast;
protected:
virtual bool processSolution(Gringo::Model const &model);
private:
StaticModel __model;
std::ostringstream __partTags;
std::ostringstream __partGeneral;
};
template<class typ>
struct ParseImplAtom {
static typ get(const Gringo::Symbol& atom) {
return atom.num();
}
};
template<>
struct ParseImplAtom<int> {
static int get(const Gringo::Symbol& atom);
};
template<>
struct ParseImplAtom<std::string> {
static std::string get(const Gringo::Symbol& atom);
};
template<>
struct ParseImplAtom<SymbolPacked> {
static SymbolPacked get(const Gringo::Symbol& atom);
};
template<>
struct ParseImplAtom<Gringo::Symbol> {
static Gringo::Symbol get(const Gringo::Symbol& atom);
};
template<>
struct ParseImplAtom<ASTSitePacked> {
static ASTSitePacked get(const Gringo::Symbol& atom);
};
template<class ItemType>
struct ParseImplAtom<std::list<ItemType>>{
static std::list<ItemType>
get(const Gringo::Symbol& atom){
bool flagIsList = (atom.type() == Gringo::SymbolType::Fun) && atom.name().empty();
std::list<ItemType> result;
if(!flagIsList) {
//treat as degenerate case: list with a single element
result.push_back(ParseImplAtom<ItemType>::get(atom));
return result;
}
for (const Gringo::Symbol& arg: atom.args()) {
result.push_back(ParseImplAtom<ItemType>::get(arg));
}
return result;
}
};
template<>
struct ParseImplAtom<Expression> {
static Expression get(const Gringo::Symbol& atom);
};
template<class Tuple, size_t index>
struct Parse_Impl {
static void parse(Tuple& tup, Gringo::SymSpan::iterator arg) {
const size_t tupleSize = std::tuple_size<Tuple>::value;
typedef typename std::tuple_element < tupleSize - index, Tuple>::type ElType;
ElType& el = std::get < tupleSize - index > (tup);
Gringo::Symbol atom = *arg;
el = ParseImplAtom<ElType>::get(atom);
Parse_Impl<Tuple, index - 1 > ::parse(tup, ++arg);
}
};
template<class Tuple>
struct Parse_Impl<Tuple, 0> {
static void parse(Tuple& tup, Gringo::SymSpan::iterator arg) {
}
};
template<class ...Types>
std::tuple<Types...>
TranscendLayer::parse(const Gringo::Symbol& atom) {
typedef std::tuple < Types...> Tuple;
Tuple tup;
Parse_Impl<Tuple, std::tuple_size<Tuple>::value>::parse(tup, atom.args().first);
return tup;
}
template<class ...Types>
std::tuple<Types...>
TranscendLayer::parse(schemeT<std::tuple<Types...>>, const Gringo::Symbol& atom){
return parse<Types...>(atom);
}
template<class Ret>
Ret
TranscendLayer::parseAtom(const Gringo::Symbol& atom){
return ParseImplAtom<Ret>::get(atom);
}
+template<class Scheme>
+std::set<Scheme> TranscendLayer::queryByScheme(const std::string& predicate){
+ StaticModel model = query(predicate);
+
+ std::set<Scheme> result;
+ std::transform(model.begin(), model.end(), std::inserter(result, result.begin()), [](const auto& entry){
+ const Gringo::Symbol& entryS = entry.second;
+ return parse(schemeT<Scheme>(), entryS);
+ });
+
+ return result;
+}
} //end of xreate namespace
#endif
diff --git a/cpp/tests/ast.cpp b/cpp/tests/ast.cpp
index 4e97c6a..e129f25 100644
--- a/cpp/tests/ast.cpp
+++ b/cpp/tests/ast.cpp
@@ -1,307 +1,324 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* ast.cpp
*
* Created on: Jun 11, 2015
* Author: pgess <v.melnychenko@xreate.org>
*/
#include "supplemental/docutils.h"
#include "xreatemanager.h"
#include "main/Parser.h"
#include "supplemental/basics.h"
#include "gtest/gtest.h"
using namespace std;
using namespace xreate;
using namespace xreate::grammar::main;
TEST(AST, Containers1) {
FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate", "r");
Scanner scanner(input);
Parser parser(&scanner);
parser.Parse();
assert(!parser.errors->count && "Parser errors");
fclose(input);
}
TEST(AST, InterfacesDataCFA) {
XreateManager* man = XreateManager::prepare
("interface(cfa){\n"
" operator map :: annotation1.\n"
"}");
auto answer = man->root->__interfacesData.equal_range(CFA);
EXPECT_EQ(1, std::distance(answer.first, answer.second));
Expression&& scheme = move(answer.first->second);
EXPECT_EQ(Operator::MAP, scheme.op);
EXPECT_EQ("annotation1", scheme.getOperands().at(0).getValueString());
}
TEST(AST, syntax_recognizeIdentifiers) {
XreateManager* man = XreateManager::prepare(R"Code(
test= function(a:: num):: num; entry {
a = b:: int.
b = 8:: int.
a
}
)Code");
}
TEST(AST, syntax_operatorIndex) {
XreateManager* man = XreateManager::prepare(R"Code(
test= function(a:: num):: num; entry {
b = a[1].
b
}
)Code");
}
TEST(AST, IdentHyphen1){
XreateManager* man = XreateManager::prepare(R"Code(
my-fn = function(m-n:: num):: num; entry
{
b = m-n-1:: int.
b
}
)Code");
}
TEST(AST, Variants_switch) {
XreateManager* man = XreateManager::prepare(R"Code(
Color = type variant{Blue, White, Green}.
main = function:: int {
x = White()::Color.
switch variant(x)::int
case (Green) {0}
case (White) {1}
case (Blue){2}
}
)Code");
Expression e = man->root->findFunction("main")->getEntryScope()->getBody();
ASSERT_EQ(4, e.getOperands().size());
ASSERT_EQ(3, e.blocks.size());
}
TEST(AST, TypeVariantEmpty){
std::string code = R"(
my-rec-t = type variant{}
)";
ASSERT_DEATH(XreateManager::prepare(move(code)), "-- line 2 col 29: Variant type can't be empty.");
}
TEST(AST, Lambda_BoundVars_1){
string code = R"(
myfn = function:: int {
a = [1..5]:: [int].
offset = 10:: int.
loop map(a->x:: int):: [int] { x + offset:: int}
}
)";
auto man = details::tier1::XreateManager::prepare(move(code));
CodeScope* scopeEntry = man->root->findFunction("myfn")->getEntryScope();
const string& offsetAlias = "offset";
ScopedSymbol offsetS = scopeEntry->findSymbolByAlias(offsetAlias);
CodeScope* scopeMap = scopeEntry->getBody().blocks.front();
- ASSERT_EQ(1, scopeMap->boundExternalSymbs.size());
- ASSERT_TRUE(scopeMap->boundExternalSymbs.count(Symbol{offsetS, scopeEntry}));
+ ASSERT_EQ(1, scopeMap->boundArgs.size());
+ ASSERT_TRUE(scopeMap->boundArgs.count(Symbol{offsetS, scopeEntry}));
+}
+
+TEST(AST, Annotations1){
+ string code = R"(
+ my-ann = type variant{
+ ann1,
+ ann2(x:: int),
+ ann3(x:: string)
+ }.
+
+ test = function:: int; entry() {
+ 0 :: int; ann1(); ann2(1); ann3("2")
+ }
+ )";
+
+ XreateManager* man = XreateManager::prepare(move(code));
+ man->run();
}
TEST(AST, DISABLED_InterfacesDataDFA) { }
TEST(AST, DISABLED_InterfacesDataExtern) { }
TEST(AST, Doc_LiteralsAndExpressions) {
XreateManager* man = XreateManager::prepare(
R"Code(
Record1 = type {year:: int, month:: string}.
isOdd = function(x :: int) :: bool {true}
test = function:: bool; entry {
x1 = 5 :: int.
x2 = "Nimefurahi kukujua":: string.
x3 = {year = 1934, month = "april"}:: Record1.
x4 = {16, 8, 3} :: [int].
x41 = [1..18]:: [int].
x5 = 8>=3:: bool.
x6 = "Blue" <> "Green" :: bool.
x7 = -true:: bool.
colors = {"Green", "Blue"} :: [string].
color = colors[0] :: string.
date = {year = 1934, month = "april"}:: Record1. year = date["year"] :: int.
a = 0::int. b = 0 :: int.
x7 = a - b:: int.
result = isOdd(6) :: bool.
true
}
)Code");
ASSERT_TRUE(true);
}
TEST(AST, Doc_CodeBlocks1) {
XreateManager* man = XreateManager::prepare(
getDocumentationExampleById("documentation/Syntax/syntax.xml", "CodeBlocks1"));
FnNoArgs resultFn = (FnNoArgs) man->run();
int resultExpected = resultFn();
ASSERT_EQ(12, resultExpected);
}
TEST(AST, Doc_Functions1) {
XreateManager* man = XreateManager::prepare(
getDocumentationExampleById("documentation/Syntax/syntax.xml", "Functions1"));
ASSERT_TRUE(true);
}
TEST(AST, Doc_FunctionSpecializations1) {
XreateManager* man = XreateManager::prepare(
getDocumentationExampleById("documentation/Syntax/syntax.xml", "FunctionSpecialization1"));
ASSERT_TRUE(true);
}
TEST(AST, Doc_BranchStatements) {
string code_IfStatement1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "IfStatement1");
string code_SwitchStatement1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "SwitchStatement1");
string code =
R"Code(
test = function:: int; entry
{
question = "Favorite color?":: string.
monthNum = 2:: int.
%IfStatement1
%SwitchStatement1
monthName
}
)Code";
replace(code, "%IfStatement1", code_IfStatement1);
replace(code, "%SwitchStatement1", code_SwitchStatement1);
XreateManager* man = XreateManager::prepare(move(code));
ASSERT_TRUE(true);
}
TEST(AST, Doc_LoopStatements) {
string code_LoopStatement1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "LoopStatement1");
string code_LoopStatement2 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "LoopStatement2");
string code_FoldStatement1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "FoldStatement1");
string code_MapStatement1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "MapStatement1");
string code =
R"Code(
test = function:: int; entry
{
%LoopStatement1
%LoopStatement2
%FoldStatement1
%MapStatement1
min
}
)Code";
replace(code, "%LoopStatement1", code_LoopStatement1);
replace(code, "%LoopStatement2", code_LoopStatement2);
replace(code, "%FoldStatement1", code_FoldStatement1);
replace(code, "%MapStatement1", code_MapStatement1);
XreateManager::prepare(move(code));
ASSERT_TRUE(true);
}
TEST(AST, Doc_Types){
string code = getDocumentationExampleById("documentation/Syntax/syntax.xml", "Types1");
XreateManager::prepare(move(code));
ASSERT_TRUE(true);
}
TEST(AST, Doc_Variants1){
string code_Variants1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "Variants1");
XreateManager::prepare(move(code_Variants1));
ASSERT_TRUE(true);
}
TEST(AST, Doc_VariantsSwitch1){
string code_Variants1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "VariantsSwitch1");
XreateManager::prepare(move(code_Variants1));
ASSERT_TRUE(true);
}
TEST(AST, Doc_Versions1){
string code_Variants1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "Versions1_1");
string code_Variants2 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "Versions1_2");
string code = R"Code(
test = function:: int; entry
{
<BODY>
y
})Code";
{
std::cout << code_Variants1 << std::endl;
XreateManager* man = XreateManager::prepare(move(code_Variants1));
man->run();
delete man;
ASSERT_TRUE(true);
}
// {
// replace(code, "<BODY>", code_Variants2);
// auto man = details::tier1::XreateManager::prepare(move(code));
// ASSERT_DEATH(man->analyse(), ".*versions graph.*");
// }
}
TEST(AST, Intrinsics1){
string code = R"Code(
test = function:: [int]
{
intrinsic array_init(8):: [int]
})Code";
XreateManager* man = XreateManager::prepare(move(code));
const Expression bodyE = man->root->findFunction("test")->getEntryScope()->getBody();
ASSERT_EQ(Operator::CALL_INTRINSIC, bodyE.op);
ASSERT_EQ(IntrinsicFn ::ARR_INIT, (IntrinsicFn) bodyE.getValueDouble());
}
TEST(AST, TypeRecordEmpty){
std::string code = R"(
my-rec-t = type {}
)";
ASSERT_DEATH(XreateManager::prepare(move(code)), "-- line 2 col 22: Record type can't be empty.");
}
TEST(AST, PredPredicates1){
string code = R"(
my-fn = function:: int; entry() {0}
)";
auto man = XreateManager::prepare(move(code));
}
\ No newline at end of file
diff --git a/cpp/tests/compilation.cpp b/cpp/tests/compilation.cpp
index 46688e9..82dad70 100644
--- a/cpp/tests/compilation.cpp
+++ b/cpp/tests/compilation.cpp
@@ -1,378 +1,422 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* compilation.cpp
*
* Created on: -
* Author: pgess <v.melnychenko@xreate.org>
*/
#include "xreatemanager.h"
#include "supplemental/basics.h"
#include "llvmlayer.h"
#include "pass/compilepass.h"
#include "compilation/lambdas.h"
#include "gtest/gtest.h"
using namespace xreate;
using namespace xreate::compilation;
using namespace std;
//DEBT implement no pkgconfig ways to link libs
//TOTEST FunctionUnit::compileInline
TEST(Compilation, functionEntry1){
std::unique_ptr<XreateManager> program(XreateManager::prepare(
"func1 = function(a:: int):: int {a+8} \
func2 = function::int; entry {12 + func1(4)} \
"));
void* entryPtr = program->run();
int (*entry)() = (int (*)())(intptr_t)entryPtr;
int answer = entry();
ASSERT_EQ(24, answer);
}
TEST(Compilation, full_IFStatementWithVariantType){
XreateManager* man = XreateManager::prepare(
"Color = type variant {RED, BLUE, GREEN}.\n"
"\n"
" main = function(x::int):: bool; entry {\n"
" color = if (x == 0 )::Color {RED()} else {BLUE()}.\n"
" if (color == BLUE())::bool {true} else {false}\n"
" }"
);
bool (*main)(int) = (bool (*)(int)) man->run();
ASSERT_FALSE(main(0));
ASSERT_TRUE(main(1));
}
TEST(Compilation, full_Variant1){
XreateManager* man = XreateManager::prepare(R"Code(
global = type predicate {
entry
}
Command= type variant{
Add(x::int, y::int),
Dec(x::int)
}.
main = function::Command; entry() {
Dec(2) ::Command
}
)Code");
void (*main)() = (void (*)()) man->run();
}
TEST(Compilation, full_SwitchVariant1){
XreateManager* man = XreateManager::prepare(R"Code(
Command= type variant{
Add(x::int, y::int),
Dec(x::int)
}.
main = function::int; entry {
command = Add(3, 5):: Command.
switch variant(command)::int
case(Add){command["x"] + command["y"]}
case(Dec){command["x"]}
}
)Code");
int (*mainFn)() = (int (*)()) man->run();
int result = mainFn();
ASSERT_EQ(8, result);
}
TEST(Compilation, full_SwitchVariantNoArguments2){
XreateManager* man = XreateManager::prepare(R"Code(
Command= type variant{Add, Dec}.
main = function::int; entry {
command = Dec():: Command.
switch variant(command)::int
case(Add){0}
case(Dec){1}
}
)Code");
int (*mainFn)() = (int (*)()) man->run();
int result = mainFn();
ASSERT_EQ(1, result);
}
TEST(Compilation, full_SwitchVariantMixedArguments3){
XreateManager* man = XreateManager::prepare(R"Code(
Command= type variant{
Add(x::int, y::int),
Dec
}.
main = function(arg::int):: int; entry {
command = if (arg > 0)::Command {Dec()} else {Add(1, 2)}.
switch variant(command)::int
case(Add){0}
case(Dec){1}
}
)Code");
int (*mainFn)(int) = (int (*)(int)) man->run();
int result = mainFn(5);
ASSERT_EQ(1, result);
}
TEST(Compilation, full_StructUpdate){
XreateManager* man = XreateManager::prepare(
R"Code(
Rec = type {
a :: int,
b:: int
}.
test= function:: int; entry {
a = {a = 18, b = 20}:: Rec.
b = a + {a = 11}:: Rec.
b["a"]
}
)Code");
int (*main)() = (int (*)()) man->run();
int result = main();
ASSERT_EQ(11, result);
}
TEST(Compilation, AnonymousStruct_init_index){
std::string code =
R"Code(
main = function:: int; entry {
x = {10, 15} :: {int, int}.
x[1]
}
)Code";
std::unique_ptr<XreateManager> man(XreateManager::prepare(move(code)));
int (*main)() = (int (*)()) man->run();
EXPECT_EQ(15, main());
}
TEST(Compilation, AnonymousStruct_init_update){
std::string code =
R"Code(
main = function:: int; entry {
x = {10, 15} :: {int, int}.
y = x + {6}:: {int, int}.
y[0]
}
)Code";
std::unique_ptr<XreateManager> man(XreateManager::prepare(move(code)));
int (*main)() = (int (*)()) man->run();
EXPECT_EQ(6, main());
}
TEST(Compilation, BugIncorrectScopes1){
std::string code =
R"Code(
init = function:: int {10}
main = function(cmd:: int):: int; entry {
x = init():: int.
if(cmd > 0):: int { x + 1 } else { x }
}
)Code";
std::unique_ptr<XreateManager> man(XreateManager::prepare(move(code)));
int (*mainFn)(int) = (int (*)(int)) man->run();
EXPECT_EQ(11, mainFn(1));
}
TEST(Compilation, Sequence1){
std::string code =
R"Code(
interface(extern-c){
libbsd = library:: pkgconfig("libbsd").
include {
libbsd = {"bsd/stdlib.h", "string.h"}
}.
}
start = function:: i32; entry {
seq {
nameNew = "TestingSequence":: string.
setprogname(nameNew)
} {strlen(getprogname())}::i32
}
)Code";
std::unique_ptr<XreateManager> man(XreateManager::prepare(move(code)));
int (*startFn)() = (int (*)()) man->run();
int nameNewLen = startFn();
ASSERT_EQ(15, nameNewLen);
}
TEST(Compilation, BoolInstructions1){
std::string code =
R"Code(
test = function (a:: bool, b:: bool):: bool; entry
{
-a
}
)Code";
std::unique_ptr<XreateManager> man(XreateManager::prepare(move(code)));
Fn2Args startFn = (Fn2Args) man->run();
}
TEST(Compilation, StructIndex1){
std::string code =
R"Code(
Anns = type predicate {
entry()
}
test = function:: int; entry()
{
x = {a = ({b = 3}::{b:: int})}:: {a:: {b:: int}}.
2 + x["a", "b"] + x["a"]["b"]
}
)Code";
std::unique_ptr<XreateManager> man(XreateManager::prepare(move(code)));
FnNoArgs startFn = (FnNoArgs) man->run();
int result = startFn();
ASSERT_EQ(2, result);
}
TEST(Compilation, PreferredInt1){
std::unique_ptr<XreateManager> man(XreateManager::prepare(""));
TypesHelper utils(man->llvm);
int bitwidth = utils.getPreferredIntTy()->getBitWidth();
ASSERT_EQ(64, bitwidth);
}
TEST(Compilation, PredPredicates1){
string code = R"(
my-fn = function:: int; entry() {0}
)";
auto man = XreateManager::prepare(move(code));
FnNoArgs startFn = (FnNoArgs) man->run();
int result = startFn();
ASSERT_EQ(0, result);
}
typedef intmax_t (*FnI_I)(intmax_t);
TEST(Compilation, Lambda1){
string code = R"(
myfn = function:: int {
a = [1..5]:: [int].
loop map(a->x:: int):: [int] { x + 10:: int}
}
)";
auto man = details::tier1::XreateManager::prepare(move(code));
LLVMLayer* llvm = man->llvm;
man->analyse();
std::unique_ptr<CompilePass> compiler(new compilation::CompilePassCustomDecorators<>(man));
compiler->prepare();
- LambdaIR compilerLambda(compiler.get());
+
CodeScope* scopeLoop = man->root->findFunction("myfn")->getEntryScope()->getBody().blocks.front();
- auto fnRaw = compilerLambda.compile(scopeLoop, "loop");
+ LambdaFn lambdaFn(scopeLoop, compiler.get(), "lmb1");
+ auto fnRaw = lambdaFn.compile();
llvm->initJit();
FnI_I fn = (FnI_I)llvm->getFunctionPointer(fnRaw);
ASSERT_EQ(20, fn(10));
}
TEST(Compilation, Lambda_BoundVars1){
string code = R"(
myfn = function:: int {
a = [1..5]:: [int].
offset = 10:: int.
loop map(a->x:: int):: [int] { x + offset:: int}
}
)";
auto man = details::tier1::XreateManager::prepare(move(code));
LLVMLayer* llvm = man->llvm;
man->analyse();
std::unique_ptr<CompilePass> compiler(new compilation::CompilePassCustomDecorators<>(man));
compiler->prepare();
- LambdaIR compilerLambda(compiler.get());
CodeScope* scopeLoop = man->root->findFunction("myfn")->getEntryScope()->getBody().blocks.front();
- auto fnRaw = compilerLambda.compile(scopeLoop, "loop");
+ LambdaFn fnLambda(scopeLoop, compiler.get(), "lmb1");
+ auto fnRaw = fnLambda.compile();
llvm->print();
llvm->initJit();
Fn2Args fn = (Fn2Args)llvm->getFunctionPointer(fnRaw);
- ASSERT_EQ(30, fn(10, 20));
+ intmax_t offset = 20;
+ ASSERT_EQ(30, fn(10, (intmax_t) &offset));
}
struct Tuple3 {intmax_t a; intmax_t b; intmax_t c; };
typedef Tuple3 (*FnTuple3)();
intmax_t fn_BUG_Triple(FnTuple3 callee){
Tuple3 result = callee();
return result.a+ result.b + result.c;
}
TEST(Compilation, BUG_Triple){
std::unique_ptr<XreateManager> man(XreateManager::prepare(R"(
Tuple2 = type {int, int}.
Tuple3 = type {int, int, int}.
Tuple4 = type {int, int, int, int}.
main = function:: Tuple3; entry()
{
{1, 2, 3}
}
)"));
FnTuple3 mainFn = (FnTuple3) man->run();
intmax_t result = fn_BUG_Triple(mainFn);
ASSERT_EQ(6, result);
// ASSERT_EQ(2, result.b);
// ASSERT_EQ(3, result.c);
}
TEST(Compilation, ExteriorFns1){
std::unique_ptr<XreateManager> man(XreateManager::prepare(R"(
fn-a = function:: int; exterior() {1}
fn-b = function:: int; exterior() {2}
)"));
man->options.requireEntryFn = false;
man->run();
FnNoArgs fnA = (FnNoArgs) man->getExteriorFn("fn-a");
ASSERT_EQ(1, fnA());
FnNoArgs fnB = (FnNoArgs) man->getExteriorFn("fn-b");
ASSERT_EQ(2, fnB());
}
TEST(Compilation, LLVMAliases){
FILE* code = fopen("scripts/compilation/llvmaliases.xreate", "r");
assert(code != nullptr);
std::unique_ptr<XreateManager> man(XreateManager::prepare(move(code)));
man->run();
+}
+
+TEST(Compilation, MMPrealloca1){
+ string code = R"(
+ make_arr = function(offset:: int):: [int]; csize(5) {
+ resultInit = undef:: [int]; csize(5); alloca("main").
+ idxs = [0..5]:: [int]; range().
+ loop fold(idxs->i:: int, (resultInit::[int]; csize(5))->result)::[int]; csize(5)
+ {
+ (result::[int]; csize(5)): {[i]= i + offset}
+ }
+ }
+
+ main = function:: int; entry(); allocapad("main") {
+ arr = make_arr(5):: [int]; csize(5).
+ arr[2] - 7
+ }
+ )";
+
+ std::unique_ptr<XreateManager> man(XreateManager::prepare(move(code)));
+ FnNoArgs fnMain = (FnNoArgs) man->run();
+ int resActual = fnMain();
+ ASSERT_EQ(0, resActual);
+}
+
+TEST(Compilation, BUG_Minus1){
+ string code = R"(
+ main = function:: int; entry()
+ {
+ a = 10:: int.
+ b = 3:: int.
+ c = 2:: int.
+
+ a - b - c
+ }
+)";
+
+ std::unique_ptr<XreateManager> man(XreateManager::prepare(move(code)));
+ FnNoArgs fnMain = (FnNoArgs) man->run();
+ int resActual = fnMain();
+ ASSERT_EQ(0, resActual);
+
}
\ No newline at end of file
diff --git a/cpp/tests/containers.cpp b/cpp/tests/containers.cpp
index a960a2d..54202e2 100644
--- a/cpp/tests/containers.cpp
+++ b/cpp/tests/containers.cpp
@@ -1,365 +1,410 @@
/* 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/containers-tests.xreate", "r");
assert(code != nullptr);
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, FoldLambdaBoundVars1){
+ 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-FoldLambdaBoundVars1\")).");
+ man->options.requireEntryFn = false;
+ man->run();
+
+ {
+ Fn2Args fn = (Fn2Args) man->getExteriorFn("fn-FoldLambdaBoundVars1");
+ ASSERT_EQ(91, fn(2, 5));
+ }
+}
+
+TEST(Containers, Reorder1){
+ 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-reorder1\")).");
+ man->options.requireEntryFn = false;
+ man->run();
+
+ {
+ Fn1Args fn = (Fn1Args) man->getExteriorFn("fn-reorder1");
+ ASSERT_EQ(1, fn(32));
+ }
+}
+
+TEST(Containers, LastLess1){
+ 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-LastLess1\")).");
+ man->options.requireEntryFn = false;
+ man->run();
+
+ {
+ Fn1Args fn = (Fn1Args) man->getExteriorFn("fn-LastLess1");
+ ASSERT_EQ(3, fn(12));
+ }
+}
+
//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");
-//}
+//}
\ No newline at end of file
diff --git a/grammar/xreate.ATG b/grammar/xreate.ATG
index 80c548f..4f7a123 100644
--- a/grammar/xreate.ATG
+++ b/grammar/xreate.ATG
@@ -1,837 +1,838 @@
//TODO add ListLiteral
//TODO ExprTyped: assign default(none) type
#include "ast.h"
#include "ExternLayer.h"
#include <string>
#include <stack>
#include <sstream>
#define wprintf(format, ...) \
char __buffer[100]; \
wcstombs(__buffer, format, 100); \
fprintf(stderr, __buffer, __VA_ARGS__)
using namespace std;
COMPILER Xreate
details::inconsistent::AST* root = nullptr; // current program unit
void SemErr(std::initializer_list<std::wstring> msgs){
std::wstringstream output;
for(const auto& msg: msgs){output << msg;}
SemErr(output.str().c_str());
}
void ensureInitalizedAST(){
if (root == nullptr) root = new details::inconsistent::AST();
}
struct {
std::stack<CodeScope*> scopesOld;
CodeScope* scope = nullptr;
} context;
void pushContextScope(CodeScope* scope){
context.scopesOld.push(context.scope);
context.scope = scope;
}
void popContextScope(){
context.scope = context.scopesOld.top();
context.scopesOld.pop();
}
int nextToken()
{
scanner->ResetPeek();
return scanner->Peek()->kind;
}
bool checkTokenAfterIdent(int key){
if (la->kind != _ident) return false;
return nextToken() == key;
}
bool checkParametersList()
{
return la->kind == _ident && nextToken() == _lparen;
}
bool checkInfix()
{
return la->kind == _ident && nextToken() == _ident;
}
bool checkIndex()
{
return la->kind == _ident && nextToken() == _lbrack;
}
bool checkListIndex()
{
return la->kind == _lcurbrack && nextToken() == _lbrack;
}
bool checkFuncDecl()
{
if (la->kind != _ident) return false;
int token2 = nextToken();
int token3 = scanner->Peek()->kind;
return token2 == _assign && token3 == _function;
}
bool checkAssignment()
{
if (la->kind != _ident) return false;
scanner->ResetPeek();
int token2 = scanner->Peek()->kind;
if (token2 == _lcurbrack) {
scanner->Peek();
int token3 = scanner->Peek()->kind;
if (token3 != _rcurbrack) return false;
int token4 = scanner->Peek()->kind;
return token4 == _assign;
}
return token2 == _assign;
}
void recognizeIdentifier(Expression& id, const std::wstring& hint){
if (!context.scope)
SemErr({L"Identifier found in undefined scope: ", hint});
if (!context.scope->recognizeIdentifier(id)){
root->postponeIdentifier(context.scope, id);
}
}
enum SwitchKind{SWITCH_NORMAL, SWITCH_META};
CHARACTERS
letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".
any = ANY - '"'.
digit = "0123456789".
cr = '\r'.
lf = '\n'.
tab = '\t'.
TOKENS
ident = (letter ['-' letter] | '_') {letter ['-' letter] | digit | '_' }.
number = digit{digit}.
string = '"' { any } '"'.
function = "function".
comma = ','.
period = '.'.
lparen = '('.
rparen = ')'.
lbrack = '['.
rbrack = ']'.
lcurbrack = '{'.
rcurbrack = '}'.
equal = "==".
assign = '='.
implic = '-' '>'.
colon = ':'.
tagcolon = "::".
lse = "<=".
lss = "<".
gte = ">=".
gtr = ">".
ne1 = "!=".
ne2= "<>".
COMMENTS FROM "/*" TO "*/" NESTED
COMMENTS FROM "//" TO lf
IGNORE cr + lf + tab
PRODUCTIONS
Xreate = (. Function* function; ensureInitalizedAST(); .)
{( //RuleDecl
InterfaceData | Imprt | GuardSection
| IF(checkFuncDecl()) FDecl<function> (. root->add(function); .)
| TDecl
| SkipModulesSection
)} (. .)
.
Ident<std::wstring& name>=
ident (. name = t->val; .).
// recognition
IdentR<Expression &e> = (. std::wstring name; .)
Ident<name> (. e = Expression(Atom<Identifier_t>(name)); .)
(. recognizeIdentifier(e, name); .).
//versioning
IdentV<Expression& e>= (. std::wstring name; .)
Ident<name> (. e = Expression(Atom<Identifier_t>(name)); .)
[ Version<e> ].
//recognition + versioning
IdentVR<Expression& e>= (. std::wstring name; .)
Ident<name> (. e = Expression(Atom<Identifier_t>(name)); .)
[ Version<e> ] (. recognizeIdentifier(e, name); .)
.
Version<Expression &e>=
lcurbrack (
ident (. SemErr({L"var version as ident is not implemented yet"}); .)
| number (. Attachments::put<versions::VariableVersion>(e, Atom<Number_t>(t->val).get()); .)
) rcurbrack .
FDecl<Function*& f> = (. std::wstring fname; std::wstring argName; TypeAnnotation typIn; TypeAnnotation typOut; Expression binding; .)
Ident<fname> assign
function (. f = new Function(fname); CodeScope* entry = f->getEntryScope(); .)
[lparen Ident<argName> tagcolon ExprAnnotations<binding> (. f->addBinding(Atom<Identifier_t>(argName), move(binding)); .)
{comma Ident<argName> tagcolon ExprAnnotations<binding> (. f->addBinding(Atom <Identifier_t>(argName), move(binding));.)
} rparen]
tagcolon Type<typOut> {';' FnTag<f> }
BDecl<entry> (. const_cast<Expression&>(entry->getBody()).bindType(move(typOut));.)
.
GuardSection<>= (. std::wstring arg, guardI; Expression guardE, guardBinding; Function* f; TypeAnnotation guardT; .)
"guard" lparen
[Ident<arg>] tagcolon Ident<guardI> (. guardE = Expression(Operator::CALL, {Atom<Identifier_t>(guardI)}); bool res = root->recognizeVariantConstructor(guardE); .)
(. if(!res) SemErr(coco_string_create("Can't recognize a guard"));.)
(. if (!arg.empty()) guardE.addBindings({Atom<Identifier_t>(arg)}); .)
(. guardBinding.type = TypeAnnotation(TypeOperator::GUARD, {guardE.type}); guardBinding.type.__valueCustom = Atom<Identifier_t>(guardI).get(); .)
rparen lcurbrack {
FDecl<f> (. f->guard = guardE; if (!arg.empty()){f->addBinding(Atom<Identifier_t>(arg), Expression(guardBinding));} .)
(. root->add(f); .)
} rcurbrack
.
/**
* TYPES
*
*/
TypeTerm<TypePrimitive& typ> = (. std::wstring tid; .)
( "string" (. typ = TypePrimitive::String;.)
| "int" (. typ = TypePrimitive::Int;.)
| "float" (. typ = TypePrimitive::Float;.)
| "bool" (. typ = TypePrimitive::Bool; .)
| "i8" (. typ = TypePrimitive::I8; .)
| "i32" (. typ = TypePrimitive::I32; .)
| "i64" (. typ = TypePrimitive::I64; .)
).
Type<TypeAnnotation& typ> = (. TypeAnnotation typ2; TypePrimitive typ3; std::wstring tid; std::string field; .)
(
TList<typ>
| TRecord<typ>
| TVariant<typ>
| TPred<typ>
| TSlave<typ>
| TRef<typ>
| TypeTerm<typ3> (. typ = typ3; .)
| IF (checkIndex()) Ident<tid> lbrack
TypeIndex<field> (. typ = TypeAnnotation(TypeOperator::ACCESS, {}); typ.__valueCustom = Atom<Identifier_t>(tid).get(); typ.fields.push_back(field); .)
{comma TypeIndex<field> (. typ.fields.push_back(field); .)
} rbrack
| Ident<tid> (. typ = TypeAnnotation(TypeOperator::ALIAS, {}); typ.__valueCustom = Atom<Identifier_t>(tid).get(); .)
[lparen Type<typ2> (. typ.__operands.push_back(typ2); .)
{comma Type<typ2> (. typ.__operands.push_back(typ2); .)
} rparen]
| '*' (.typ = TypeAnnotation(); .)
) .
TypeIndex<std::string& name> =
(
number (. name = Atom<Identifier_t>(t->val).get(); .)
| string (. name = Atom<String_t>(t->val).get(); .)
)
.
TList<TypeAnnotation& typ> = (. TypeAnnotation ty; .)
lbrack Type<ty> rbrack (. typ = TypeAnnotation(TypeOperator::ARRAY, {ty}); .)
.
TRecordBody<TypeAnnotation& typ> =
(. TypeAnnotation t; std::wstring key; size_t keyCounter=0;
typ = TypeAnnotation(TypeOperator::RECORD, {});
.)
{
(
IF(checkTokenAfterIdent(_tagcolon)) Ident<key> tagcolon
| (. key = to_wstring(keyCounter++); .)
)
Type<t> [comma] (. typ.__operands.push_back(t); .)
(. typ.fields.push_back(Atom<Identifier_t>(key).get()); .)
}.
TRecord<TypeAnnotation& typ> =
lcurbrack TRecordBody<typ> rcurbrack
(. if(!typ.__operands.size()) SemErr(coco_string_create("Record type can't be empty.")); .)
.
TVariantRec<TypeAnnotation& typ> = (. TypeAnnotation typVoid; .)
lparen TRecordBody<typ> rparen
(. if(typ.__operands.size()==0) typ = typVoid; .)
.
TVariantBody<TypeAnnotation& typ> = (. TypeAnnotation t, typVoid; std::vector<TypeAnnotation> operands; std::vector<Atom<Identifier_t>> keys; std::wstring v; .)
lcurbrack
{ (. t = typVoid; .)
Ident<v> [TVariantRec<t>] (. keys.push_back(Atom<Identifier_t>(v)); operands.push_back(t); .)
[comma]
}
rcurbrack
(. typ = TypeAnnotation(TypeOperator::VARIANT, {});
typ.__operands = operands;
typ.addFields(std::move(keys));
.)
.
TVariant<TypeAnnotation& typ>=
"variant" TVariantBody<typ>
(. if(!typ.__operands.size()) SemErr(coco_string_create("Variant type can't be empty.")); .)
.
TPred<TypeAnnotation& typ>=
"predicate" TVariantBody<typ>
(. if(!typ.__operands.size()) SemErr(coco_string_create("Predicate type can't be empty.")); .)
.
TSlave<TypeAnnotation& typ>=
"slave" (. typ = TypeAnnotation(TypeOperator::SLAVE, {}); .)
lparen
string (. typ.__valueCustom = Atom<String_t>(t->val).get(); .)
rparen
.
TRef<TypeAnnotation& typ>= (. TypeAnnotation typChild; .)
"ref" lparen Type<typChild> rparen (. typ = TypeAnnotation(TypeOperator::REF, {typChild}); .)
.
TDecl = (. TypeAnnotation t; std::wstring tname, arg; std::vector<Atom<Identifier_t>> args; .)
Ident<tname> assign "type"
[lparen Ident<arg> (. args.push_back(Atom<Identifier_t>(arg)); .)
{comma Ident<arg> (. args.push_back(Atom<Identifier_t>(arg)); .)
} rparen]
Type<t>[period] (. t.addBindings(move(args)); root->add(move(t), Atom<Identifier_t>(tname)); .)
.
ContextDecl<CodeScope * scope> = (. Expression tag; .)
"context" tagcolon
MetaSimpExpr<tag> (. scope->tags.push_back(tag); .)
{';' MetaSimpExpr<tag> (. scope->tags.push_back(tag); .)
}.
VDecl<CodeScope* f> = (. Expression var, value;.)
IdentV<var> assign ExprTyped<value> (. Symbol identSymbol = f->addDefinition(move(var), move(value));
Attachments::put<ExprAlias_A>(value, identSymbol);
.)
.
BDecl<CodeScope* scope> = lcurbrack (. Expression body; pushContextScope(scope); bool flagBodyFound = false; .)
{(IF(checkAssignment()) VDecl<scope> period
// | RuleContextDecl<scope>
| ContextDecl<scope>period
| ExprTyped<body> (. scope->setBody(body); flagBodyFound = true; Attachments::put<ExprAlias_A>(body, Symbol{ScopedSymbol::RetSymbol, scope});.)
)}
rcurbrack (. if(!flagBodyFound) SemErr(coco_string_create("Code block with an empty body!"));
popContextScope();
.)
.
IfDecl<Expression& e> =
(. Expression cond(Operator::AND, {}), condPart;
ManagedScpPtr blockTrue = root->add(new CodeScope(context.scope));
ManagedScpPtr blockFalse = root->add(new CodeScope(context.scope));
e = Expression(Operator::IF, {});
.)
"if" lparen Expr<condPart> (. cond.operands.push_back(condPart); .)
{ comma Expr<condPart> (. cond.operands.push_back(condPart); .)
} rparen (. e.operands.push_back(cond); .)
tagcolon ExprAnnotations<e>
BDecl<&*blockTrue> "else" BDecl<&*blockFalse> (. e.addBlock(blockTrue); e.addBlock(blockFalse); .)
.
LoopDecl<Expression& e> =
(.
Expression eIn, eAcc, eFilters; std::wstring varEl, varAcc, contextClass; Expression tagsEl;
ManagedScpPtr block = root->add(new CodeScope(context.scope));
- block->trackExternalSymbs = true;
+ block->bindExternalArgs = true;
.)
"loop"
(
"map" lparen Expr<eIn> implic Ident<varEl>
(. e = Expression(Operator::MAP, {eIn}); .)
tagcolon ExprAnnotations<tagsEl> rparen tagcolon ExprAnnotations<e>
(.
e.addBindings({Atom<Identifier_t>(varEl)});
block->addBinding(Atom<Identifier_t>(varEl), move(tagsEl));
.)
BDecl<&*block>
(. e.addBlock(block); .)
| "fold" lparen Expr<eIn> implic Ident<varEl> tagcolon ExprAnnotations<tagsEl>
['|' Expr<eFilters> ] comma Expr<eAcc> implic Ident<varAcc>rparen
(.
e = Expression(Operator::FOLD, {eIn, eAcc});
e.addBindings({Atom<Identifier_t>(varEl), Atom<Identifier_t>(varAcc)});
.)
tagcolon ExprAnnotations<e>
(.
Expression varAccBindingE; varAccBindingE.type = e.type;
block->addBinding(Atom<Identifier_t>(varEl), move(tagsEl));
block->addBinding(Atom<Identifier_t>(varAcc), move(varAccBindingE));
.)
BDecl<&*block>
(. e.addBlock(block); .)
| lparen Expr<eAcc> implic Ident<varAcc> rparen
(.
e = Expression(Operator::FOLD_INF, {eAcc});
e.addBindings({Atom<Identifier_t>(varAcc)});
.)
tagcolon ExprAnnotations<e>
(.
Expression varAccBindingE; varAccBindingE.type = e.type;
block->addBinding(Atom<Identifier_t>(varAcc), move(varAccBindingE));
.)
BDecl<&*block>
(. e.addBlock(block); .)
).
// Switches
SwitchDecl<Expression& eSwitch, SwitchKind flagSwitchKind> = (. TypeAnnotation typ; eSwitch = Expression(Operator::SWITCH, {}); Expression eCondition; Expression tag;.)
"switch"
(
SwitchVariantDecl<eSwitch>
| SwitchLateDecl<eSwitch>
| lparen ExprTyped<eCondition> rparen tagcolon ExprAnnotations<eSwitch> (. eSwitch.operands.push_back(eCondition);.)
CaseDecl<eSwitch, flagSwitchKind> {CaseDecl<eSwitch, flagSwitchKind>}
)
.
CaseDecl<Expression& outer, SwitchKind flagSwitchKind> = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); Expression condition; .)
"case"
( IF(flagSwitchKind == SWITCH_META)
lparen MetaSimpExpr<condition> rparen BDecl<&*scope> (. Expression exprCase(Operator::CASE, {}); exprCase.addTags({condition}); exprCase.addBlock(scope); outer.addArg(move(exprCase));.)
| "default" BDecl<&*scope> (. Expression exprCase(Operator::CASE_DEFAULT, {});
exprCase.addBlock(scope);
outer.operands.insert(++outer.operands.begin(), exprCase); .)
| lparen CaseParams<&*scope> rparen (. ManagedScpPtr scopeBody = root->add(new CodeScope(&*scope)); Expression exprCase(Operator::CASE, {}); .)
BDecl<&*scopeBody> (. exprCase.addBlock(scope); exprCase.addBlock(scopeBody); outer.addArg(move(exprCase)); .)
).
CaseParams<CodeScope* scope> = (. Expression condition; Expression guard(Operator::LOGIC_AND, {}); pushContextScope(scope); .)
ExprTyped<condition> (. guard.addArg(Expression(condition)); .)
{comma ExprTyped<condition> (. guard.addArg(Expression(condition)); .)
} (. scope->setBody(guard); popContextScope(); .)
.
SwitchLateDecl<Expression& expr> =
(.
std::wstring aliasCondition; Expression exprCondition, aliasAnns;
expr = Expression(Operator::SWITCH_LATE, {});
ManagedScpPtr scope = root->add(new CodeScope(context.scope));
.)
"late" lparen Expr<exprCondition> [implic Ident<aliasCondition>] [tagcolon ExprAnnotations<aliasAnns>] rparen
tagcolon ExprAnnotations<expr> BDecl<&*scope>
(.
expr.addArg(Expression(exprCondition));
expr.addBlock(scope);
std::string alias;
if(aliasCondition.empty()){
if(exprCondition.__state != Expression::IDENT){
SemErr(coco_string_create("An identifier expected in the short form"));
return;
}
//Use exprCondition as identifier
alias = exprCondition.getValueString();
} else {
//Use aliasCondition
alias = Atom<Identifier_t>(move(aliasCondition)).get();
}
expr.addBindings({Atom<Identifier_t>(string(alias))});
scope->addBinding(Atom<Identifier_t>(move(alias)), move(aliasAnns));
.)
.
SwitchVariantDecl<Expression& expr> =
(. Expression varTested; std::wstring varAlias; bool flagAliasFound = false; expr = Expression(Operator::SWITCH_VARIANT, {}); .)
"variant" lparen Expr<varTested> [implic Ident<varAlias>
(. flagAliasFound = true; .)
] [tagcolon ExprAnnotations<varTested>] rparen tagcolon ExprAnnotations<expr>
(. expr.addArg(std::move(varTested));
if (flagAliasFound) {
expr.addBindings({Atom<Identifier_t>(varAlias)});
} else {
if(varTested.__state == Expression::IDENT){
expr.addBindings({Atom<Identifier_t>(string(varTested.getValueString()))});
}
}
.)
CaseVariantDecl<expr> {CaseVariantDecl<expr>}
.
CaseVariantDecl<Expression& expr> = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); std::wstring key; scope->addBinding(Atom<Identifier_t>(string(expr.bindings.front())), Expression()); .)
"case" lparen Ident<key> rparen (. expr.addArg(root->recognizeVariantConstructor(Atom<Identifier_t>(std::move(key)))); .)
BDecl<&*scope> (. expr.addBlock(scope); .)
.
IntrinsicDecl<Expression& outer>= (. std::wstring name; .)
"intrinsic"
(
Ident< name>
(. outer = Expression(Operator::CALL_INTRINSIC, {});
outer.setValue(Atom<Identifier_t>(name));
root->recognizeIntrinsic(outer);
.)
lparen [CalleeParams<outer>] rparen
| "query" (. outer = Expression(Operator::QUERY, {}); .)
(
"late" IntrinsicQueryLateDecl<outer>
| lparen [CalleeParams<outer>] rparen
)
).
IntrinsicQueryLateDecl<Expression& expr> =
(.
std::wstring predicateAlias; Expression predicateE, predicateAnns;
expr = Expression(Operator::QUERY_LATE, {});
ManagedScpPtr scope = root->add(new CodeScope(context.scope));
.)
lparen Expr<predicateE> implic Ident<predicateAlias> tagcolon ExprAnnotations<predicateAnns> rparen
tagcolon ExprAnnotations<expr> BDecl<&*scope>
(.
expr.addArg(move(predicateE));
expr.addBindings({Atom<Identifier_t>(wstring(predicateAlias))});
scope->addBinding(Atom<Identifier_t>(move(predicateAlias)), move(predicateAnns));
expr.addBlock(scope);
.)
.
SequenceDecl<Expression& sequence> = (. sequence = Expression(); sequence.setOp(Operator::SEQUENCE); ManagedScpPtr scope = root->add(new CodeScope(context.scope)); .)
"seq" BDecl<&*scope> (. sequence.blocks.push_back(&*scope); scope = root->add(new CodeScope(&*scope)); .)
{ (. scope = root->add(new CodeScope(&*scope)); .)
BDecl<&*scope> (. sequence.blocks.push_back(&*scope); .)
}.
/*============================ INTERFACES ===============================*/
Imprt<> =
"import" "raw" lparen string (. root->__rawImports.push_back(Atom<String_t>(t->val).get()); .)
rparen period.
InterfaceData<> = "interface" lparen
( "dfa" rparen InterfaceDFA
// | "extern-c" rparen InterfaceExternC
| "cfa" rparen InterfaceCFA
).
// InterfaceExternC<> = (. ExternData data; .)
// lcurbrack {ExternHeadersDecl<data> | ExternAliasDecl<data> } rcurbrack
// (. root->addExternData(move(data)); .)
// .
//
// ExternPkgDecl<std::wstring& package> =
// "pkgconfig" lparen
// string (. package = t->val.)
// rparen
// .
//
// ExternAliasDecl<ExternData& data> = (. std::wstring alias, package; .)
// Ident<alias> assign "library" lparen ExternPkgDecl<package> rparen period
// (. data.addLibAlias(Atom<Identifier_t>(alias), Atom<String_t>(package)); .)
// .
//
// ExternHeadersDecl<ExternData& data> = (. std::list<std::string> listInc; std::wstring& package; .)
// "include"
// [lparen
// (
// Ident<alias> (. data.requireLibAlias(Atom<Identifier_t>(alias)); .)
// | ExternPkgDecl<package> (. data.requireLibPackage(Atom<String_t>(package)); .)
// )
// rparen]
// lcurbrack { string (. listInc.push_back(Atom<String_t>(t->val).get()); .)
// [comma] } rcurbrack [period] (. data.requireHeaders(listInc); .)
// .
InterfaceDFA<> = lcurbrack { InstructDecl } rcurbrack .
InstructDecl = (.Operator op; Expression tag;
Expression scheme;
std::vector<Expression>& tags = scheme.operands;
tags.push_back(Expression()); /* return value */ .)
"operator" InstructAlias<op> tagcolon lparen (.scheme.setOp(op); .)
[
MetaSimpExpr<tag> (. tags.push_back(tag); .)
{
comma MetaSimpExpr<tag> (. tags.push_back(tag); .)
}
] rparen [ implic MetaSimpExpr<tag> (. tags[0] = tag; .)
] (. root->addDFAData(move(scheme)); .)
period.
InstructAlias<Operator& op> =
(
"map" (. op = Operator::MAP; .)
| "list_range" (. op = Operator::LIST_RANGE; .)
| "list" (. op = Operator::LIST; .)
| "fold" (. op = Operator::FOLD; .)
| "index" (. op = Operator::INDEX; .)
).
InterfaceCFA<> = lcurbrack { InstructCFADecl } rcurbrack .
InstructCFADecl<> = (.Operator op; Expression tag;
Expression scheme;
std::vector<Expression>& tags = scheme.operands; .)
"operator" InstructAlias<op> tagcolon (. scheme.setOp(op); .)
[
MetaSimpExpr<tag> (. tags.push_back(tag); .)
{
comma MetaSimpExpr<tag> (. tags.push_back(tag); .)
}
] period (. root->addInterfaceData(CFA, move(scheme)); .).
/*============================ METAPROGRAMMING ===============================*/
// TagsDecl<CodeScope* f> = (. Expression tag; TagModifier mod = TagModifier::NONE; .)
// ':' { MetaSimpExpr<tag> (. /*f.addTag(std::move(tag), mod); */ .)
// }.
FnTag<Function* f> = (. Expression tag; TagModifier mod = TagModifier::NONE; .)
MetaSimpExpr<tag>
['-' TagMod<mod>] (. f->addTag(std::move(tag), mod); .).
TagMod<TagModifier& mod> =
( "assert" (. mod = TagModifier::ASSERT; .)
| "require" (. mod = TagModifier::REQUIRE; .)
).
// RuleDecl<> =
// "rule" tagcolon (. RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg; .)
// lparen Ident<arg> tagcolon Domain<typ> (. args.add(arg, typ); .)
// {comma Ident<arg> tagcolon Domain<typ> (. args.add(arg, typ); .)
// } rparen
// ["case" RGuard<guards> {comma RGuard<guards>}]
// lcurbrack RBody<args, guards> rcurbrack .
/* - TODO use RGuard for guards-*/
// RuleContextDecl<CodeScope* scope> = (.Expression eHead, eGuards, eBody; .)
// "rule" "context" tagcolon MetaSimpExpr<eHead>
// "case" lparen MetaSimpExpr<eGuards> rparen
// lcurbrack MetaSimpExpr<eBody> rcurbrack (.scope->contextRules.push_back(Expression(Operator::CONTEXT_RULE, {eHead, eGuards, eBody})); .).
// Domain<DomainAnnotation& dom> =
// (
// "function" (. dom = DomainAnnotation::FUNCTION; .)
// | "variable" (. dom = DomainAnnotation::VARIABLE; .)
// ).
// RGuard<RuleGuards& guards>= (. Expression e; .)
// MetaExpr<e> (. guards.add(std::move(e)); .).
// MetaExpr<Expression& e>= (.Operator op; Expression e2; .)
// MetaExpr2<e>
// [MetaOp<op> MetaExpr2<e2> (. e = Expression(op, {e, e2}); .)
// ].
// MetaExpr2<Expression& e>=
// (
// lparen MetaExpr<e> rparen
// | MetaSimpExpr<e>
// ).
MetaSimpExpr<Expression& e>= (. std::wstring i1, infix; Expression e2; .)
(
'-' MetaSimpExpr<e2> (. e = Expression(Operator::NEG, {e2}); .)
| IF(checkParametersList()) Ident<i1>
(. e = Expression(Operator::CALL, {Expression(Atom<Identifier_t>(i1))});
if (!root->recognizeVariantConstructor(e))
SemErr({L"Undefined predicate: ", i1});
.)
lparen [ MetaCalleeParams<e> ] rparen
| IF(checkInfix()) Ident<i1> Ident<infix> MetaSimpExpr<e2>
(. e = Expression(Operator::CALL, {Expression(Atom<Identifier_t>(infix))});
e.addArg(Expression(Atom<Identifier_t>(i1)));
e.addArg(std::move(e2));
.)
| IdentR<e>
| number (. e = Expression(Atom<Number_t>(t->val)); .)
+ | string (. e = Expression(Atom<String_t>(t->val)); .)
).
MetaCalleeParams<Expression& e> = (. Expression e2; .)
MetaSimpExpr<e2> (. e.addArg(Expression(e2)); .)
{comma MetaSimpExpr<e2> (. e.addArg(Expression(e2)); .)
}.
// RBody<const RuleArguments& args, const RuleGuards& guards> =
// (. Expression e; std::wstring msg; .)
// "warning" MetaExpr<e> ["message" string (. msg = t->val; .)
// ] (. root->add(new RuleWarning(RuleArguments(args), RuleGuards(guards), std::move(e), Atom<String_t>(msg))); .)
// .
// MetaOp< Operator& op> =
// implic (. op = Operator::IMPL; .)
// .
/*============================ Expressions ===============================*/
ExprAnnotations<Expression& e> = (. TypeAnnotation typ; std::list<Expression> tags; Expression tag; e.tags.clear();.)
Type<typ> (. e.bindType(move(typ)); .)
{';' MetaSimpExpr<tag> (. tags.push_back(tag); .)
} (. e.addTags(tags); .)
.
ExprTyped<Expression&e> = Expr<e> [tagcolon ExprAnnotations<e>].
Expr< Expression& e> (. Expression e2; .)
= ExprLogicAnd<e>
[ ("or" | "OR") Expr<e2> (. e = Expression(Operator::OR, {e, e2}); .)
]
.
ExprLogicAnd< Expression& e> (. Expression e2; .)
= ExprRel<e>
[ ("and" | "AND") ExprLogicAnd <e2> (. e = Expression(Operator::AND, {e, e2}); .)
]
.
ExprRel< Expression& e> (. Operator op; Expression e2; .)
= ExprArithmAdd<e>
[ RelOp<op> ExprRel<e2> (. e = Expression(op, {e, e2}); .)
]
.
ExprArithmAdd< Expression& e>= (. Operator op; Expression e2; .)
ExprArithmMul< e>
[
AddOp<op>ExprArithmAdd< e2> (. e = Expression(op, {e, e2});.)
].
ExprArithmMul< Expression& e> (. Operator op; Expression e2; .)
= ExprUpdate<e>
[ MulOp< op>
ExprArithmMul< e2> (. e = Expression(op, {e, e2}); .)
].
ExprUpdate<Expression& e>= (. Expression e2; .)
ExprPostfix< e>
[
colon
( IF(checkListIndex()) ListIndexLiteral<e2>
| ListLiteral<e2>) (. e = Expression(Operator::UPDATE, {e, e2}); .)
].
ExprPostfix<Expression& e>
= Term<e>
[ (. e = Expression(Operator::INDEX, {e}); .)
{lbrack CalleeParams<e> rbrack }
].
Term< Expression& e> (. std::wstring name; e = Expression(); .)
=
(IF (checkParametersList()) Ident< name>
(. e = Expression(Operator::CALL, {Atom<Identifier_t>(name)}); root->recognizeVariantConstructor(e); .)
lparen [CalleeParams<e>] rparen
| IdentVR<e>
| ListLiteral<e>
| ListRangeLiteral<e>
| LoopDecl<e>
| IfDecl<e>
| SwitchDecl<e, SWITCH_NORMAL>
| IntrinsicDecl<e>
| SequenceDecl<e>
| number (. e = Expression(Atom<Number_t>(t->val)); .)
| string (. e = Expression(Atom<String_t>(t->val)); .)
| "true" (. e = Expression(Atom<Number_t>(1)); e.bindType(TypePrimitive::Bool); .)
| "false" (. e = Expression(Atom<Number_t>(0)); e.bindType(TypePrimitive::Bool); .)
| "undef" (. e = Expression(Operator::UNDEF, {}); .)
| '-' Term<e> (. e = Expression(Operator::NEG, {e}); .)
| lparen ExprTyped<e> rparen
).
ListLiteral<Expression& e> = (. std::wstring key;
Expression val;
std::list<Atom<Identifier_t>> keys;
e = Expression(Operator::LIST, {});
.)
lcurbrack {
( IF(checkTokenAfterIdent(_assign)) Ident<key> assign
| (. key = L""; .)
) Expr<val> (. keys.push_back(Atom<Identifier_t>(key));
e.operands.push_back(val);
.)
[comma] } rcurbrack (. e.addBindings(keys.begin(), keys.end()); .)
.
ListIndexLiteral<Expression& e> = (. e = Expression(Operator::LIST_INDEX, {});Expression valE;.)
lcurbrack
{ (. Expression idxE(Operator::LIST, {});.)
lbrack CalleeParams<idxE> rbrack
assign Expr<valE>[comma] (. e.operands.push_back(idxE); e.operands.push_back(valE); .)
}
rcurbrack
.
ListRangeLiteral<Expression& e> = (. Expression eFrom, eTo; .)
lbrack Expr<eFrom> ".." Expr<eTo> rbrack (. e = Expression(Operator::LIST_RANGE, {eFrom, eTo}); .)
.
CalleeParams<Expression& e> = (. Expression e2; .)
ExprTyped<e2> (. e.addArg(Expression(e2)); .)
{comma ExprTyped<e2> (. e.addArg(Expression(e2)); .)
}.
AddOp< Operator& op>
= (. op = Operator::ADD; .)
( '+'
| '-' (. op = Operator::SUB; .)
).
MulOp< Operator& op>
= (. op = Operator::MUL; .)
( '*'
| '/' (. op = Operator::DIV; .)
| '%' (. op = Operator::MOD; .)
).
RelOp< Operator& op>
= (. op = Operator::EQU; .)
( equal
| (ne1 | ne2) (. op = Operator::NE; .)
| lse (. op = Operator::LSE; .)
| lss (. op = Operator::LSS; .)
| gte (. op = Operator::GTE; .)
| gtr (. op = Operator::GTR; .)
).
SkipModulesSection = "module" {ANY} (lcurbrack {ANY} rcurbrack | '.').
END Xreate.
diff --git a/scripts/containers/containers-tests.assembly.lp b/scripts/containers/containers-tests.assembly.lp
index c0c6b76..e9703af 100644
--- a/scripts/containers/containers-tests.assembly.lp
+++ b/scripts/containers/containers-tests.assembly.lp
@@ -1,6 +1,8 @@
bind_func(Fn, exterior):-
+ function(Fn);
select(test(Template));
bind_func(Fn, test(Template)).
-bind_func(FnName, exterior):-
- select(function(FnName)).
+bind_func(Fn, exterior):-
+ function(Fn);
+ select(function(Fn)).
diff --git a/scripts/containers/containers-tests.xreate b/scripts/containers/containers-tests.xreate
index 2a617fc..f63aac9 100644
--- a/scripts/containers/containers-tests.xreate
+++ b/scripts/containers/containers-tests.xreate
@@ -1,110 +1,151 @@
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}
+ 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]
+fn-FoldLambdaBoundVars1 = function(scale::int, offset:: int):: int {
+ data = [1..8]:: [int]; range().
+ data2 = loop map(data->el:: int):: [int]; fly(range())
+ {
+ scale * el + offset:: int
+ //scale * el:: int
+ }.
+
+ loop fold(data2->el:: int, 0->sum):: int { el + sum }
+}
+
+fn-reorder1 = function(div:: int):: int; allocapad("global")
+{
+ arr = {2, 4, 6, 8}:: [int]; csize(4).
+ idx = {3, 1}:: [int]; csize(2).
+
+ arr2 = reorder(arr, idx):: [int]; fly(csize(2)).
+
+ loop fold(arr2->divisor::int, div->quotent):: int
+ {
+ quotent / divisor
+ }
+}
+
+reorder = function(aggrSrc:: [int];csize(4), idxs::[int];csize(2)):: [int];fly(csize(2))
{
- loop map(idxs->idx)::[int]
+ loop map(idxs->idx:: int)::[int]; fly(csize(2));alloca("global")
{
- aggrSrc[idx])
+ aggrSrc[idx]::int
}
}
-reverse = function(aggrSrc::[int])::[int]
+reorder2 = function(aggrSrc:: [int];csize(4), idxs::[int];fly(range())):: [int];fly(fly(range()))
{
- sizeDst = 5:: int.
- idxsDst = intrinsic keys(aggrSrc):: [int].
- idxsTnsf = loop map(idxsDst-> idx:: int):: [int]
+ loop map(idxs->idx:: int)::[int]; fly(fly(range()))
{
- sizeDst - idx - 1
+ aggrSrc[idx]::int
}
+}
+
+reverse = function(aggrSrc::[int]; csize(4))::[int];fly(fly(range()))
+{
+ sizeDst = 4:: int.
+ idxsDst = intrinsic keys(aggrSrc):: [int]; range().
+ idxsTnsf = loop map(idxsDst-> idx:: int):: [int]; fly(range()); alloca("main")
+ {
+ sizeDst - (idx + 1):: int
+ }.
- reorder(aggrSrc, idxsTnsf)
+ reorder2(aggrSrc, idxsTnsf)
+}
+
+fn-LastLess1 = function(limit:: int):: int; allocapad("main")
+{
+ aggr = {15, 19, 3, 9}:: [int].
+
+ loop fold((reverse(aggr)::[int];fly(fly(range())))->x:: int, 0->acc):: int
+ {
+ if (x < limit):: int { x } else { acc }
+ }
}
-*/

Event Timeline