Page Menu
Home
Xreate
Search
Configure Global Search
Log In
Docs
Questions
Repository
Issues
Patches
Internal API
Files
F2718201
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sun, Feb 15, 5:14 PM
Size
252 KB
Mime Type
text/x-diff
Expires
Tue, Feb 17, 5:14 PM (1 d, 16 h)
Engine
blob
Format
Raw Data
Handle
237591
Attached To
rXR Xreate
View Options
diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp
index 483b048..4f92561 100644
--- a/cpp/src/ast.cpp
+++ b/cpp/src/ast.cpp
@@ -1,966 +1,972 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Author: pgess <v.melnychenko@xreate.org>
* File: ast.cpp
*/
#include "ast.h"
#include "analysis/typeinference.h"
#include "analysis/predefinedanns.h"
#ifdef XREATE_ENABLE_EXTERN
#include "ExternLayer.h"
#endif
#include <stdexcept>
#include <iostream>
//TODO BDecl. forbid multiple body declaration (ExprTyped)
namespace std {
std::size_t
hash<xreate::ScopedSymbol>::operator()(xreate::ScopedSymbol const& s) const {
return s.id ^ (s.version << 2);
}
bool
equal_to<xreate::ScopedSymbol>::operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const {
return __x.id == __y.id && __x.version == __y.version;
}
size_t
hash<xreate::Symbol>::operator()(xreate::Symbol const& s) const {
return hash<xreate::ScopedSymbol>()(s.identifier) ^ ((long int) s.scope << 1);
}
bool
equal_to<xreate::Symbol>::operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const {
return __x == __y;
};
}
using namespace std;
namespace xreate {
Atom<Identifier_t>::Atom(const std::wstring& value) {
__value = wstring_to_utf8(value);
}
Atom<Identifier_t>::Atom(std::string && name) : __value(name) {
}
const std::string&
Atom<Identifier_t>::get() const {
return __value;
}
Atom<Number_t>::Atom(wchar_t* value) {
//DEBT reconsider number literal recognition
__value = wcstol(value, 0, 10);
}
Atom<Number_t>::Atom(int value)
: __value(value) {
}
double
Atom<Number_t>::get()const {
return __value;
}
Atom<String_t>::Atom(const std::wstring& value) {
assert(value.size() >= 2);
__value = wstring_to_utf8(value.substr(1, value.size() - 2));
}
Atom<String_t>::Atom(std::string && name) : __value(name) {}
const std::string&
Atom<String_t>::get() const {
return __value;
}
/** \brief xreate::Expression static information*/
class ExpressionHints {
public:
static bool
isStringValueValid(const Expression& e) {
switch (e.__state) {
case Expression::INVALID:
assert(false);
case Expression::IDENT:
case Expression::STRING:
return true;
case Expression::NUMBER:
case Expression::BINDING:
return false;
case Expression::COMPOUND:
{
switch (e.op) {
case Operator::CALL:
return true;
default: return false;
}
}
}
return false;
}
static bool
isDoubleValueValid(const Expression& e) {
switch (e.__state) {
case Expression::NUMBER:
return true;
case Expression::INVALID:
assert(false);
case Expression::IDENT:
case Expression::STRING:
case Expression::BINDING:
return false;
case Expression::COMPOUND: {
switch (e.op) {
case Operator::VARIANT:
return true;
default: return false;
}
}
}
return false;
}
};
class TypeResolver {
public:
TypeResolver(const AST* ast,
TypeResolver * parent,
std::set<std::string> trace,
const std::map<std::string, TypeAnnotation>& scope = std::map<std::string, TypeAnnotation>())
: __ast(ast), __scope(scope), __trace(trace), __parent(parent) {}
ExpandedType
operator()(const TypeAnnotation &t, const std::vector<TypeAnnotation> &args = std::vector<TypeAnnotation>()) {
assert(args.size() == t.bindings.size()); // invalid number of arguments
for (size_t i = 0; i < args.size(); ++i) {
__scope[t.bindings.at(i)] = args.at(i);
}
switch (t.__operator) {
case TypeOperator::ARRAY:{
assert(t.__operands.size() == 1);
Expanded<TypeAnnotation> elTy = this->operator()(t.__operands.at(0));
return ExpandedType(TypeAnnotation(TypeOperator::ARRAY, {elTy.get()}));
}
case TypeOperator::RECORD:
{
std::vector<TypeAnnotation>&& packOperands = expandOperands(t.__operands);
auto typNew = TypeAnnotation(TypeOperator::RECORD, move(packOperands));
typNew.fields = t.fields;
return ExpandedType(move(typNew));
};
case TypeOperator::VARIANT:
{
std::vector<TypeAnnotation>&& packOperands = expandOperands(t.__operands);
auto typNew = TypeAnnotation(TypeOperator::VARIANT, move(packOperands));
typNew.fields = t.fields;
return ExpandedType(move(typNew));
};
case TypeOperator::ALIAS: {
std::string alias = t.__valueCustom;
if (__trace.count(alias)){
assert(false && "Recursive Type");
return ExpandedType(TypeAnnotation());
}
const TypeAnnotation& tyAlias = findType(alias);
std::vector<TypeAnnotation>&& operands = expandOperands(t.__operands);
auto traceNew =__trace;
traceNew.insert(alias);
return TypeResolver(__ast, this, traceNew, __scope)(tyAlias, operands);
};
case TypeOperator::ACCESS:
{
std::string alias = t.__valueCustom;
const TypeAnnotation& ty = findType(alias);
TypeAnnotation tyAggr = this->operator()(ty).get();
for (const string& field : t.fields) {
auto fieldIt = std::find(tyAggr.fields.begin(), tyAggr.fields.end(), field);
assert(fieldIt != tyAggr.fields.end() && "unknown field");
int fieldId = fieldIt - tyAggr.fields.begin();
tyAggr = tyAggr.__operands.at(fieldId);
}
return ExpandedType(tyAggr);
}
case TypeOperator::NONE:
case TypeOperator::VOID:
case TypeOperator::SLAVE:
case TypeOperator::REF: {
return ExpandedType(t);
}
default:
assert(false);
}
assert(false);
return ExpandedType(TypeAnnotation());
}
private:
const AST* __ast;
std::map<std::string, TypeAnnotation> __scope;
std::set<std::string> __trace;
TypeResolver* __parent;
std::vector<TypeAnnotation>
expandOperands(const std::vector<TypeAnnotation>& operands) {
std::vector<TypeAnnotation> pack;
pack.reserve(operands.size());
std::transform(operands.begin(), operands.end(), std::inserter(pack, pack.end()),
[this](const TypeAnnotation & t) {
return this->operator()(t).get();
});
return pack;
}
TypeAnnotation findType(const std::string& alias){
if (__scope.count(alias)) {
return __scope.at(alias);
} else if (__parent){
return __parent->findType(alias);
} else if (__ast->__registryTypes.count(alias)){
return __ast->__registryTypes.at(alias);
}
assert(false && "Undefined or external type");
return TypeAnnotation();
}
};
TypeAnnotation::TypeAnnotation()
: __operator(TypeOperator::NONE), __value(TypePrimitive::Invalid) {
}
TypeAnnotation::TypeAnnotation(TypePrimitive typ)
: __value(typ)
{}
TypeAnnotation::TypeAnnotation(TypeOperator op, std::initializer_list<TypeAnnotation> operands)
: __operator(op), __operands(operands) {
}
TypeAnnotation::TypeAnnotation(TypeOperator op, std::vector<TypeAnnotation>&& operands)
: __operator(op), __operands(operands) {
}
bool
TypeAnnotation::isValid() const {
return !(__value == TypePrimitive::Invalid && __operator == TypeOperator::NONE);
}
bool
TypeAnnotation::operator<(const TypeAnnotation& t) const {
if (__operator != t.__operator) return __operator < t.__operator;
if (__operator == TypeOperator::NONE)
return __value < t.__value;
if (__operator == TypeOperator::ALIAS || __operator == TypeOperator::ACCESS) {
if (__valueCustom != t.__valueCustom)
return __valueCustom < t.__valueCustom;
}
return __operands < t.__operands;
}
TypeAnnotation
TypeAnnotation::alias(const std::string& alias) {
TypeAnnotation aliasT(TypeOperator::ALIAS, {});
aliasT.__valueCustom = alias;
return aliasT;
}
void
TypeAnnotation::addBindings(std::vector<Atom<Identifier_t>>&& params) {
bindings.reserve(bindings.size() + params.size());
std::transform(params.begin(), params.end(), std::inserter(bindings, bindings.end()),
[](const Atom<Identifier_t>& ident) {
return ident.get(); });
}
void
TypeAnnotation::addFields(std::vector<Atom<Identifier_t>>&& listFields) {
fields.reserve(fields.size() + listFields.size());
std::transform(listFields.begin(), listFields.end(), std::inserter(fields, fields.end()),
[](const Atom<Identifier_t>& ident) {
return ident.get(); });
}
unsigned int Expression::nextVacantId = 0;
Expression::Expression(const Atom<Number_t>& number)
: Expression() {
__state = NUMBER;
op = Operator::INVALID;
__valueD = number.get();
}
Expression::Expression(const Atom<String_t>& a)
: Expression() {
__state = STRING;
op = Operator::INVALID;
__valueS = a.get();
}
Expression::Expression(const Atom<Identifier_t> &ident)
: Expression() {
__state = IDENT;
op = Operator::INVALID;
__valueS = ident.get();
}
Expression::Expression(const Operator &oprt, std::initializer_list<Expression> params)
: Expression() {
__state = COMPOUND;
op = oprt;
if (op == Operator::CALL) {
assert(params.size() > 0);
Expression arg = *params.begin();
assert(arg.__state == Expression::IDENT);
__valueS = std::move(arg.__valueS);
operands.insert(operands.end(), params.begin() + 1, params.end());
return;
}
operands.insert(operands.end(), params.begin(), params.end());
}
void
Expression::setOp(Operator oprt) {
op = oprt;
switch (op) {
case Operator::INVALID:
__state = INVALID;
break;
default:
__state = COMPOUND;
break;
}
}
void
Expression::addArg(Expression &&arg) {
operands.push_back(arg);
}
void
Expression::addTags(const std::list<Expression> tags) const {
std::transform(tags.begin(), tags.end(), std::inserter(this->tags, this->tags.end()),
[](const Expression & tag) {
return make_pair(tag.getValueString(), tag);
});
}
void
Expression::addBindings(std::initializer_list<Atom<Identifier_t>> params) {
addBindings(params.begin(), params.end());
}
void
Expression::bindType(TypeAnnotation t) {
type = move(t);
}
void
Expression::addBlock(ManagedScpPtr scope) {
blocks.push_back(scope.operator->());
}
const std::vector<Expression>&
Expression::getOperands() const {
return operands;
}
double
Expression::getValueDouble() const {
return __valueD;
}
const std::string&
Expression::getValueString() const {
return __valueS;
}
void
Expression::setValue(const Atom<Identifier_t>&& v) {
__valueS = v.get();
}
void Expression::setValueDouble(double value) {
__valueD = value;
}
bool
Expression::isValid() const {
return (__state != INVALID);
}
bool
Expression::isDefined() const {
return (__state != BINDING && __state != INVALID);
}
Expression::Expression()
: __state(INVALID), op(Operator::INVALID), id(nextVacantId++) {
}
namespace details { namespace inconsistent {
std::map<std::string, IntrinsicFn>
AST::__registryIntrinsics = {};
AST::AST() {
Attachments::init<versions::VariableVersion>();
Attachments::init<IdentifierSymbol>();
Attachments::init<ExprAlias_A>();
Attachments::init<TypeInferred>();
Attachments::init<ExprId_A>();
initIntrinsics();
analysis::PredefinedAnns man = analysis::PredefinedAnns::instance();
man.registerVariants(__registryVariants);
man.registerAliases(__registryTypes);
}
void
AST::addInterfaceData(const ASTInterface& interface, Expression&& data) {
__interfacesData.emplace(interface, move(data));
}
void
AST::addDFAData(Expression &&data) {
__dfadata.push_back(data);
}
void
AST::addExternData(ExternData &&entry) {
//__externdata.push_back(entry);
}
void
AST::add(Function* f) {
__functions.push_back(f);
__dictFunctions.emplace(f->getName(), __functions.size() - 1);
}
void
AST::add(MetaRuleAbstract *r) {
__rules.push_back(r);
}
void
AST::add(TypeAnnotation t, Atom<Identifier_t> alias) {
if (t.__operator == TypeOperator::VARIANT) {
for (int i = 0, size = t.fields.size(); i < size; ++i) {
__registryVariants.emplace(t.fields[i], make_pair(t, i));
}
}
__registryTypes.emplace(alias.get(), move(t));
}
ManagedScpPtr
AST::add(CodeScope* scope) {
this->__scopes.push_back(scope);
return ManagedScpPtr(this->__scopes.size() - 1, &this->__scopes);
}
std::string
AST::getModuleName() {
const std::string name = "main";
return name;
}
ManagedPtr<Function>
AST::findFunction(const std::string& name) {
int count = __dictFunctions.count(name);
if (!count) {
return ManagedFnPtr::Invalid();
}
assert(count == 1);
auto range = __dictFunctions.equal_range(name);
return ManagedPtr<Function>(range.first->second, &this->__functions);
}
std::list<ManagedFnPtr>
AST::getAllFunctions() const {
const size_t size = __functions.size();
std::list<ManagedFnPtr> result;
for (size_t i = 0; i < size; ++i) {
result.push_back(ManagedFnPtr(i, &this->__functions));
}
return result;
}
//TASK select default specializations
std::list<ManagedFnPtr>
AST::getFnSpecializations(const std::string& fnName) const {
auto functions = __dictFunctions.equal_range(fnName);
std::list<ManagedFnPtr> result;
std::transform(functions.first, functions.second, inserter(result, result.end()),
[this](auto f) {
return ManagedFnPtr(f.second, &this->__functions);
});
return result;
}
template<>
ManagedPtr<Function>
AST::begin<Function>() {
return ManagedPtr<Function>(0, &this->__functions);
}
template<>
ManagedPtr<CodeScope>
AST::begin<CodeScope>() {
return ManagedPtr<CodeScope>(0, &this->__scopes);
}
template<>
ManagedPtr<MetaRuleAbstract>
AST::begin<MetaRuleAbstract>() {
return ManagedPtr<MetaRuleAbstract>(0, &this->__rules);
}
void
AST::recognizeIntrinsic(Expression& fn) const {
assert(fn.op == Operator::CALL_INTRINSIC);
if (!__registryIntrinsics.count(fn.getValueString())){
assert(false);
}
IntrinsicFn fnCode = __registryIntrinsics.at(fn.getValueString());
fn.op = Operator::CALL_INTRINSIC;
fn.setValueDouble((int) fnCode);
}
bool
AST::recognizeVariantConstructor(Expression& function) {
assert(function.op == Operator::CALL);
std::string variant = function.getValueString();
if (!__registryVariants.count(variant)) {
return false;
}
auto record = __registryVariants.at(variant);
const TypeAnnotation& typ = record.first;
function.op = Operator::VARIANT;
function.setValueDouble(record.second);
function.type = typ;
return true;
}
Atom<Number_t>
AST::recognizeVariantConstructor(Atom<Identifier_t> ident) {
std::string variant = ident.get();
assert(__registryVariants.count(variant) && "Can't recognize variant constructor");
auto record = __registryVariants.at(variant);
return Atom<Number_t>(record.second);
}
void
AST::postponeIdentifier(CodeScope* scope, const Expression& id) {
__bucketUnrecognizedIdentifiers.emplace(scope, id);
}
void
AST::recognizePostponedIdentifiers() {
for (const auto& identifier : __bucketUnrecognizedIdentifiers) {
if (!identifier.first->recognizeIdentifier(identifier.second)) {
//exception: Ident not found
std::cout << "Unknown identifier: " << identifier.second.getValueString() << std::endl;
assert(false && "Unknown identifier");
}
}
}
xreate::AST*
AST::finalize() {
//all finalization steps:
recognizePostponedIdentifiers();
return reinterpret_cast<xreate::AST*> (this);
}
void
AST::initIntrinsics(){
if (__registryIntrinsics.size()) return;
__registryIntrinsics = {
{"array_init", IntrinsicFn::ARR_INIT},
{"rec_fields", IntrinsicFn::REC_FIELDS}
};
}
} } //namespace details::incomplete
Expanded<TypeAnnotation>
AST::findType(const std::string& name) {
// find in general scope:
if (__registryTypes.count(name))
return expandType(__registryTypes.at(name));
//if type is unknown keep it as is.
TypeAnnotation t(TypeOperator::ALIAS, {});
t.__valueCustom = name;
return ExpandedType(move(t));
}
Expanded<TypeAnnotation>
AST::expandType(const TypeAnnotation &t) const {
return TypeResolver(this, nullptr, {}, {})(t);
}
ExpandedType
AST::getType(const Expression& e, const TypeAnnotation& expectedT) {
return typeinference::getType(e, expectedT, *this);
}
Function::Function(const Atom<Identifier_t>& name)
: __entry(new CodeScope(0)) {
__name = name.get();
}
void
Function::addTag(Expression&& tag, const TagModifier mod) {
string name = tag.getValueString();
__tags.emplace(move(name), move(tag));
}
const std::map<std::string, Expression>&
Function::getTags() const {
return __tags;
}
CodeScope*
Function::getEntryScope() const {
return __entry;
}
void
Function::addBinding(Atom <Identifier_t>&& name, Expression&& argument, const VNameId hintBindingId) {
__entry->addBinding(move(name), move(argument), hintBindingId);
}
const std::string&
Function::getName() const {
return __name;
}
ScopedSymbol
CodeScope::registerIdentifier(const Expression& identifier, const VNameId hintBindingId) {
versions::VariableVersion version = Attachments::get<versions::VariableVersion>(identifier, versions::VERSION_NONE);
auto result = __identifiers.emplace(identifier.getValueString(), hintBindingId? hintBindingId: __identifiers.size() + 1);
return { result.first->second, version };
}
bool
-CodeScope::recognizeIdentifier(const Expression& identifier) const {
- versions::VariableVersion version = Attachments::get<versions::VariableVersion>(identifier, versions::VERSION_NONE);
- const std::string& name = identifier.getValueString();
+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(name)) {
- VNameId id = __identifiers.at(name);
+ //search identifier in the current block
+ if (__identifiers.count(identStr)) {
+ VNameId id = __identifiers.at(identStr);
- Symbol s;
- s.identifier = ScopedSymbol{id, version};
- s.scope = const_cast<CodeScope*> (this);
- Attachments::put<IdentifierSymbol>(identifier, s);
+ Symbol identS;
+ identS.identifier = ScopedSymbol{id, version};
+ identS.scope = const_cast<CodeScope*> (this);
+ Attachments::put<IdentifierSymbol>(identE, identS);
- return true;
- }
+ return true;
+ }
- //search in the parent scope
- if (__parent) {
- return __parent->recognizeIdentifier(identifier);
- }
+ //search in the parent scope
+ bool result = false;
+ if (__parent) {
+ result = __parent->recognizeIdentifier(identE);
+ }
- return false;
+ if (trackExternalSymbs && result){
+ Symbol identS = Attachments::get<IdentifierSymbol>(identE);
+ boundExternalSymbs.insert(identS);
+ }
+
+ return result;
}
ScopedSymbol
-CodeScope::getSymbol(const std::string& alias) {
+CodeScope::findSymbolByAlias(const std::string& alias) {
assert(__identifiers.count(alias));
VNameId id = __identifiers.at(alias);
return {id, versions::VERSION_NONE };
}
void
CodeScope::addBinding(Expression&& var, Expression&& argument, const VNameId hintBindingId) {
argument.__state = Expression::BINDING;
__bindings.push_back(var.getValueString());
ScopedSymbol binding = registerIdentifier(var, hintBindingId);
__declarations[binding] = move(argument);
}
Symbol
CodeScope::addDefinition(Expression&& var, Expression&& body) {
ScopedSymbol s = registerIdentifier(var);
__declarations[s] = move(body);
return Symbol{s, this};
}
CodeScope::CodeScope(CodeScope* parent)
: __parent(parent) {
}
CodeScope::~CodeScope() {
}
void
CodeScope::setBody(const Expression &body) {
assert(__declarations.count(ScopedSymbol::RetSymbol)==0 && "Attempt to reassign scope body");
__declarations[ScopedSymbol::RetSymbol] = body;
}
const Expression&
CodeScope::getBody() const{
return __declarations.at(ScopedSymbol::RetSymbol);
}
const Expression&
CodeScope::getDefinition(const Symbol& symbol, bool flagAllowUndefined){
const CodeScope* self = symbol.scope;
return self->getDefinition(symbol.identifier, flagAllowUndefined);
}
const Expression&
CodeScope::getDefinition(const ScopedSymbol& symbol, bool flagAllowUndefined) const{
static Expression expressionInvalid;
if (!__declarations.count(symbol)){
if (flagAllowUndefined) return expressionInvalid;
assert(false && "Symbol's declaration not found");
}
return __declarations.at(symbol);
}
void
RuleArguments::add(const Atom<Identifier_t> &arg, DomainAnnotation typ) {
emplace_back(arg.get(), typ);
}
void
RuleGuards::add(Expression&& e) {
push_back(e);
}
MetaRuleAbstract::
MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards)
: __args(std::move(args)), __guards(std::move(guards)) {
}
MetaRuleAbstract::~MetaRuleAbstract() {
}
RuleWarning::
RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom<String_t>&& message)
: MetaRuleAbstract(std::move(args), std::move(guards)), __message(message.get()), __condition(condition) {
}
RuleWarning::~RuleWarning() {
}
void
RuleWarning::compile(TranscendLayer& layer) {
//TODO restore addRuleWarning
//layer.addRuleWarning(*this);
}
bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2) {
return (s1.id < s2.id) || (s1.id == s2.id && s1.version < s2.version);
}
bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2) {
return (s1.id == s2.id) && (s1.version == s2.version);
}
bool operator<(const Symbol& s1, const Symbol& s2) {
return (s1.scope < s2.scope) || (s1.scope == s2.scope && s1.identifier < s2.identifier);
}
bool operator==(const Symbol& s1, const Symbol& s2) {
return (s1.scope == s2.scope) && (s1.identifier == s2.identifier);
}
bool operator< (const ASTSite& s1, const ASTSite& s2){
return s1.id < s2.id;
}
bool operator<(const Expression&a, const Expression&b) {
if (a.__state != b.__state) return a.__state < b.__state;
assert(a.__state != Expression::INVALID);
switch (a.__state) {
case Expression::IDENT:
case Expression::STRING:
return a.getValueString() < b.getValueString();
case Expression::NUMBER:
return a.getValueDouble() < b.getValueDouble();
case Expression::COMPOUND:
{
assert(a.blocks.size() == 0);
assert(b.blocks.size() == 0);
if (a.op != b.op) {
return a.op < b.op;
}
bool flagAValid = ExpressionHints::isStringValueValid(a);
bool flagBValid = ExpressionHints::isStringValueValid(b);
if (flagAValid != flagBValid) {
return flagAValid < flagBValid;
}
if (flagAValid) {
if (a.getValueString() != b.getValueString()) {
return a.getValueString() < b.getValueString();
}
}
flagAValid = ExpressionHints::isDoubleValueValid(a);
flagBValid = ExpressionHints::isDoubleValueValid(b);
if (flagAValid != flagBValid) {
return flagAValid < flagBValid;
}
if (flagAValid) {
if (a.getValueDouble() != b.getValueDouble()) {
return a.getValueDouble() < b.getValueDouble();
}
}
if (a.operands.size() != b.operands.size()) {
return (a.operands.size() < b.operands.size());
}
for (size_t i = 0; i < a.operands.size(); ++i) {
bool result = a.operands[i] < b.operands[i];
if (result) return true;
}
return false;
}
case Expression::BINDING:
case Expression::INVALID:
assert(false);
}
return false;
}
bool
Expression::operator==(const Expression& other) const {
if (this->__state != other.__state) return false;
if (ExpressionHints::isStringValueValid(*this)) {
if (this->__valueS != other.__valueS) return false;
}
if (ExpressionHints::isDoubleValueValid(*this)) {
if (this->__valueD != other.__valueD) return false;
}
if (this->__state != Expression::COMPOUND) {
return true;
}
if (this->op != other.op) {
return false;
}
if (this->operands.size() != other.operands.size()) {
return false;
}
for (size_t i = 0; i<this->operands.size(); ++i) {
if (!(this->operands[i] == other.operands[i])) return false;
}
assert(!this->blocks.size());
assert(!other.blocks.size());
return true;
}
const ScopedSymbol
ScopedSymbol::RetSymbol = ScopedSymbol{0, versions::VERSION_NONE};
Expression
ASTSite::getDefinition() const{
if (Attachments::exists<ExprAlias_A>(id)){
const Symbol& siteS = Attachments::get<ExprAlias_A>(id);
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 06517c4..db518d6 100644
--- a/cpp/src/ast.h
+++ b/cpp/src/ast.h
@@ -1,751 +1,754 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Author: pgess <v.melnychenko@xreate.org>
* File: ast.h
*/
/**
* \file ast.h
* \brief A syntax tree representation and related code
*
* \sa xreate::AST
*/
#ifndef AST_H
#define AST_H
#include "attachments.h"
#include "utils.h"
#include <string>
#include <list>
#include <vector>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <algorithm>
#include <climits>
namespace xreate {
struct ScopedSymbol;
struct Symbol;
}
namespace std {
template<>
struct hash<xreate::ScopedSymbol> {
std::size_t operator()(xreate::ScopedSymbol const& s) const;
};
template<>
struct equal_to<xreate::ScopedSymbol> {
bool operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const;
};
template<>
struct hash<xreate::Symbol> {
size_t operator()(xreate::Symbol const& s) const;
};
template<>
struct equal_to<xreate::Symbol> {
bool operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const;
};
}
namespace xreate {
struct String_t {
};
struct Identifier_t {
};
struct Number_t {
};
struct Type_t {
};
template<typename A>
class Atom {
};
//DEBT store line:col for all atoms/identifiers
template<> class
Atom<Identifier_t> {
public:
Atom(const std::wstring& value);
Atom(std::string && name);
const std::string& get() const;
private:
std::string __value;
};
template<>
class Atom<Number_t> {
public:
Atom(wchar_t* value);
Atom(int value);
double get()const;
private:
double __value;
};
template<>
class Atom<String_t> {
public:
Atom(const std::wstring& value);
Atom(std::string && name);
const std::string& get() const;
private:
std::string __value;
};
enum class TypePrimitive {
Invalid, Bool, I8, I32, I64, Int, Float, String
};
enum class TypeOperator {
NONE, VOID, REF, ALIAS, VARIANT, ARRAY, RECORD, ACCESS, SLAVE, GUARD
};
struct struct_tag {
};
const struct_tag tag_struct = struct_tag();
/**
* \brief A type representation to support type system
*
* The class represents type in a denormalized form, i.e. with no arguments and aliases substitution
* \sa AST::expandType()
*/
class TypeAnnotation {
public:
TypeAnnotation();
TypeAnnotation(TypePrimitive typ);
TypeAnnotation(TypeOperator op, std::initializer_list<TypeAnnotation> operands);
TypeAnnotation(TypeOperator op, std::vector<TypeAnnotation>&& operands);
static TypeAnnotation alias(const std::string& alias);
void addBindings(std::vector<Atom<Identifier_t>>&& params);
void addFields(std::vector<Atom<Identifier_t>>&& listFields);
bool operator<(const TypeAnnotation& t) const;
// TypeAnnotation (struct_tag, std::initializer_list<TypePrimitive>);
bool isValid() const;
TypeOperator __operator = TypeOperator::NONE;
std::vector<TypeAnnotation> __operands;
TypePrimitive __value;
std::string __valueCustom;
std::vector<std::string> fields;
std::vector<std::string> bindings;
private:
};
enum class Operator {
INVALID, UNDEF, AND, OR, ADD, SUB, MUL, DIV, MOD,
EQU, NE, NEG, LSS,
LSE, GTR, GTE, LIST,
LIST_INDEX, LIST_RANGE,
CALL, CALL_INTRINSIC, QUERY, QUERY_LATE,
IMPL/* implication */, MAP,
FOLD, FOLD_INF, INDEX,
IF, SWITCH, SWITCH_VARIANT, SWITCH_LATE,
CASE, CASE_DEFAULT, LOGIC_AND,
CONTEXT_RULE, VARIANT, SEQUENCE, UPDATE
};
class Function;
class AST;
class CodeScope;
class MetaRuleAbstract;
typedef ManagedPtr<Function> ManagedFnPtr;
typedef ManagedPtr<CodeScope> ManagedScpPtr;
typedef ManagedPtr<MetaRuleAbstract> ManagedRulePtr;
const ManagedScpPtr NO_SCOPE = ManagedScpPtr(UINT_MAX, 0);
/**
* \brief AST node to represent a single instruction or an annotation
* \attention In case of any changes update \ref xreate::ExpressionHints auxiliary helper as well
*
* %Expression is a generic building block of syntax tree which is able to hold node data
* along with child nodes as operands.
*
* \note For types the %expression-like data structure \ref TypeAnnotation is used rather than Expression itself.
* \sa xreate::AST, xreate::TypeAnnotation
*/
struct Expression {
friend class CodeScope;
friend class TranscendLayer;
friend class CFAPass;
friend class ExpressionHints;
Expression(const Operator &oprt, std::initializer_list<Expression> params);
Expression(const Atom<Identifier_t>& ident);
Expression(const Atom<Number_t>& number);
Expression(const Atom<String_t>& a);
Expression();
void setOp(Operator oprt);
void addArg(Expression&& arg);
void addBindings(std::initializer_list<Atom<Identifier_t>> params);
void bindType(TypeAnnotation t);
template<class InputIt>
void addBindings(InputIt paramsBegin, InputIt paramsEnd);
void addTags(const std::list<Expression> tags) const;
void addBlock(ManagedScpPtr scope);
const std::vector<Expression>& getOperands() const;
double getValueDouble() const;
void setValueDouble(double value);
const std::string& getValueString() const;
void setValue(const Atom<Identifier_t>&& v);
bool isValid() const;
bool isDefined() const;
bool operator==(const Expression& other) const;
/**
* \brief is it string, number, compound operation and so on
*/
enum {
INVALID, COMPOUND, IDENT, NUMBER, STRING, BINDING
} __state = INVALID;
/**
* \brief Valid for compound State. Holds type of compound operator
*/
Operator op;
/**
* \brief Unique id to identify expression within syntax tree
*/
unsigned int id;
/**
* \brief Exact meaning depends on particular instruction
* \details As an example, named lists/structs hold field names in bindings
*/
std::vector<std::string> bindings;
/**
* \brief Holds child instructions as arguments
*/
std::vector<Expression> operands;
/**
* \brief Holds type of instruction's result
*/
TypeAnnotation type;
/**
* \brief Holds additional annotations
*/
mutable std::map<std::string, Expression> tags;
/**
* \brief Child code blocks
* \details For example, If statement holds TRUE-branch as first and FALSE-branch as second block here
*/
std::list<CodeScope*> blocks;
private:
std::string __valueS;
double __valueD;
static unsigned int nextVacantId;
};
bool operator<(const Expression&, const Expression&);
template<class InputIt>
void Expression::addBindings(InputIt paramsBegin, InputIt paramsEnd) {
size_t index = bindings.size();
std::transform(paramsBegin, paramsEnd, std::inserter(bindings, bindings.end()),
[&index, this] (const Atom<Identifier_t> atom) {
std::string key = atom.get();
return key;
});
}
typedef std::list<Expression> ExpressionList;
enum class TagModifier {
NONE, ASSERT, REQUIRE
};
enum class DomainAnnotation {
FUNCTION, VARIABLE
};
class RuleArguments : public std::vector<std::pair<std::string, DomainAnnotation>>
{
public:
void add(const Atom<Identifier_t>& name, DomainAnnotation typ);
};
class RuleGuards : public std::vector<Expression> {
public:
void add(Expression&& e);
};
class TranscendLayer;
class LLVMLayer;
class MetaRuleAbstract {
public:
MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards);
virtual ~MetaRuleAbstract();
virtual void compile(TranscendLayer& layer) = 0;
protected:
RuleArguments __args;
RuleGuards __guards;
};
class RuleWarning : public MetaRuleAbstract {
friend class TranscendLayer;
public:
RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom<String_t>&& message);
virtual void compile(TranscendLayer& layer);
~RuleWarning();
private:
std::string __message;
Expression __condition;
};
typedef unsigned int VNameId;
namespace versions {
typedef int VariableVersion;
const VariableVersion VERSION_NONE = -2;
const VariableVersion VERSION_INIT = 0;
}
template<>
struct AttachmentsDict<versions::VariableVersion> {
typedef versions::VariableVersion Data;
static const unsigned int key = 6;
};
struct ScopedSymbol {
VNameId id;
versions::VariableVersion version;
static const ScopedSymbol RetSymbol;
};
struct Symbol {
ScopedSymbol identifier;
const CodeScope * scope;
};
struct ASTSite {
unsigned int id;
Expression getDefinition() const;
//static Ast registerSite(const Expression& e);
};
struct IdentifierSymbol{};
struct ExprAlias_A{};
struct ExprId_A{};
template<>
struct AttachmentsDict<IdentifierSymbol> {
typedef Symbol Data;
static const unsigned int key = 7;
};
template<>
struct AttachmentsDict<ExprAlias_A> {
typedef Symbol Data;
static const unsigned int key = 9;
};
template<>
struct AttachmentsDict<ExprId_A>{
typedef Expression Data;
static const unsigned int key = 12;
};
typedef std::pair<Expression, TagModifier> Tag;
bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2);
bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2);
bool operator<(const Symbol& s1, const Symbol& s2);
bool operator==(const Symbol& s1, const Symbol& s2);
bool operator< (const ASTSite& s1, const ASTSite& s2);
/**
* \brief AST node to represent a single code block/a scope of visibility
*
* Holds a single expression as a `body` along with set of variable assignments(declarations) used in body's expression.
* \sa xreate::AST
*/
class CodeScope {
friend class Function;
friend class PassManager;
public:
CodeScope(CodeScope* parent = 0);
~CodeScope();
/** \brief Set expression as a body */
void setBody(const Expression& body);
/** \brief Returns current code scope body */
const Expression& getBody() const;
/** \brief Adds variable definition to be used in body as well as in other declarations */
Symbol addDefinition(Expression&& var, Expression&& body);
/** \brief Returns symbols' definition */
static const Expression& getDefinition(const Symbol& symbol, bool flagAllowUndefined = false);
const Expression& getDefinition(const ScopedSymbol& symbol, bool flagAllowUndefined = false) const;
/** \brief Adds variable defined elsewhere */
void addBinding(Expression&& var, Expression&& argument, const VNameId hintBindingId = 0);
std::vector<std::string> __bindings;
std::map<std::string, VNameId> __identifiers;
CodeScope* __parent;
//TODO move __definitions to SymbolsAttachments data
//NOTE: definition of return type has index 0
std::unordered_map<ScopedSymbol, Expression> __declarations;
std::vector<Expression> tags;
std::vector<Expression> contextRules;
-
+
+ bool trackExternalSymbs = false;
+ std::set<Symbol> boundExternalSymbs;
+
private:
ScopedSymbol registerIdentifier(const Expression& identifier, const VNameId hintBindingId = 0);
public:
- bool recognizeIdentifier(const Expression& identifier) const;
- ScopedSymbol getSymbol(const std::string& alias);
+ 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
};
namespace details { namespace inconsistent {
/**
* \brief AST in an inconsistent form during construction
*
* Represents AST under construction(**inconsistent state**).
* \attention Clients should use rather xreate::AST unless client's code explicitly works with Syntax Tree during construction.
*
* Typically an instance is created by xreate::XreateManager only and filled out by the parser
* \sa xreate::XreateManager::prepare(std::string&&)
*/
class AST {
friend class xreate::TypeResolver;
public:
AST();
/**
* \brief Adds new function to AST
* \param f Function to register
*/
void add(Function* f);
/**
* \brief Adds new declarative rule to AST
* \param r Declarative Rule
*/
void add(MetaRuleAbstract* r);
/** \brief Registers new code block */
ManagedScpPtr add(CodeScope* scope);
/**
* \brief Add new type to AST
* @param t Type definition
* @param alias Typer name
*/
void add(TypeAnnotation t, Atom<Identifier_t> alias);
/** \brief Current module's name */
std::string getModuleName();
/**
* \brief Looks for function with given name
* \param name Function name to find
* \note Requires that only one function exists under given name
* \return Found function
*/
ManagedPtr<Function> findFunction(const std::string& name);
/** \brief Returns all function in AST */
std::list<ManagedFnPtr> getAllFunctions() const;
/**
* \brief Returns all specializations of a function with a given name
* \param fnName function to find
* \return list of found function specializations
*/
std::list<ManagedFnPtr> getFnSpecializations(const std::string& fnName) const;
/**
* \return First element in Functions/Scopes/Rules list depending on template parameter
* \tparam Target either Function or CodeScope or MetaRuleAbstract
*/
template<class Target>
ManagedPtr<Target> begin();
/**
* \brief Performs all necessary steps after AST is built
*
* Performs all finalization steps and moves AST into consistent state represented by xreate::AST
* \sa xreate::AST
* \return AST in consistent state
*/
xreate::AST* finalize();
typedef std::multimap<std::string, unsigned int> FUNCTIONS_REGISTRY;
//std::list<ExternData> __externdata;
std::list<Expression> __dfadata; //TODO move to more appropriate place
std::list<std::string> __rawImports; //TODO move to more appropriate place
std::multimap<ASTInterface, Expression> __interfacesData; //TODO CFA data here.
private:
std::vector<MetaRuleAbstract*> __rules;
std::vector<Function*> __functions;
std::vector<CodeScope*> __scopes;
FUNCTIONS_REGISTRY __dictFunctions;
protected:
std::map<std::string, TypeAnnotation> __registryTypes;
public:
/**
* \brief Stores DFA scheme for later use by DFA Pass
*
* Treats expression as a DFA scheme and feeds to the DFA Pass later
* \param data DFA Scheme
* \sa xreate::DFAPass
*/
void addDFAData(Expression&& data);
/** \brief Stores data for later use by xreate::ExternLayer */
void addExternData(ExternData&& entry);
/**
* \brief Generalized function to store particular data for later use by particular pass
* \param interface Particular Interface
* \param data Particular data
*/
void addInterfaceData(const ASTInterface& interface, Expression&& data);
/**\name Symbols Recognition */
///@{
public:
//TODO revisit enums/variants, move to codescope
/**
* \brief Tries to find out whether expression is Variant constructor
*/
bool recognizeVariantConstructor(Expression& function);
Atom<Number_t> recognizeVariantConstructor(Atom<Identifier_t> ident);
/**
* \brief Postpones unrecognized identifier for future second round of recognition
* \param scope Code block identifier is encountered
* \param id Identifier
*/
void postponeIdentifier(CodeScope* scope, const Expression& id);
/** \brief Second round of identifiers recognition done right after AST is fully constructed */
void recognizePostponedIdentifiers();
void recognizeIntrinsic(Expression& fn) const;
private:
std::map<std::string, std::pair<TypeAnnotation, int>> __registryVariants;
static std::map<std::string, IntrinsicFn> __registryIntrinsics;
std::set<std::pair<CodeScope*, Expression>> __bucketUnrecognizedIdentifiers;
static void initIntrinsics();
public:
///@}
};
template<>
ManagedPtr<Function>
AST::begin<Function>();
template<>
ManagedPtr<CodeScope>
AST::begin<CodeScope>();
template<>
ManagedPtr<MetaRuleAbstract>
AST::begin<MetaRuleAbstract>();
} } // namespace details::incomplete
/**
* \brief AST in a consistent state
*
* AST has two mutually exclusive possible states:
* - an inconsistent state while AST is under construction. Represented by xreate::details::inconsistent::AST
* - a consistent state when AST is built and finalize() is invoked.
*
* This class represents a consistent state and should be used by clients unless client's code explicitly works with AST under construction.
* Consistent AST enables access to additional functions(such as type management).
* \sa xreate::details::inconsistent::AST
*/
class AST : public details::inconsistent::AST {
public:
AST() : details::inconsistent::AST() {}
/**
* \brief Computes fully expanded form of type by substituting all arguments and aliases
* \param t Type to expand
* \return Expdanded or normal form of type
* \sa TypeAnnotation
*/
ExpandedType expandType(const TypeAnnotation &t) const;
/**
* Searches type by given name
* \param name Typename to search
* \return Expanded or normal form of desired type
* \note if type name is not found returns new undefined type with this name
*/
ExpandedType findType(const std::string& name);
/**
* Invokes Type Inference Analysis to find out expanded(normal) form expressions's type
* \sa typeinference.h
* \param e
* \param expectedT expected type
* \return Type of expression
*/
ExpandedType getType(const Expression& e, const TypeAnnotation& expectedT = TypeAnnotation());
};
}
#endif // AST_H
diff --git a/cpp/src/compilation/control.cpp b/cpp/src/compilation/control.cpp
index 6eb5fc6..7780fa9 100644
--- a/cpp/src/compilation/control.cpp
+++ b/cpp/src/compilation/control.cpp
@@ -1,393 +1,393 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: control.cpp
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on June 26, 2016, 6:00 PM
*/
#include "analysis/typeinference.h"
#include "compilation/control.h"
#include "compilation/containers.h"
#include "compilation/transformersaturation.h"
#include "query/containers.h"
#include "llvmlayer.h"
#include "ast.h"
using namespace std;
using namespace llvm;
using namespace xreate;
using namespace xreate::containers;
using namespace xreate::compilation;
#define NAME(x) (hintRetVar.empty()? x : hintRetVar)
#define UNUSED(x) (void)(x)
#define EXPAND_CONTEXT \
LLVMLayer* llvm = context.pass->man->llvm; \
compilation::IBruteScope* scope = context.scope; \
compilation::IBruteFunction* function = context.function;
ControlIR::ControlIR(compilation::Context ctx)
: context(ctx), tyNum(static_cast<llvm::IntegerType*> (ctx.pass->man->llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::Int))))) {
}
Value*
ControlIR::compileStructIndex(llvm::Value* aggregate, ExpandedType aggrT, const list<string>& indices) {
EXPAND_CONTEXT UNUSED(scope); UNUSED(function);
TypesHelper types(llvm);
llvm::Value* result = aggregate;
assert(indices.size());
for (const string& indexField: indices){
const std::vector<std::string>& tyfields = types.getRecordFields(aggrT);
unsigned idx = -1; bool flagFound = false;
for (unsigned i = 0, size = tyfields.size(); i < size; ++i) {
if (tyfields.at(i) == indexField) {
idx = i; flagFound = true; break;
}
}
if (flagFound){
result = llvm->irBuilder.CreateExtractValue(result, llvm::ArrayRef<unsigned>{idx});
aggrT = typeinference::getSubtype(aggrT, indexField);
} else {
assert(false && "not found required struct field");
}
}
return result;
//dereference pointer
//if (types.isPointerT(t)) {
// llvm::Value* addr = llvm->irBuilder.CreateConstGEP2_32(nullptr, aggregate, 0, i);
// return llvm->irBuilder.CreateLoad(addr);
//}
}
llvm::Value*
ControlIR::compileFold(const Expression& loopE, const std::string& hintAlias) {
EXPAND_CONTEXT
assert(loopE.op == Operator::FOLD);
AST* ast = context.pass->man->root;
//initialization:
const Expression aggrE = loopE.getOperands().at(0);
const ExpandedType& aggrT = ast->getType(aggrE);
llvm::Value* aggrRaw = context.scope->process(aggrE);
IFwdIteratorIR* aggrItIR = IFwdIteratorIR::create(aggrE, aggrT, context);
llvm::Value* idxBeginRaw = aggrItIR->begin(aggrRaw);
llvm::Value* idxEndRaw = aggrItIR->end(aggrRaw);
ExpandedType loopT = ast->getType(loopE);
std::string elAlias = loopE.bindings[0];
std::string accumAlias = loopE.bindings[1];
const Expression& accumE = loopE.getOperands().at(1);
ExpandedType accumT = ast->getType(accumE, loopT.get());
llvm::Type* accumRawT = llvm->toLLVMType(accumT);
llvm::Value* accumInitRaw = scope->process(accumE, accumAlias, accumT.get());
llvm::BasicBlock *blockProlog = llvm::BasicBlock::Create(llvm->llvmContext, "fold_prlg", function->raw);
llvm::BasicBlock *blockHeader = llvm::BasicBlock::Create(llvm->llvmContext, "fold_hdr", function->raw);
llvm::BasicBlock *blockBody = llvm::BasicBlock::Create(llvm->llvmContext, "fold", function->raw);
llvm::BasicBlock *blockFooter = llvm::BasicBlock::Create(llvm->llvmContext, "fold_ftr", function->raw);
llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "fold_eplg", function->raw);
std::unique_ptr<TransformerSaturation> transformerSaturation(new TransformerSaturation(blockProlog, context.pass->managerTransformations));
//Header:
// * create phi
llvm->irBuilder.SetInsertPoint(blockHeader);
llvm::PHINode *accum = llvm->irBuilder.CreatePHI(accumRawT, 2, accumAlias);
accum->addIncoming(accumInitRaw, blockProlog);
llvm::PHINode *idxCurrentRaw = llvm->irBuilder.CreatePHI(idxBeginRaw->getType(), 2, "foldIt");
idxCurrentRaw->addIncoming(idxBeginRaw, blockProlog);
// * loop checks
Value* condRange = llvm->irBuilder.CreateICmpNE(idxCurrentRaw, idxEndRaw);
llvm->irBuilder.CreateCondBr(condRange, blockBody, blockEpilog);
//Body:
llvm->irBuilder.SetInsertPoint(blockBody);
CodeScope* scopeLoop = loopE.blocks.front();
compilation::IBruteScope* loopUnit = function->getBruteScope(scopeLoop);
Value* elIn = aggrItIR->get(aggrRaw, idxCurrentRaw);
loopUnit->bindArg(accum, move(accumAlias));
loopUnit->bindArg(elIn, move(elAlias));
Value* accumNext = loopUnit->compile();
// * Loop saturation checks
bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockFooter, blockEpilog, context);
llvm::BasicBlock* blockSaturation = llvm->irBuilder.GetInsertBlock();
if (!flagSaturationTriggered){
llvm->irBuilder.CreateBr(blockFooter);
}
//Footer:
// * computing next iteration state
llvm->irBuilder.SetInsertPoint(blockFooter);
Value *itLoopNext = aggrItIR->advance(idxCurrentRaw);
accum->addIncoming(accumNext, llvm->irBuilder.GetInsertBlock());
idxCurrentRaw->addIncoming(itLoopNext, llvm->irBuilder.GetInsertBlock());
llvm->irBuilder.CreateBr(blockHeader);
//Prolog:
llvm->irBuilder.SetInsertPoint(context.scope->lastBlockRaw);
llvm->irBuilder.CreateBr(blockProlog);
llvm->irBuilder.SetInsertPoint(blockProlog);
llvm->irBuilder.CreateBr(blockHeader);
// Epilog:
llvm->irBuilder.SetInsertPoint(blockEpilog);
if (!flagSaturationTriggered){
return accum;
}
llvm::PHINode* result = llvm->irBuilder.CreatePHI(accumRawT, 2, hintAlias);
result->addIncoming(accum, blockHeader);
result->addIncoming(accumNext, blockSaturation);
return result;
}
llvm::Value*
ControlIR::compileFoldInf(const Expression& fold, const std::string& hintRetVar) {
EXPAND_CONTEXT
assert(fold.op == Operator::FOLD_INF);
std::string accumName = fold.bindings[0];
llvm::Value* accumInit = scope->process(fold.getOperands()[0]);
llvm::BasicBlock *blockBeforeLoop = llvm->irBuilder.GetInsertBlock();
llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm->llvmContext, "foldinf", function->raw);
llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm->llvmContext, "foldinf_next", function->raw);
llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm->llvmContext, "foldinf_post", function->raw);
std::unique_ptr<TransformerSaturation> transformerSaturation(new TransformerSaturation(blockBeforeLoop, context.pass->managerTransformations));
llvm->irBuilder.CreateBr(blockLoop);
// * create phi
llvm->irBuilder.SetInsertPoint(blockLoop);
llvm::PHINode *accum = llvm->irBuilder.CreatePHI(accumInit->getType(), 2, accumName);
accum->addIncoming(accumInit, blockBeforeLoop);
// * loop body
CodeScope* scopeLoop = fold.blocks.front();
compilation::IBruteScope* unitLoop = function->getBruteScope(scopeLoop);
unitLoop->bindArg(accum, move(accumName));
Value* accumNext = unitLoop->compile();
// * Loop saturation checks
bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockNext, blockAfterLoop, context);
assert(flagSaturationTriggered);
// * computing next iteration state
llvm->irBuilder.SetInsertPoint(blockNext);
accum->addIncoming(accumNext, llvm->irBuilder.GetInsertBlock());
llvm->irBuilder.CreateBr(blockLoop);
// finalization:
llvm->irBuilder.SetInsertPoint(blockAfterLoop);
return accumNext;
}
llvm::Value*
ControlIR::compileIf(const Expression& exprIf, const std::string& hintRetVar) {
EXPAND_CONTEXT
const Expression& condExpr = exprIf.getOperands()[0];
llvm::IRBuilder<>& builder = llvm->irBuilder;
assert(builder.GetInsertBlock() == scope->lastBlockRaw);
//initialization:
llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "ifAfter", function->raw);
llvm::BasicBlock *blockTrue = llvm::BasicBlock::Create(llvm->llvmContext, "ifTrue", function->raw);
llvm::BasicBlock *blockFalse = llvm::BasicBlock::Create(llvm->llvmContext, "ifFalse", function->raw);
llvm::Value* cond = scope->process(condExpr);
builder.SetInsertPoint(blockTrue);
CodeScope* scopeTrue = exprIf.blocks.front();
llvm::Value* resultTrue = function->getBruteScope(scopeTrue)->compile();
llvm::BasicBlock * blockTrueEnd = builder.GetInsertBlock();
builder.CreateBr(blockEpilog);
builder.SetInsertPoint(blockFalse);
CodeScope* scopeFalse = exprIf.blocks.back();
llvm::Value* resultFalse = function->getBruteScope(scopeFalse)->compile();
llvm::BasicBlock * blockFalseEnd = builder.GetInsertBlock();
builder.CreateBr(blockEpilog);
builder.SetInsertPoint(scope->lastBlockRaw);
llvm->irBuilder.CreateCondBr(cond, blockTrue, blockFalse);
builder.SetInsertPoint(blockEpilog);
- llvm::PHINode *ret = builder.CreatePHI(resultTrue->getType(), 2, NAME("if"));
+ 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, NAME("switch"));
+ 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, NAME("switch"));
+ 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/decorators.h b/cpp/src/compilation/decorators.h
index 4e78236..61b4f65 100644
--- a/cpp/src/compilation/decorators.h
+++ b/cpp/src/compilation/decorators.h
@@ -1,237 +1,254 @@
/* 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"
#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;
+ 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};
+ 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;
+ }
+
+ llvm::Value*
+ compile(const std::string& aliasBlock="") override{
+ if (__rawVars.count(ScopedSymbol::RetSymbol)){
+ return __rawVars[ScopedSymbol::RetSymbol];
}
- void bindArg(llvm::Value* value, const ScopedSymbol& s) {
- __rawVars[s] = value;
- }
+ return Parent::compile(aliasBlock);
+ }
- llvm::Value* compile(const std::string& aliasBlock="") override{
- if (__rawVars.count(ScopedSymbol::RetSymbol)){
- return __rawVars[ScopedSymbol::RetSymbol];
+ 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);
}
-
- return Parent::compile(aliasBlock);
}
- llvm::Value*
- processSymbol(const Symbol& s, std::string hintRetVar) override{
- const CodeScope* scope = s.scope;
- SELF* self = dynamic_cast<SELF*>(Parent::function->getBruteScope(scope));
+ const CodeScope* scope = s.scope;
+ SELF* self = dynamic_cast<SELF*>(Parent::function->getBruteScope(scope));
- if (self->__rawVars.count(s.identifier)){
- return self->__rawVars[s.identifier];
- }
+ 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];
+ //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.
- }
+ } 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();
+ llvm::Value* resultRaw = Parent::processSymbol(s, hintRetVar);
+ self->__rawVars.emplace(s.identifier, resultRaw);
+ return resultRaw;
+ }
- for (auto entry: bindings){
- SELF* self = dynamic_cast<SELF*>(Parent::function->getBruteScope(entry.first.scope));
- assert(self == this);
+ void
+ overrideDeclarations(std::list<std::pair<Symbol, Expression>> bindings){
+ reset();
- self->__declarationsOverriden.emplace(entry.first.identifier, entry.second);
- }
- }
+ for (auto entry: bindings){
+ SELF* self = dynamic_cast<SELF*>(Parent::function->getBruteScope(entry.first.scope));
+ assert(self == this);
- void registerChildScope(std::shared_ptr<IBruteScope> scope){
- __childScopes.push_back(scope);
+ self->__declarationsOverriden.emplace(entry.first.identifier, entry.second);
}
+ }
- void reset(){
- __rawVars.clear();
- __declarationsOverriden.clear();
- __childScopes.clear();
- }
+ 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::list<std::shared_ptr<IBruteScope>> __childScopes;
+ 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;
} //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<
compilation::BasicBruteFunction
> BruteFunctionDefault;
#endif
} //end of xreate
#endif /* SCOPEDECORATORS_H */
diff --git a/cpp/src/compilation/lambdas.cpp b/cpp/src/compilation/lambdas.cpp
index b82f971..0bed041 100644
--- a/cpp/src/compilation/lambdas.cpp
+++ b/cpp/src/compilation/lambdas.cpp
@@ -1,65 +1,71 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: lambdas.cpp
* Author: pgess <v.melnychenko@xreate.org>
*
* Created in April, 2020
*/
#include "compilation/lambdas.h"
#include "llvmlayer.h"
#include "compilation/resources.h"
using namespace xreate::compilation;
using namespace std;
unsigned LambdaBruteFn::__counter = 0;
std::string
LambdaBruteFn::prepareName(){
return string(LAMBDA_PREFIX) + "_" + __hintAlias + "_" + to_string(__counter++);
}
std::vector<llvm::Type*>
LambdaBruteFn::prepareSignature(){
return getScopeSignature(IBruteFunction::__entry);
}
llvm::Type*
LambdaBruteFn::prepareResult(){
LLVMLayer* llvm = IBruteFunction::pass->man->llvm;
AST* ast = IBruteFunction::pass->man->root;
return llvm->toLLVMType(ast->getType(__entry->getBody()));
}
llvm::Function::arg_iterator
LambdaBruteFn::prepareBindings(){
- CodeScope* entry = IBruteFunction::__entry;
- IBruteScope* entryCompilation = IBruteFunction::getBruteScope(entry);
+ CodeScope* entrySc = IBruteFunction::__entry;
+ IBruteScope* entryBruteSc = IBruteFunction::getBruteScope(entrySc);
llvm::Function::arg_iterator fargsI = IBruteFunction::raw->arg_begin();
- for (std::string &arg : entry->__bindings) {
- ScopedSymbol argid{entry->__identifiers[arg], versions::VERSION_NONE};
+ for (std::string &arg : entrySc->__bindings) {
+ ScopedSymbol argid{entrySc->__identifiers[arg], versions::VERSION_NONE};
- entryCompilation->bindArg(&*fargsI, argid);
+ entryBruteSc->bindArg(&*fargsI, argid);
fargsI->setName(arg);
++fargsI;
}
+ for (Symbol symbExtern: entrySc->boundExternalSymbs){
+ entryBruteSc->bindExternalSymb(&*fargsI, symbExtern);
+ //fargsI->setName(arg);
+ ++fargsI;
+ }
+
return fargsI;
}
void
LambdaBruteFn::applyAttributes(){
raw->addFnAttr(llvm::Attribute::AlwaysInline);
}
llvm::Function*
LambdaIR::compile(CodeScope* body, const std::string& hintAlias){
LambdaBruteFn fnLambda(body, __pass, hintAlias);
return fnLambda.compile();
}
diff --git a/cpp/src/compilation/lambdas.h b/cpp/src/compilation/lambdas.h
index 900b151..2f3f355 100644
--- a/cpp/src/compilation/lambdas.h
+++ b/cpp/src/compilation/lambdas.h
@@ -1,52 +1,55 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: lambdas.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created in April, 2020
*/
#ifndef XREATE_LAMBDAS_H
#define XREATE_LAMBDAS_H
#include "pass/compilepass.h"
namespace llvm {
class Function;
}
namespace xreate { namespace compilation {
class LambdaBruteFn: public IBruteFunction {
public:
LambdaBruteFn(CodeScope* entry, CompilePass* p, const std::string& hintAlias)
- : IBruteFunction(entry, p), __hintAlias(hintAlias) {}
+ : IBruteFunction(entry, p), __hintAlias(hintAlias) {
+ IBruteFunction::isLambda = true;
+ }
-protected:
virtual std::string prepareName() override;
+
+protected:
virtual std::vector<llvm::Type*> prepareSignature() override;
virtual llvm::Function::arg_iterator prepareBindings() override;
virtual llvm::Type* prepareResult() override;
virtual void applyAttributes() override;
private:
std::string __hintAlias;
static unsigned __counter;
};
class LambdaIR{
public:
LambdaIR(CompilePass* p): __pass(p){}
llvm::Function* compile(CodeScope* body, const std::string& hintAlias);
private:
compilation::Context __context;
CompilePass* __pass;
};
}}
#endif //XREATE_LAMBDAS_H
diff --git a/cpp/src/compilation/targetinterpretation.cpp b/cpp/src/compilation/targetinterpretation.cpp
index 45605dd..d6f93b9 100644
--- a/cpp/src/compilation/targetinterpretation.cpp
+++ b/cpp/src/compilation/targetinterpretation.cpp
@@ -1,646 +1,646 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: targetinterpretation.cpp
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on June 29, 2016, 6:45 PM
*/
/**
* \file targetinterpretation.h
* \brief Interpretation support. See more details on [Interpretation](/d/concepts/interpretation/)
*/
#include "compilation/targetinterpretation.h"
#include "pass/interpretationpass.h"
#include "analysis/typeinference.h"
#include "llvmlayer.h"
#include "compilation/decorators.h"
#include "compilation/i12ninst.h"
#include "compilation/intrinsics.h"
#include <boost/scoped_ptr.hpp>
#include <iostream>
#include <csignal>
using namespace std;
using namespace xreate::compilation;
namespace xreate{
namespace interpretation{
const Expression EXPRESSION_FALSE = Expression(Atom<Number_t>(0));
const Expression EXPRESSION_TRUE = Expression(Atom<Number_t>(1));
CodeScope*
InterpretationScope::processOperatorIf(const Expression& expression) {
const Expression& exprCondition = process(expression.getOperands()[0]);
if (exprCondition == EXPRESSION_TRUE) {
return expression.blocks.front();
}
return expression.blocks.back();
}
CodeScope*
InterpretationScope::processOperatorSwitch(const Expression& expression) {
const Expression& exprCondition = process(expression.operands[0]);
bool flagHasDefault = expression.operands[1].op == Operator::CASE_DEFAULT;
//TODO check that one and only one case variant is appropriate
for (size_t size = expression.operands.size(), i = flagHasDefault ? 2 : 1; i < size; ++i) {
const Expression& exprCase = process(expression.operands[i]);
if (function->getScope((const CodeScope*) exprCase.blocks.front())->processScope() == exprCondition) {
return exprCase.blocks.back();
}
}
if (flagHasDefault) {
const Expression& exprCaseDefault = expression.operands[1];
return exprCaseDefault.blocks.front();
}
assert(false && "Switch has no appropriate variant");
return nullptr;
}
CodeScope*
InterpretationScope::processOperatorSwitchVariant(const Expression& expression) {
const ExpandedType& conditionT = function->__pass->man->root->getType(expression.operands.at(0));
const Expression& conditionE = process(expression.operands.at(0));
assert(conditionE.op == Operator::VARIANT);
const string& aliasS = expression.bindings.front();
unsigned caseExpectedId = (int) conditionE.getValueDouble();
auto itFoundValue = std::find_if(++expression.operands.begin(), expression.operands.end(), [caseExpectedId](const auto& caseActualE){
return (unsigned) caseActualE.getValueDouble() == caseExpectedId;
});
assert(itFoundValue != expression.operands.end());
int caseScopeId = itFoundValue - expression.operands.begin() - 1;
auto caseScopeRef = expression.blocks.begin();
std::advance(caseScopeRef, caseScopeId);
InterpretationScope* scopeI12n = function->getScope(*caseScopeRef);
if(conditionE.operands.size()) {
Expression valueE(Operator::LIST, {});
valueE.operands = conditionE.operands;
valueE.bindings = conditionT->__operands.at(caseExpectedId).fields;
scopeI12n->overrideBindings({
{valueE, aliasS}
});
};
return *caseScopeRef;
}
llvm::Value*
InterpretationScope::processLate(const InterpretationOperator& op, const Expression& expression, const Context& context, const std::string& hintAlias) {
switch(op) {
case IF_INTERPRET_CONDITION:
{
CodeScope* scopeResult = processOperatorIf(expression);
llvm::Value* result = context.function->getBruteScope(scopeResult)->compile();
return result;
}
case SWITCH_INTERPRET_CONDITION:
{
CodeScope* scopeResult = processOperatorSwitch(expression);
llvm::Value* result = context.function->getBruteScope(scopeResult)->compile();
return result;
}
case SWITCH_VARIANT:
{
CodeScope* scopeResult = processOperatorSwitchVariant(expression);
const Expression& condCrudeE = expression.operands.at(0);
const Expression& condE = process(condCrudeE);
const string identCondition = expression.bindings.front();
auto scopeCompilation = Decorators<CachedScopeDecoratorTag>::getInterface(
context.function->getBruteScope(scopeResult));
if(condE.operands.size()) {
//override value
Symbol symbCondition{ScopedSymbol{scopeResult->__identifiers.at(identCondition), versions::VERSION_NONE}, scopeResult};
scopeCompilation->overrideDeclarations({
{symbCondition, Expression(condE.operands.at(0))}}
);
//set correct type for binding:
const ExpandedType& typeVariant = function->__pass->man->root->getType(condCrudeE);
int conditionIndex = condE.getValueDouble();
- ScopedSymbol symbolInternal = scopeResult->getSymbol(identCondition);
+ ScopedSymbol symbolInternal = scopeResult->findSymbolByAlias(identCondition);
scopeResult->__declarations[symbolInternal].bindType(typeVariant->__operands.at(conditionIndex));
}
llvm::Value* result = context.function->getBruteScope(scopeResult)->compile();
return result;
}
case SWITCH_LATE:
{
return nullptr;
// latereasoning::LateReasoningCompiler compiler(dynamic_cast<InterpretationFunction*>(this->function), context);
// return compiler.processSwitchLateStatement(expression, "");
}
case FOLD_INTERPRET_INPUT:
{
//initialization
const Expression& containerE = process(expression.getOperands().at(0));
const TypeAnnotation& accumT = expression.type;
assert(containerE.op == Operator::LIST);
CodeScope* bodyScope = expression.blocks.front();
const string& elAlias = expression.bindings[0];
Symbol elS{ScopedSymbol{bodyScope->__identifiers.at(elAlias), versions::VERSION_NONE}, bodyScope};
const std::string& accumAlias = expression.bindings[1];
llvm::Value* accumRaw = context.scope->process(expression.getOperands().at(1), accumAlias, accumT);
InterpretationScope* bodyI12n = function->getScope(bodyScope);
auto bodyBrute = Decorators<CachedScopeDecoratorTag>::getInterface(context.function->getBruteScope(bodyScope));
const std::vector<Expression>& containerVec = containerE.getOperands();
for(size_t i = 0; i < containerVec.size(); ++i) {
const Expression& elE = containerVec[i];
bodyI12n->overrideBindings({
{elE, elAlias}
});
bodyBrute->overrideDeclarations({
{elS, elE}
}); //resets bodyBrute
bodyBrute->bindArg(accumRaw, string(accumAlias));
accumRaw = bodyBrute->compile();
}
return accumRaw;
}
// case FOLD_INF_INTERPRET_INOUT:
// {
// }
//TODO refactor as InterpretationCallStatement class
case CALL_INTERPRET_PARTIAL:
{
const std::string &calleeName = expression.getValueString();
IBruteScope* scopeUnitSelf = context.scope;
ManagedFnPtr callee = this->function->__pass->man->root->findFunction(calleeName);
const I12nFunctionSpec& calleeData = FunctionInterpretationHelper::getSignature(callee);
std::vector<llvm::Value *> argsActual;
PIFnSignature sig;
sig.declaration = callee;
for(size_t no = 0, size = expression.operands.size(); no < size; ++no) {
const Expression& op = expression.operands[no];
if (calleeData.signature.at(no) == INTR_ONLY) {
sig.bindings.push_back(process(op));
continue;
}
argsActual.push_back(scopeUnitSelf->process(op));
}
TargetInterpretation* man = dynamic_cast<TargetInterpretation*> (this->function->__pass);
PIFunction* pifunction = man->getFunction(move(sig));
llvm::Function* raw = pifunction->compile();
boost::scoped_ptr<BruteFnInvocation> statement(new BruteFnInvocation(raw, man->pass->man->llvm));
return (*statement)(move(argsActual));
}
case QUERY_LATE:
{
return nullptr;
// return IntrinsicQueryInstruction(
// dynamic_cast<InterpretationFunction*>(this->function))
// .processLate(expression, context);
}
default: break;
}
assert(false && "Unknown late interpretation operator");
return nullptr;
}
llvm::Value*
InterpretationScope::compile(const Expression& expression, const Context& context, const std::string& hintAlias) {
const InterpretationData& data = Attachments::get<InterpretationData>(expression);
if (data.op != InterpretationOperator::NONE) {
return processLate(data.op, expression, context, hintAlias);
}
Expression result = process(expression);
return context.scope->process(result, hintAlias);
}
Expression
InterpretationScope::process(const Expression& expression) {
#ifndef NDEBUG
if (expression.tags.count("bpoint")) {
std::raise(SIGINT);
}
#endif
PassManager* man = function->__pass->man;
switch (expression.__state) {
case Expression::INVALID:
assert(false);
case Expression::NUMBER:
case Expression::STRING:
return expression;
case Expression::IDENT:
{
Symbol s = Attachments::get<IdentifierSymbol>(expression);
return Parent::processSymbol(s);
}
case Expression::COMPOUND:
break;
default: assert(false);
}
switch (expression.op) {
case Operator::EQU:
{
const Expression& left = process(expression.operands[0]);
const Expression& right = process(expression.operands[1]);
if (left == right) return EXPRESSION_TRUE;
return EXPRESSION_FALSE;
}
case Operator::NE:
{
const Expression& left = process(expression.operands[0]);
const Expression& right = process(expression.operands[1]);
if (left == right) return EXPRESSION_FALSE;
return EXPRESSION_TRUE;
}
case Operator::LOGIC_AND:
{
assert(expression.operands.size() == 1);
return process (expression.operands[0]);
}
// case Operator::LOGIC_OR:
case Operator::CALL:
{
const std::string &fnName = expression.getValueString();
ManagedFnPtr fnAst = man->root->findFunction(fnName);
InterpretationFunction* fnUnit = this->function->__pass->getFunction(fnAst);
vector<Expression> args;
args.reserve(expression.getOperands().size());
for(size_t i = 0, size = expression.getOperands().size(); i < size; ++i) {
args.push_back(process(expression.getOperands()[i]));
}
return fnUnit->process(args);
}
case Operator::CALL_INTRINSIC:
{
const Expression& opCallIntrCrude = expression;
vector<Expression> argsActual;
argsActual.reserve(opCallIntrCrude.getOperands().size());
for(const auto& op: opCallIntrCrude.getOperands()) {
argsActual.push_back(process(op));
}
Expression opCallIntr(Operator::CALL_INTRINSIC, {});
opCallIntr.setValueDouble(opCallIntrCrude.getValueDouble());
opCallIntr.operands = argsActual;
compilation::IntrinsicCompiler compiler(man);
return compiler.interpret(opCallIntr);
}
case Operator::QUERY:
{
return Expression();
// return IntrinsicQueryInstruction(dynamic_cast<InterpretationFunction*>(this->function))
// .process(expression);
}
case Operator::QUERY_LATE:
{
assert(false && "Can't be interpretated");
return Expression();
}
case Operator::IF:
{
CodeScope* scopeResult = processOperatorIf(expression);
return function->getScope(scopeResult)->processScope();
}
case Operator::SWITCH:
{
CodeScope* scopeResult = processOperatorSwitch(expression);
return function->getScope(scopeResult)->processScope();
}
case Operator::SWITCH_VARIANT:
{
CodeScope* scopeResult = processOperatorSwitchVariant(expression);
return function->getScope(scopeResult)->processScope();
}
case Operator::VARIANT:
{
Expression result{Operator::VARIANT, {}};
result.setValueDouble(expression.getValueDouble());
for(const Expression& op: expression.operands){
result.operands.push_back(process(op));
}
return result;
}
case Operator::INDEX:
{
Expression aggrE = process(expression.operands[0]);
for (size_t keyId = 1; keyId < expression.operands.size(); ++keyId) {
const Expression& keyE = process(expression.operands[keyId]);
if (keyE.__state == Expression::STRING) {
const string& fieldExpectedS = keyE.getValueString();
unsigned fieldId;
for(fieldId = 0; fieldId < aggrE.bindings.size(); ++fieldId){
if (aggrE.bindings.at(fieldId) == fieldExpectedS){break;}
}
assert(fieldId < aggrE.bindings.size());
aggrE = Expression(aggrE.operands.at(fieldId));
continue;
}
if (keyE.__state == Expression::NUMBER) {
int opId = keyE.getValueDouble();
aggrE = Expression(aggrE.operands.at(opId));
continue;
}
assert(false && "Inappropriate key");
}
return aggrE;
}
case Operator::FOLD:
{
const Expression& exprInput = process(expression.getOperands()[0]);
const Expression& exprInit = process(expression.getOperands()[1]);
const std::string& argEl = expression.bindings[0];
const std::string& argAccum = expression.bindings[1];
InterpretationScope* body = function->getScope(expression.blocks.front());
Expression accum = exprInit;
for(size_t size = exprInput.getOperands().size(), i = 0; i < size; ++i) {
body->overrideBindings({
{exprInput.getOperands()[i], argEl},
{accum, argAccum}
});
accum = body->processScope();
}
return accum;
}
case Operator::LIST:
case Operator::LIST_RANGE:
{
Expression result(expression.op,{});
result.operands.resize(expression.operands.size());
result.bindings = expression.bindings;
int keyId = 0;
for(const Expression& opCurrent : expression.operands) {
result.operands[keyId++] = process(opCurrent);
}
return result;
}
// case Operator::MAP: {
// break;
// }
default: break;
}
return expression;
}
InterpretationFunction*
TargetInterpretation::getFunction(IBruteFunction* unit) {
if (__dictFunctionsByUnit.count(unit)) {
return __dictFunctionsByUnit.at(unit);
}
InterpretationFunction* f = new InterpretationFunction(unit->getASTFn(), this);
__dictFunctionsByUnit.emplace(unit, f);
assert(__functions.emplace(unit->getASTFn().id(), f).second);
return f;
}
PIFunction*
TargetInterpretation::getFunction(PIFnSignature&& sig) {
auto f = __pifunctions.find(sig);
if (f != __pifunctions.end()) {
return f->second;
}
PIFunction* result = new PIFunction(PIFnSignature(sig), __pifunctions.size(), this);
__pifunctions.emplace(move(sig), result);
assert(__dictFunctionsByUnit.emplace(result->fnRaw, result).second);
return result;
}
InterpretationScope*
TargetInterpretation::transformContext(const Context& c) {
return this->getFunction(c.function)->getScope(c.scope->scope);
}
llvm::Value*
TargetInterpretation::compile(const Expression& expression, const Context& ctx, const std::string& hintAlias) {
return transformContext(ctx)->compile(expression, ctx, hintAlias);
}
InterpretationFunction::InterpretationFunction(const ManagedFnPtr& function, Target<TargetInterpretation>* target)
: Function<TargetInterpretation>(function, target) { }
Expression
InterpretationFunction::process(const std::vector<Expression>& args) {
InterpretationScope* body = getScope(__function->__entry);
list<pair<Expression, string>> bindings;
for(size_t i = 0, size = args.size(); i < size; ++i) {
bindings.push_back(make_pair(args.at(i), body->scope->__bindings.at(i)));
}
body->overrideBindings(bindings);
return body->processScope();
}
// Partial function interpretation
typedef BasicBruteFunction BruteFunction;
class PIBruteFunction : public BruteFunction{
public:
PIBruteFunction(ManagedFnPtr f, std::set<size_t>&& arguments, size_t id, CompilePass* p)
: BruteFunction(f, p), argumentsActual(move(arguments)), __id(id) { }
+ virtual std::string
+ prepareName() override {
+ return BruteFunction::prepareName() + "_" + std::to_string(__id);
+ }
+
protected:
std::vector<llvm::Type*>
prepareSignature() override {
LLVMLayer* llvm = BruteFunction::pass->man->llvm;
AST* ast = BruteFunction::pass->man->root;
CodeScope* entry = IBruteFunction::__entry;
std::vector<llvm::Type*> signature;
for(size_t no : argumentsActual) {
VNameId argId = entry->__identifiers.at(entry->__bindings.at(no));
ScopedSymbol arg{argId, versions::VERSION_NONE};
signature.push_back(llvm->toLLVMType(ast->expandType(entry->__declarations.at(arg).type)));
}
return signature;
}
llvm::Function::arg_iterator
prepareBindings() override{
CodeScope* entry = IBruteFunction::__entry;
IBruteScope* entryCompilation = BruteFunction::getBruteScope(entry);
llvm::Function::arg_iterator fargsI = BruteFunction::raw->arg_begin();
for(size_t no : argumentsActual) {
ScopedSymbol arg{entry->__identifiers.at(entry->__bindings.at(no)), versions::VERSION_NONE};
entryCompilation->bindArg(&*fargsI, arg);
fargsI->setName(entry->__bindings.at(no));
++fargsI;
}
return fargsI;
}
- virtual std::string
- prepareName() override {
- return BruteFunction::prepareName() + "_" + std::to_string(__id);
- }
-
private:
std::set<size_t> argumentsActual;
size_t __id;
} ;
PIFunction::PIFunction(PIFnSignature&& sig, size_t id, TargetInterpretation* target)
: InterpretationFunction(sig.declaration, target), instance(move(sig)) {
const I12nFunctionSpec& functionData = FunctionInterpretationHelper::getSignature(instance.declaration);
std::set<size_t> argumentsActual;
for (size_t no = 0, size = functionData.signature.size(); no < size; ++no) {
if (functionData.signature.at(no) != INTR_ONLY) {
argumentsActual.insert(no);
}
}
fnRaw = new PIBruteFunction(instance.declaration, move(argumentsActual), id, target->pass);
CodeScope* entry = instance.declaration->__entry;
auto entryUnit = Decorators<CachedScopeDecoratorTag>::getInterface<>(fnRaw->getEntry());
InterpretationScope* entryIntrp = InterpretationFunction::getScope(entry);
list<pair<Expression, std::string>> bindingsPartial;
list<pair<Symbol, Expression>> declsPartial;
for(size_t no = 0, sigNo = 0, size = entry->__bindings.size(); no < size; ++no) {
if(functionData.signature.at(no) == INTR_ONLY) {
bindingsPartial.push_back({instance.bindings[sigNo], entry->__bindings[no]});
VNameId argId = entry->__identifiers.at(entry->__bindings[no]);
Symbol argSymbol{ScopedSymbol
{argId, versions::VERSION_NONE}, entry};
declsPartial.push_back({argSymbol, instance.bindings[sigNo]});
++sigNo;
}
}
entryIntrp->overrideBindings(bindingsPartial);
entryUnit->overrideDeclarations(declsPartial);
}
llvm::Function*
PIFunction::compile() {
llvm::Function* raw = fnRaw->compile();
return raw;
}
bool operator<(const PIFnSignature& lhs, const PIFnSignature& rhs) {
if (lhs.declaration.id() != rhs.declaration.id()) {
return lhs.declaration.id() < rhs.declaration.id();
}
return lhs.bindings < rhs.bindings;
}
bool operator<(const PIFnSignature& lhs, PIFunction * const rhs) {
return lhs < rhs->instance;
}
bool operator<(PIFunction * const lhs, const PIFnSignature& rhs) {
return lhs->instance < rhs;
}
}
}
/** \class xreate::interpretation::InterpretationFunction
*
* Holds list of xreate::interpretation::InterpretationScope 's focused on interpretation of individual code scopes
*
* There is particulat subclass PIFunction intended to represent partially interpreted functions.
*\sa TargetInterpretation, [Interpretation Concept](/d/concepts/interpretation/)
*/
/** \class xreate::interpretation::TargetInterpretation
*
* TargetInterpretation is executed during compilation and is intended to preprocess eligible for interpretation parts of a source code.
*
* Keeps a list of InterpretationFunction / PIFunction that represent interpretation for an individual functions.
*
* There is \ref InterpretationScopeDecorator that embeds interpretation to an overall compilation process.
* \sa InterpretationPass, compilation::Target, [Interpretation Concept](/d/concepts/interpretation/)
*
*/
diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp
index 4eb8b7f..cdd9647 100644
--- a/cpp/src/pass/compilepass.cpp
+++ b/cpp/src/pass/compilepass.cpp
@@ -1,895 +1,908 @@
/* 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 "analysis/resources.h"
#ifdef XREATE_ENABLE_EXTERN
#include "ExternLayer.h"
#endif
#include "compilation/containers.h"
#include "compilation/containers/arrays.h"
#ifndef XREATE_CONFIG_MIN
#include "query/containers.h"
#include "pass/versionspass.h"
#include "compilation/targetinterpretation.h"
#endif
#include <boost/optional.hpp>
#include <memory>
using namespace std;
using namespace llvm;
using namespace xreate::typehints;
using namespace xreate::containers;
namespace xreate{
namespace compilation{
#define DEFAULT(x) (hintAlias.empty()? x: hintAlias)
std::string
BasicBruteFunction::prepareName() {
AST* ast = IBruteFunction::pass->man->root;
string name = ast->getFnSpecializations(__function->__name).size() > 1 ?
__function->__name + std::to_string(__function.id()) :
__function->__name;
return name;
}
std::vector<llvm::Type*>
BasicBruteFunction::prepareSignature() {
CodeScope* entry = __function->__entry;
return getScopeSignature(entry);
}
llvm::Type*
BasicBruteFunction::prepareResult() {
LLVMLayer* llvm = IBruteFunction::pass->man->llvm;
AST* ast = IBruteFunction::pass->man->root;
CodeScope* entry = __function->__entry;
return llvm->toLLVMType(ast->expandType(entry->__declarations.at(ScopedSymbol::RetSymbol).type));
}
llvm::Function::arg_iterator
BasicBruteFunction::prepareBindings() {
CodeScope* entry = __function->__entry;
IBruteScope* entryCompilation = IBruteFunction::getBruteScope(entry);
llvm::Function::arg_iterator fargsI = IBruteFunction::raw->arg_begin();
for (std::string &arg : entry->__bindings) {
ScopedSymbol argid{entry->__identifiers[arg], versions::VERSION_NONE};
entryCompilation->bindArg(&*fargsI, argid);
fargsI->setName(arg);
++fargsI;
}
return fargsI;
}
void
BasicBruteFunction::applyAttributes(){}
IBruteScope::IBruteScope(const CodeScope * const codeScope, IBruteFunction* f, CompilePass* compilePass)
: pass(compilePass), function(f), scope(codeScope), lastBlockRaw(nullptr) { }
llvm::Value*
BruteFnInvocation::operator()(std::vector<llvm::Value *>&& args, const std::string& hintDecl) {
if (__calleeTy) {
auto argsFormalT = __calleeTy->params();
size_t sizeArgsF = __calleeTy->getNumParams();
assert(args.size() >= sizeArgsF);
assert(__calleeTy->isVarArg() || args.size() == sizeArgsF);
auto argFormalT = argsFormalT.begin();
for(size_t argId = 0; argId < args.size(); ++argId){
if(argFormalT != argsFormalT.end()){
args[argId] = typeinference::doAutomaticTypeConversion(
args.at(argId), *argFormalT, llvm->irBuilder);
++argFormalT;
}
}
}
//Do not name function call that returns Void.
std::string hintName = (!__calleeTy->getReturnType()->isVoidTy()) ? hintDecl : "";
return llvm->irBuilder.CreateCall(__calleeTy, __callee, args, hintName);
}
llvm::Value*
HiddenArgsFnInvocation::operator() (std::vector<llvm::Value *>&& args, const std::string& hintDecl) {
args.insert(args.end(), __args.begin(), __args.end());
return __parent->operator ()(std::move(args), hintDecl);
}
class CallStatementInline : public IFnInvocation{
public:
CallStatementInline(IBruteFunction* caller, IBruteFunction* callee, LLVMLayer* l)
: __caller(caller), __callee(callee), llvm(l) { }
llvm::Value* operator()(std::vector<llvm::Value *>&& args, const std::string& hintDecl) {
return nullptr;
}
private:
IBruteFunction* __caller;
IBruteFunction* __callee;
LLVMLayer* llvm;
bool
isInline() {
// Symbol ret = Symbol{0, function->__entry};
// bool flagOnTheFly = SymbolAttachments::get<IsImplementationOnTheFly>(ret, false);
//TODO consider inlining
return false;
}
} ;
BasicBruteScope::BasicBruteScope(const CodeScope * const codeScope, IBruteFunction* f, CompilePass* compilePass)
: IBruteScope(codeScope, f, compilePass) { }
llvm::Value*
BasicBruteScope::processSymbol(const Symbol& s, std::string hintRetVar) {
Expression declaration = CodeScope::getDefinition(s);
const CodeScope* scopeExternal = s.scope;
IBruteScope* scopeBruteExternal = IBruteScope::function->getBruteScope(scopeExternal);
assert(scopeBruteExternal->lastBlockRaw);
llvm::Value* resultRaw;
llvm::BasicBlock* blockOwn = pass->man->llvm->irBuilder.GetInsertBlock();
if (scopeBruteExternal->lastBlockRaw == blockOwn) {
resultRaw = scopeBruteExternal->process(declaration, hintRetVar);
scopeBruteExternal->lastBlockRaw = lastBlockRaw =
pass->man->llvm->irBuilder.GetInsertBlock();
} else {
pass->man->llvm->irBuilder.SetInsertPoint(scopeBruteExternal->lastBlockRaw);
resultRaw = scopeBruteExternal->processSymbol(s, hintRetVar);
pass->man->llvm->irBuilder.SetInsertPoint(blockOwn);
}
return resultRaw;
}
IFnInvocation*
BasicBruteScope::findFunction(const Expression& opCall) {
const std::string& calleeName = opCall.getValueString();
LLVMLayer* llvm = pass->man->llvm;
const std::list<ManagedFnPtr>& specializations = pass->man->root->getFnSpecializations(calleeName);
#ifdef XREATE_ENABLE_EXTERN
//if no specializations registered - check external function
if (specializations.size() == 0) {
llvm::Function* external = llvm->layerExtern->lookupFunction(calleeName);
llvm::outs() << "Debug/External function: " << calleeName;
external->getType()->print(llvm::outs(), true);
llvm::outs() << "\n";
return new BruteFnInvocation(external, llvm);
}
#endif
//There should be only one specialization without any valid guards at this point
return new BruteFnInvocation(pass->getBruteFn(
pass->man->root->findFunction(calleeName))->compile(),
llvm);
}
//DISABLEDFEATURE transformations
// if (pass->transformations->isAcceptable(expr)){
// return pass->transformations->transform(expr, result, ctx);
// }
llvm::Value*
BasicBruteScope::process(const Expression& expr, const std::string& hintAlias, const TypeAnnotation& expectedT) {
llvm::Value *leftRaw;
llvm::Value *rightRaw;
LLVMLayer& l = *pass->man->llvm;
Context ctx{this, function, pass};
xreate::compilation::ControlIR controlIR = xreate::compilation::ControlIR({this, function, pass});
switch (expr.op) {
case Operator::ADD:
case Operator::SUB: case Operator::MUL: case Operator::MOD:
case Operator::DIV: case Operator::EQU: case Operator::LSS:
case Operator::GTR: case Operator::NE: case Operator::LSE:
case Operator::GTE:
assert(expr.__state == Expression::COMPOUND);
assert(expr.operands.size() == 2);
leftRaw = process(expr.operands.at(0));
rightRaw = process(expr.operands.at(1));
break;
default:;
}
switch (expr.op) {
case Operator::AND:
{
assert(expr.operands.size());
llvm::Value* resultRaw = process(expr.operands.at(0));
if (expr.operands.size() == 1) return resultRaw;
for(size_t i=1; i< expr.operands.size()-1; ++i){
resultRaw = l.irBuilder.CreateAnd(resultRaw, process(expr.operands.at(i)));
}
return l.irBuilder.CreateAnd(resultRaw, process(expr.operands.at(expr.operands.size()-1)), hintAlias);
}
case Operator::OR:
{
assert(expr.operands.size());
llvm::Value* resultRaw = process(expr.operands.at(0));
if (expr.operands.size() == 1) return resultRaw;
for(size_t i=1; i< expr.operands.size()-1; ++i){
resultRaw = l.irBuilder.CreateOr(resultRaw, process(expr.operands.at(i)));
}
return l.irBuilder.CreateOr(resultRaw, process(expr.operands.at(expr.operands.size()-1)), hintAlias);
}
case Operator::ADD:
{
- return l.irBuilder.CreateAdd(leftRaw, rightRaw, DEFAULT("addv"));
+ return l.irBuilder.CreateAdd(leftRaw, rightRaw, hintAlias);
}
case Operator::SUB:
- return l.irBuilder.CreateSub(leftRaw, rightRaw, DEFAULT("tmp_sub"));
+ return l.irBuilder.CreateSub(leftRaw, rightRaw, hintAlias);
break;
case Operator::MUL:
- return l.irBuilder.CreateMul(leftRaw, rightRaw, DEFAULT("tmp_mul"));
+ return l.irBuilder.CreateMul(leftRaw, rightRaw, hintAlias);
break;
case Operator::DIV:
- if (leftRaw->getType()->isIntegerTy()) return l.irBuilder.CreateSDiv(leftRaw, rightRaw, DEFAULT("tmp_div"));
- if (leftRaw->getType()->isFloatingPointTy()) return l.irBuilder.CreateFDiv(leftRaw, rightRaw, DEFAULT("tmp_div"));
+ 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, DEFAULT("tmp_equ"));
- if (leftRaw->getType()->isFloatingPointTy()) return l.irBuilder.CreateFCmpOEQ(leftRaw, rightRaw, DEFAULT("tmp_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, DEFAULT("tmp_equ"));
+ return l.irBuilder.CreateICmpEQ(leftUnwapped, rightUnwapped, hintAlias);
}
break;
}
case Operator::NE:
- return l.irBuilder.CreateICmpNE(leftRaw, rightRaw, DEFAULT("tmp_ne"));
+ return l.irBuilder.CreateICmpNE(leftRaw, rightRaw, hintAlias);
break;
case Operator::LSS:
- return l.irBuilder.CreateICmpSLT(leftRaw, rightRaw, DEFAULT("tmp_lss"));
+ return l.irBuilder.CreateICmpSLT(leftRaw, rightRaw, hintAlias);
break;
case Operator::LSE:
- return l.irBuilder.CreateICmpSLE(leftRaw, rightRaw, DEFAULT("tmp_lse"));
+ return l.irBuilder.CreateICmpSLE(leftRaw, rightRaw, hintAlias);
break;
case Operator::GTR:
- return l.irBuilder.CreateICmpSGT(leftRaw, rightRaw, DEFAULT("tmp_gtr"));
+ return l.irBuilder.CreateICmpSGT(leftRaw, rightRaw, hintAlias);
break;
case Operator::GTE:
- return l.irBuilder.CreateICmpSGE(leftRaw, rightRaw, DEFAULT("tmp_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), DEFAULT("res_" + nameCallee));
+ return (*callee)(move(args), hintAlias);
}
case Operator::IF:
{
- return controlIR.compileIf(expr, DEFAULT("tmp_if"));
+ return controlIR.compileIf(expr, hintAlias);
}
case Operator::SWITCH:
{
- return controlIR.compileSwitch(expr, DEFAULT("tmp_switch"));
+ return controlIR.compileSwitch(expr, hintAlias);
}
case Operator::LOGIC_AND:
{
assert(expr.operands.size() == 1);
return process(expr.operands[0]);
}
case Operator::LIST: //init record or array
{
ExpandedType exprT = l.ast->getType(expr, expectedT);
TypesHelper helper(pass->man->llvm);
enum {RECORD, ARRAY} kind;
if (helper.isArrayT(exprT)){
kind = ARRAY;
} else if (helper.isRecordT(exprT)){
kind = RECORD;
} else {
assert(false && "Inapproriate type");
}
#ifdef XREATE_ENABLE_EXTERN
if (exprT->__operator == TypeOperator::ALIAS){
if (l.layerExtern->isArrayType(exprT->__valueCustom)){
flagIsArray = true;
break;
}
if (l.layerExtern->isRecordType(exprT->__valueCustom)){
flagIsArray = false;
break;
}
assert(false && "Inapproriate external type");
}
#endif
switch(kind){
case RECORD:{
const std::vector<string> fieldsFormal = helper.getRecordFields(exprT);
containers::RecordIR irRecords(ctx);
llvm::StructType *recordTRaw = llvm::cast<llvm::StructType>(l.toLLVMType(exprT));
llvm::Value *resultRaw = irRecords.init(recordTRaw);
return irRecords.update(resultRaw, exprT, expr);
}
case ARRAY: {
std::unique_ptr<containers::IContainersIR> containerIR(
containers::IContainersIR::create(expr, expectedT, ctx));
llvm::Value* aggrRaw = containerIR->init(hintAlias);
return containerIR->update(aggrRaw, expr, hintAlias);
}
}
break;
};
case Operator::LIST_RANGE:
{
containers::RangeIR compiler(ctx);
const ExpandedType& aggrT = pass->man->root->getType(expr);
return compiler.init(expr, aggrT, hintAlias);
};
case Operator::MAP:
{
assert(expr.blocks.size());
containers::ImplementationType implType = containers::IContainersIR::getImplementation(expr, pass->man->root);
switch(implType){
case containers::ImplementationType::SOLID: {
ExpandedType exprT = pass->man->root->getType(expr, expectedT);
ArrayHint hint = find(expr, ArrayHint{});
containers::ArrayIR compiler(exprT, hint, ctx);
- return compiler.operatorMap(expr, DEFAULT("map"));
+ 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, DEFAULT("map"));
+ 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, DEFAULT("fold"));
+ return controlIR.compileFold(expr, hintAlias);
};
case Operator::FOLD_INF:
{
- return controlIR.compileFoldInf(expr, DEFAULT("fold"));
+ return controlIR.compileFoldInf(expr, hintAlias);
};
case Operator::INDEX:
{
assert(expr.operands.size() > 1);
const Expression& aggrE = expr.operands[0];
const ExpandedType& aggrT = pass->man->root->getType(aggrE);
llvm::Value* aggrRaw = process(aggrE);
switch (aggrT->__operator) {
case TypeOperator::RECORD:
{
list<string> fieldsList;
for(auto opIt = ++expr.operands.begin(); opIt!=expr.operands.end(); ++opIt){
fieldsList.push_back(getIndexStr(*opIt));
}
return controlIR.compileStructIndex(aggrRaw, aggrT, fieldsList);
};
case TypeOperator::ARRAY:
{
std::vector<llvm::Value*> indexes;
std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()),
[this] (const Expression & op) {
return process(op);
}
);
std::unique_ptr<containers::IContainersIR> containersIR(
containers::IContainersIR::create(aggrE, expectedT, ctx)
);
containers::ArrayIR* arraysIR = static_cast<containers::ArrayIR*>(containersIR.get());
return arraysIR->get(aggrRaw, indexes, hintAlias);
};
default:
assert(false);
}
};
case Operator::CALL_INTRINSIC:
{
// const std::string op = expr.getValueString();
//
// if (op == "copy") {
// llvm::Value* result = process(expr.getOperands().at(0));
//
// auto decoratorVersions = Decorators<VersionsScopeDecoratorTag>::getInterface(this);
// llvm::Value* storage = decoratorVersions->processIntrinsicInit(result->getType());
// decoratorVersions->processIntrinsicCopy(result, storage);
//
// return l.irBuilder.CreateLoad(storage, hintAlias);
// }
assert(false && "undefined intrinsic");
}
case Operator::QUERY:
case Operator::QUERY_LATE:
{
assert(false && "Should be processed by interpretation");
}
case Operator::VARIANT:
{
const ExpandedType& typResult = pass->man->root->getType(expr);
llvm::Type* typResultRaw = l.toLLVMType(typResult);
llvm::Type* typIdRaw = llvm::cast<llvm::StructType>(typResultRaw)->getElementType(0);
uint64_t id = expr.getValueDouble();
llvm::Value* resultRaw = llvm::UndefValue::get(typResultRaw);
resultRaw = l.irBuilder.CreateInsertValue(resultRaw, llvm::ConstantInt::get(typIdRaw, id), llvm::ArrayRef<unsigned>({0}));
const ExpandedType& typVariant = ExpandedType(typResult->__operands.at(id));
llvm::Type* typVariantRaw = l.toLLVMType(typVariant);
llvm::Value* variantRaw = llvm::UndefValue::get(typVariantRaw);
assert(expr.operands.size() == typVariant->__operands.size() && "Wrong variant arguments count");
if (!typVariant->__operands.size()) return resultRaw;
for (unsigned int fieldId = 0; fieldId < expr.operands.size(); ++fieldId) {
const ExpandedType& typField = ExpandedType(typVariant->__operands.at(fieldId));
Attachments::put<TypeInferred>(expr.operands.at(fieldId), typField);
llvm::Value* fieldRaw = process(expr.operands.at(fieldId));
assert(fieldRaw);
variantRaw = l.irBuilder.CreateInsertValue(variantRaw, fieldRaw, llvm::ArrayRef<unsigned>({fieldId}));
}
llvm::Type* typStorageRaw = llvm::cast<llvm::StructType>(typResultRaw)->getElementType(1);
llvm::Value* addrAsStorage = l.irBuilder.CreateAlloca(typStorageRaw);
llvm::Value* addrAsVariant = l.irBuilder.CreateBitOrPointerCast(addrAsStorage, typVariantRaw->getPointerTo());
l.irBuilder.CreateStore(variantRaw, addrAsVariant);
llvm::Value* storageRaw = l.irBuilder.CreateLoad(typStorageRaw, addrAsStorage);
resultRaw = l.irBuilder.CreateInsertValue(resultRaw, storageRaw, llvm::ArrayRef<unsigned>({1}));
return resultRaw;
}
case Operator::SWITCH_VARIANT:
{
- return controlIR.compileSwitchVariant(expr, DEFAULT("tmpswitch"));
+ return controlIR.compileSwitchVariant(expr, hintAlias);
}
case Operator::SWITCH_LATE:
{
assert(false && "Instruction's compilation should've been redirected to interpretation");
return nullptr;
}
case Operator::SEQUENCE:
{
return controlIR.compileSequence(expr);
}
case Operator::UNDEF:
{
llvm::Type* typExprUndef = l.toLLVMType(pass->man->root->getType(expr, expectedT));
return llvm::UndefValue::get(typExprUndef);
}
case Operator::UPDATE:
{
TypesHelper helper(pass->man->llvm);
containers::RecordIR irRecords(ctx);
const Expression& aggrE = expr.operands.at(0);
const Expression& updE = expr.operands.at(1);
const ExpandedType& aggrT = pass->man->root->getType(aggrE);
llvm::Value* aggrRaw = process(aggrE);
if (helper.isRecordT(aggrT)){
return irRecords.update(aggrRaw, aggrT, updE);
}
if (helper.isArrayT(aggrT)){
if (updE.op == Operator::LIST_INDEX){
std::unique_ptr<containers::IContainersIR> containersIR(
containers::IContainersIR::create(aggrE, TypeAnnotation(), ctx
));
return containersIR->update(aggrRaw, updE, hintAlias);
}
}
assert(false);
return nullptr;
}
case Operator::INVALID:
assert(expr.__state != Expression::COMPOUND);
switch (expr.__state) {
case Expression::IDENT:
{
Symbol s = Attachments::get<IdentifierSymbol>(expr);
return processSymbol(s, expr.getValueString());
}
case Expression::NUMBER:
{
llvm::Type* typConst = l.toLLVMType(pass->man->root->getType(expr, expectedT));
int literal = expr.getValueDouble();
if (typConst->isFloatingPointTy()) return llvm::ConstantFP::get(typConst, literal);
if (typConst->isIntegerTy()) return llvm::ConstantInt::get(typConst, literal);
assert(false && "Can't compile literal");
}
case Expression::STRING:
{
- return controlIR.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str"));
+ return controlIR.compileConstantStringAsPChar(expr.getValueString(), hintAlias);
};
default:
{
break;
}
};
break;
default: break;
}
assert(false && "Can't compile expression");
return 0;
}
llvm::Value*
BasicBruteScope::compile(const std::string& hintBlockDecl) {
LLVMLayer* llvm = pass->man->llvm;
if (!hintBlockDecl.empty()) {
llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm->llvmContext, hintBlockDecl, function->raw);
pass->man->llvm->irBuilder.SetInsertPoint(block);
}
lastBlockRaw = pass->man->llvm->irBuilder.GetInsertBlock();
Symbol symbScope = Symbol{ScopedSymbol::RetSymbol, scope};
- return processSymbol(symbScope);
+
+ //set hint for an entry scope
+ string retAlias = (scope->__parent)? "" : function->prepareName();
+ return processSymbol(symbScope, retAlias);
}
IBruteScope::~IBruteScope() { }
IBruteFunction::~IBruteFunction() { }
llvm::Function*
IBruteFunction::compile() {
if (raw != nullptr) return raw;
LLVMLayer* llvm = pass->man->llvm;
llvm::IRBuilder<>& builder = llvm->irBuilder;
string&& functionName = prepareName();
std::vector<llvm::Type*>&& types = prepareSignature();
llvm::Type* expectedResultType = prepareResult();
llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false);
raw = llvm::cast<llvm::Function>(llvm->module->getOrInsertFunction(functionName, ft));
prepareBindings();
applyAttributes();
const std::string& blockName = "entry";
llvm::BasicBlock* blockCurrent = builder.GetInsertBlock();
llvm::Value* result = getBruteScope(__entry)->compile(blockName);
assert(result);
//SECTIONTAG types/convert function ret value
builder.CreateRet(typeinference::doAutomaticTypeConversion(result, expectedResultType, llvm->irBuilder));
if (blockCurrent) {
builder.SetInsertPoint(blockCurrent);
}
llvm->moveToGarbage(ft);
return raw;
}
IBruteScope*
IBruteFunction::getBruteScope(const CodeScope * const scope) {
if (__scopes.count(scope)) {
auto result = __scopes.at(scope).lock();
if (result) {
return result.get();
}
}
std::shared_ptr<IBruteScope> unit(pass->buildCodeScopeUnit(scope, this));
if (scope->__parent != nullptr) {
auto parentUnit = Decorators<CachedScopeDecoratorTag>::getInterface(getBruteScope(scope->__parent));
parentUnit->registerChildScope(unit);
} else {
__orphanedScopes.push_back(unit);
}
if (!__scopes.emplace(scope, unit).second) {
__scopes[scope] = unit;
}
return unit.get();
}
IBruteScope*
IBruteFunction::getScopeUnit(ManagedScpPtr scope) {
return getBruteScope(&*scope);
}
IBruteScope*
IBruteFunction::getEntry() {
return getBruteScope(__entry);
}
std::vector<llvm::Type*>
IBruteFunction::getScopeSignature(CodeScope* scope){
LLVMLayer* llvm = IBruteFunction::pass->man->llvm;
AST* ast = IBruteFunction::pass->man->root;
std::vector<llvm::Type*> result;
std::transform(scope->__bindings.begin(), scope->__bindings.end(), std::inserter(result, result.end()),
- [llvm, ast, scope](const std::string & argAlias)->llvm::Type* {
+ [llvm, ast, scope](const std::string & argAlias)->llvm::Type* {
assert(scope->__identifiers.count(argAlias));
ScopedSymbol argS{scope->__identifiers.at(argAlias), versions::VERSION_NONE};
const Expression& argE = scope->__declarations.at(argS);
const ExpandedType& argT = ast->expandType(argE.type);
return llvm->toLLVMType(argT, argE);
});
+ if(scope->trackExternalSymbs){
+ std::transform(scope->boundExternalSymbs.begin(), scope->boundExternalSymbs.end(), std::inserter(result, result.end()),
+ [llvm, ast](const Symbol& argS){
+ const Expression& argE = CodeScope::getDefinition(argS);
+ const ExpandedType& argT = ast->expandType(argE.type);
+
+ return llvm->toLLVMType(argT, argE);
+ });
+ }
+
return result;
}
template<>
compilation::IBruteFunction*
CompilePassCustomDecorators<void, void>
::buildFunctionUnit(const ManagedFnPtr& function) {
return new BruteFunctionDefault(function, this);
}
template<>
compilation::IBruteScope*
CompilePassCustomDecorators<void, void>
::buildCodeScopeUnit(const CodeScope * const scope, IBruteFunction* function) {
return new DefaultCodeScopeUnit(scope, function, this);
}
std::string
BasicBruteScope::getIndexStr(const Expression& index){
switch(index.__state){
//named struct field
case Expression::STRING:
return index.getValueString();
break;
//anonymous struct field
case Expression::NUMBER:
return to_string((int) index.getValueDouble());
break;
default:
assert(false && "Wrong index for a struct");
}
return "";
}
} // end of compilation
compilation::IBruteFunction*
CompilePass::getBruteFn(const ManagedFnPtr& function) {
unsigned int id = function.id();
if (!functions.count(id)) {
compilation::IBruteFunction* unit = buildFunctionUnit(function);
functions.emplace(id, unit);
return unit;
}
return functions.at(id);
}
void
CompilePass::prepare(){
//Initialization:
#ifndef XREATE_CONFIG_MIN
#endif
managerTransformations = new xreate::compilation::TransformationsManager();
targetInterpretation = new interpretation::TargetInterpretation(man, this);
}
void
CompilePass::run() {
prepare();
//Determine entry function:
StaticModel modelEntry = man->transcend->query(analysis::FN_ENTRY_PREDICATE);
if (man->options.requireEntryFn){
assert(modelEntry.size() && "Error: No entry function found");
assert(modelEntry.size() == 1 && "Error: Ambiguous entry function");
}
if(modelEntry.size()){
string fnEntryName = std::get<0>(TranscendLayer::parse<std::string>(modelEntry.begin()->second));
compilation::IBruteFunction* fnEntry = getBruteFn(man->root->findFunction(fnEntryName));
__fnEntryRaw = fnEntry->compile();
}
//Compile exterior functions:
StaticModel modelExterior = man->transcend->query(analysis::FN_EXTERIOR_PREDICATE);
for(const auto entry: modelExterior){
const string& fnName = std::get<0>(TranscendLayer::parse<std::string>(entry.second));
getBruteFn(man->root->findFunction(fnName))->compile();
}
}
llvm::Function*
CompilePass::getEntryFunction() {
return __fnEntryRaw;
}
void
CompilePass::prepareQueries(TranscendLayer* transcend) {
#ifndef XREATE_CONFIG_MIN
transcend->registerQuery(new latex::LatexQuery(), QueryId::LatexQuery);
#endif
transcend->registerQuery(new containers::Query(), QueryId::ContainersQuery);
transcend->registerQuery(new demand::DemandQuery(), QueryId::DemandQuery);
transcend->registerQuery(new polymorph::PolymorphQuery(), QueryId::PolymorphQuery);
}
} //end of namespace xreate
/**
* \class xreate::CompilePass
* \brief The owner of the compilation process. Performs fundamental compilation activities along with the xreate::compilation's routines
*
* xreate::CompilePass traverses over xreate::AST tree and produces executable code.
* The pass performs compilation using the following data sources:
* - %Attachments: the data gathered by the previous passes. See \ref xreate::Attachments.
* - Transcend solutions accessible via queries. See \ref xreate::IQuery, \ref xreate::TranscendLayer.
*
* The pass generates a bytecode by employing \ref xreate::LLVMLayer(wrapper over LLVM toolchain).
* Many compilation activities are delegated to more specific routines. Most notable delegated compilation aspects are:
* - Containers support. See \ref xreate::containers.
* - Latex compilation. See \ref xreate::latex.
* - Interpretation support. See \ref xreate::interpretation.
* - Loop saturation support. See \ref xreate::compilation::TransformationsScopeDecorator.
* - External code interaction support. See \ref xreate::ExternLayer (wrapper over Clang library).
*
* \section adaptability_sect Adaptability
* xreate::CompilePass's behaviour can be adapted in several ways:
* - %Function Decorators to alter function-level compilation. See \ref xreate::compilation::IBruteFunction
* - Code Block Decorators to alter code block level compilation. See \ref xreate::compilation::ICodeScopeUnit.
* Default functionality defined by \ref xreate::compilation::DefaultCodeScopeUnit
* - Targets to allow more versitile extensions.
* Currently only xreate::interpretation::TargetInterpretation use Targets infrastructure. See \ref xreate::compilation::Target.
* - Altering %function invocation. See \ref xreate::compilation::IFnInvocation.
*
* Clients are free to construct a compiler instantiation with the desired decorators by using \ref xreate::compilation::CompilePassCustomDecorators.
* As a handy alias, `CompilePassCustomDecorators<void, void>` constructs the default compiler.
*
- */
+ */
\ No newline at end of file
diff --git a/cpp/src/pass/compilepass.h b/cpp/src/pass/compilepass.h
index e7f2238..d050a82 100644
--- a/cpp/src/pass/compilepass.h
+++ b/cpp/src/pass/compilepass.h
@@ -1,233 +1,236 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Author: pgess <v.melnychenko@xreate.org>
*
* compilepass.h
*/
#ifndef COMPILEPASS_H
#define COMPILEPASS_H
#include "abstractpass.h"
#include "llvm/IR/Function.h"
namespace xreate {
class TranscendLayer;
class CompilePass;
class LLVMLayer;
namespace interpretation{
class TargetInterpretation;
}
}
namespace xreate { namespace compilation {
class IBruteScope;
class IBruteFunction;
class TransformationsManager;
/** \brief Holds current position in %AST while traversing*/
struct Context{
IBruteScope* scope;
IBruteFunction* function;
CompilePass* pass;
};
/** \brief Interface for custom function invocation operation compilation
* \details Default implementation is xreate::compilation::BruteFnInvocation
*/
class IFnInvocation {
public:
/** \brief Returns result of custom function invocation for the given arguments*/
virtual llvm::Value* operator() (std::vector<llvm::Value *>&& args, const std::string& hintDecl="") = 0;
};
/** \brief Default IFnInvocation implementation */
class BruteFnInvocation: public IFnInvocation{
public:
BruteFnInvocation(llvm::Function* callee, LLVMLayer* l)
: __callee(callee), __calleeTy(callee->getFunctionType()), llvm(l) {}
BruteFnInvocation(llvm::Value* callee, llvm::FunctionType* ty, LLVMLayer* l)
: __callee(callee), __calleeTy(ty), llvm(l) {}
/** \brief Makes type conversions and returns LLVM call statement with given arguments*/
llvm::Value* operator() (std::vector<llvm::Value *>&& args, const std::string& hintDecl="");
protected:
llvm::Value* __callee;
llvm::FunctionType* __calleeTy;
LLVMLayer* llvm;
};
/** \brief %Function invocation operator decorator to handle latex enabled functions with hidden extra arguments */
class HiddenArgsFnInvocation : public compilation::IFnInvocation{
public:
HiddenArgsFnInvocation(std::vector<llvm::Value *> args, compilation::IFnInvocation *parent)
: __args(args), __parent(parent){}
llvm::Value *operator()(std::vector<llvm::Value *> &&args, const std::string &hintDecl = "");
private:
std::vector<llvm::Value *> __args;
compilation::IFnInvocation *__parent;
};
/** \brief Interface to allow modification of CodeScope compilation
* \details Default implementation defined in xreate::compilation::DefaultCodeScopeUnit
*/
class IBruteScope{
public:
CompilePass* const pass;
IBruteFunction* const function;
const CodeScope* const scope;
llvm::BasicBlock* lastBlockRaw;
IBruteScope(const CodeScope* const codeScope, IBruteFunction* f, CompilePass* compilePass);
virtual ~IBruteScope();
virtual llvm::Value* compile(const std::string& hintBlockDecl="")=0;
virtual llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar="")=0;
virtual llvm::Value* process(const Expression& expr, const std::string& hintVarDecl="", const TypeAnnotation& expectedT = TypeAnnotation())=0;
virtual Symbol bindArg(llvm::Value* value, std::string&& alias)=0;
virtual void bindArg(llvm::Value* value, const ScopedSymbol& s)=0;
+ virtual void bindExternalSymb(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;
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): pass(p), __entry(entry){}
- virtual ~IBruteFunction();
+ IBruteFunction(CodeScope* entry, CompilePass* p):
+ isLambda(false), pass(p), __entry(entry){}
+ virtual ~IBruteFunction();
- llvm::Function* compile();
+ 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;
- IBruteScope* getEntry();
- virtual ManagedFnPtr getASTFn() const {return ManagedFnPtr();};
- IBruteScope* getBruteScope(const CodeScope * const scope);
- IBruteScope* getScopeUnit(ManagedScpPtr scope);
+ llvm::Function* raw = nullptr;
+ bool isLambda;
- llvm::Function* raw = nullptr;
-
protected:
- CompilePass* pass=nullptr;
- CodeScope* __entry;
-
- virtual std::string prepareName() = 0;
- virtual std::vector<llvm::Type*> prepareSignature() = 0;
- virtual llvm::Function::arg_iterator prepareBindings() = 0;
- virtual llvm::Type* prepareResult() = 0;
- virtual void applyAttributes() = 0;
+ 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;
private:
- std::map<const CodeScope * const, std::weak_ptr<IBruteScope>> __scopes;
- std::list<std::shared_ptr<IBruteScope>> __orphanedScopes;
+ 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)
+ BasicBruteFunction(ManagedFnPtr f, CompilePass* p)
: IBruteFunction(f->getEntryScope(), p), __function(f) {}
+ std::string prepareName() override;
+
protected:
- std::string prepareName() override;
virtual std::vector<llvm::Type*> prepareSignature() override;
virtual llvm::Type* prepareResult() override;
virtual llvm::Function::arg_iterator prepareBindings() override;
virtual void applyAttributes() override;
virtual ManagedFnPtr getASTFn() const {return __function;};
protected:
ManagedFnPtr __function;
};
} // end of namespace compilation
class CompilePass : public AbstractPass<void> {
friend class compilation::BasicBruteScope;
friend class compilation::IBruteFunction;
public:
compilation::TransformationsManager* managerTransformations;
interpretation::TargetInterpretation* targetInterpretation;
CompilePass(PassManager* manager): AbstractPass<void>(manager) {}
/** \brief Executes compilation process */
void run() override;
/**\brief Returns compiled specified %Function
* \details Executes function compilation or read cache if it's already done
*/
compilation::IBruteFunction* 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();
protected:
virtual compilation::IBruteFunction* buildFunctionUnit(const ManagedFnPtr& function)=0;
virtual compilation::IBruteScope* buildCodeScopeUnit(const CodeScope* const scope, compilation::IBruteFunction* function)=0;
private:
//TODO free `functions` in destructor
std::map<unsigned int, compilation::IBruteFunction*> functions;
llvm::Function* __fnEntryRaw = 0;
};
namespace compilation{
/** \brief Constructs compiler with desired %Function and %Code Scope decorators. See adaptability in xreate::CompilePass*/
template<class FUNCTION_DECORATOR=void, class SCOPE_DECORATOR=void>
class CompilePassCustomDecorators: public ::xreate::CompilePass{
public:
CompilePassCustomDecorators(PassManager* manager): ::xreate::CompilePass(manager) {}
virtual compilation::IBruteFunction* buildFunctionUnit(const ManagedFnPtr& function) override{
return new FUNCTION_DECORATOR(function, this);
}
virtual compilation::IBruteScope* buildCodeScopeUnit(const CodeScope* const scope, IBruteFunction* function) override{
return new SCOPE_DECORATOR(scope, function, this);
}
};
template<>
compilation::IBruteFunction*
CompilePassCustomDecorators<void, void>::buildFunctionUnit(const ManagedFnPtr& function);
template<>
compilation::IBruteScope*
CompilePassCustomDecorators<void, void>::buildCodeScopeUnit(const CodeScope* const scope, IBruteFunction* function);
}} //end of namespace xreate::compilation
#endif // COMPILEPASS_H
diff --git a/cpp/src/pass/interpretationpass.cpp b/cpp/src/pass/interpretationpass.cpp
index 5f1d29e..5a7b9bb 100644
--- a/cpp/src/pass/interpretationpass.cpp
+++ b/cpp/src/pass/interpretationpass.cpp
@@ -1,563 +1,563 @@
/* 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: interpretationpass.cpp
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on July 5, 2016, 5:21 PM
*/
/**
* \file interpretationpass.h
* \brief Interpretation analysis: determines what parts of a code could be interpreted
*/
#include "ast.h"
#include "pass/interpretationpass.h"
#include "compilation/targetinterpretation.h"
#include "analysis/utils.h"
#include "analysis/predefinedanns.h"
#include <bits/stl_vector.h>
//DEBT implement InterpretationPass purely in transcend
//DEBT represent InterpretationPass as general type inference
using namespace std;
namespace xreate {
template<>
interpretation::InterpretationResolution
defaultValue<interpretation::InterpretationResolution>() {
return interpretation::CMPL_ONLY;
}
namespace interpretation {
enum InterpretationQuery {
QUERY_INTR_ONLY, QUERY_CMPL_ONLY
};
namespace details {
template<InterpretationQuery FLAG_REQUIRED>
bool
checkConstraints(InterpretationResolution flag) {
return( (flag==INTR_ONLY&&FLAG_REQUIRED==QUERY_INTR_ONLY)
||(flag==CMPL_ONLY&&FLAG_REQUIRED==QUERY_CMPL_ONLY));
}
InterpretationResolution
recognizeTags(const map<std::string, Expression>& tags) {
std::list<Expression> tagsL;
auto predefined = analysis::PredefinedAnns::instance();
for(const auto& tag: tags){tagsL.push_back(tag.second);}
const Expression& tagI12nE = analysis::findAnnById(
(unsigned) analysis::PredefinedAnns::ExprAnnotations::I12N,
ExpandedType(predefined.exprAnnsT),
tagsL);
if (!tagI12nE.isValid()) return ANY;
analysis::PredefinedAnns::I12ModeTag modeI12n = (analysis::PredefinedAnns::I12ModeTag) tagI12nE.operands.at(0).getValueDouble();
switch(modeI12n){
case analysis::PredefinedAnns::I12ModeTag::ON:
return INTR_ONLY;
case analysis::PredefinedAnns::I12ModeTag::OFF:
return CMPL_ONLY;
}
return ANY;
}
}
InterpretationResolution
unify(InterpretationResolution flag) {
return flag;
}
template<typename FLAG_A, typename FLAG_B, typename... FLAGS>
InterpretationResolution
unify(FLAG_A flagA, FLAG_B flagB, FLAGS... flags) {
if(flagA==ANY){
return unify(flagB, flags...);
}
if(flagB==ANY){
return unify(flagA, flags...);
}
assert(flagA==flagB);
return flagA;
}
template<InterpretationQuery FLAG_REQUIRED>
bool
checkConstraints(std::vector<InterpretationResolution>&& flags) {
assert(flags.size());
InterpretationResolution flag=flags.front();
return details::checkConstraints<FLAG_REQUIRED>(flag);
}
template<InterpretationQuery FLAG_REQUIRED_A, InterpretationQuery FLAG_REQUIRED_B, InterpretationQuery... FLAGS>
bool
checkConstraints(std::vector<InterpretationResolution>&& flags) {
assert(flags.size());
InterpretationResolution flag=flags.front();
flags.pop_back();
if(details::checkConstraints<FLAG_REQUIRED_A>(flag)){
return checkConstraints<FLAG_REQUIRED_B, FLAGS...>(move(flags));
}
return false;
}
bool
InterpretationData::isDefault() const {
return(resolution==ANY&&op==NONE);
}
void
recognizeTags(const Expression& e) {
InterpretationData tag{details::recognizeTags(e.tags), NONE};
if(!tag.isDefault())
Attachments::put<InterpretationData>(e, tag);
}
InterpretationResolution
recognizeTags(const ManagedFnPtr& f) {
return details::recognizeTags(f->getTags());
}
InterpretationPass::InterpretationPass(PassManager* manager)
: AbstractPass(manager) {
Attachments::init<I12nFunctionSpec>();
Attachments::init<InterpretationData>();
}
void
InterpretationPass::run() {
ManagedFnPtr f=man->root->begin<Function>();
auto& visitedSymbols=getSymbolCache();
while(f.isValid()) {
const Symbol&symbolFunction{ScopedSymbol::RetSymbol, f->getEntryScope()};
if(!visitedSymbols.isCached(symbolFunction)){
visitedSymbols.setCachedValue(symbolFunction, process(f));
}
++f;
}
}
InterpretationResolution
InterpretationPass::process(const Expression& expression, PassContext context, const std::string& decl) {
recognizeTags(expression);
InterpretationResolution resolution=ANY;
InterpretationOperator opNo=NONE;
switch(expression.__state) {
case Expression::NUMBER:
case Expression::STRING:
{
break;
}
case Expression::IDENT:
{
resolution=Parent::processSymbol(Attachments::get<IdentifierSymbol>(expression), context);
break;
}
case Expression::COMPOUND:
break;
default:
{
resolution=CMPL_ONLY;
break;
}
}
if(expression.__state==Expression::COMPOUND)
switch(expression.op) {
case Operator::EQU:
case Operator::NE:
{
InterpretationResolution left=process(expression.operands[0], context);
InterpretationResolution right=process(expression.operands[1], context);
resolution=unify(left, right);
break;
}
case Operator::LOGIC_AND:
{
assert(expression.operands.size()==1);
resolution=process(expression.operands[0], context);
break;
}
case Operator::CALL:
{
size_t sizeOperands = expression.operands.size();
std::vector<InterpretationResolution> operands;
operands.reserve(sizeOperands);
for(size_t opNo=0; opNo<sizeOperands; ++opNo) {
const Expression &operand=expression.operands[opNo];
operands.push_back(process(operand, context));
}
//TODO cope with static/dynamic context
//TODO BUG here: if several variants they all are processed as CMPL regardless of signature
list<ManagedFnPtr> callees=man->root->getFnSpecializations(expression.getValueString());
if(callees.size()!=1){
resolution=CMPL_ONLY;
break;
}
ManagedFnPtr callee=callees.front();
const Symbol& symbCalleeFunc{ScopedSymbol::RetSymbol, callee->getEntryScope()};
//recursion-aware processing:
// - skip self recursion
const Symbol&symbSelfFunc{ScopedSymbol::RetSymbol, context.function->getEntryScope()};
if(!(symbSelfFunc==symbCalleeFunc)){
InterpretationResolution resCallee=processFnCall(callee, context);
assert(resCallee!=FUNC_POSTPONED&&"Indirect recursion detected: can't decide on interpretation resolution");
resolution=unify(resolution, resCallee);
}
//check arguments compatibility
const I12nFunctionSpec& calleeSignature=FunctionInterpretationHelper::getSignature(callee);
for(size_t opNo=0; opNo<sizeOperands; ++opNo){
InterpretationResolution argActual=operands.at(opNo);
InterpretationResolution argExpected=calleeSignature.signature[opNo];
//TODO use args unification result to properly process function call
unify(argActual, argExpected);
}
if(FunctionInterpretationHelper::needPartialInterpretation(callee)){
opNo=CALL_INTERPRET_PARTIAL;
}
break;
}
case Operator::CALL_INTRINSIC:
{
switch((IntrinsicFn) expression.getValueDouble()){
case IntrinsicFn::REC_FIELDS: resolution = INTR_ONLY; break;
default: resolution=CMPL_ONLY; break;
}
break;
}
case Operator::QUERY:
{
resolution=INTR_ONLY;
break;
}
case Operator::QUERY_LATE:
{
InterpretationResolution predicate=process(expression.operands[0], context);
unify(predicate, INTR_ONLY);
CodeScope* exprBody=expression.blocks.front();
const std::string& argName=expression.bindings[0];
Symbol argS = {
ScopedSymbol{exprBody->__identifiers.at(argName), versions::VERSION_NONE},
exprBody
};
getSymbolCache().setCachedValue(argS, INTR_ONLY);
Parent::process(expression.blocks.front(), context);
resolution = CMPL_ONLY;
opNo=QUERY_LATE;
break;
}
case Operator::SWITCH_LATE:
{
resolution = CMPL_ONLY;
opNo = SWITCH_LATE;
break;
}
case Operator::IF:
{
InterpretationResolution flagCondition=process(expression.getOperands()[0], context);
InterpretationResolution flagScope1=Parent::process(expression.blocks.front(), context);
InterpretationResolution flagScope2=Parent::process(expression.blocks.back(), context);
//special case: IF_INTERPRET_CONDITION
if(checkConstraints<QUERY_INTR_ONLY>({flagCondition})){
opNo=IF_INTERPRET_CONDITION;
flagCondition=ANY;
}
resolution=unify(flagCondition, flagScope1, flagScope2);
break;
}
case Operator::FOLD:
{
InterpretationResolution flagInput=process(expression.getOperands()[0], context);
InterpretationResolution flagAccumInit=process(expression.getOperands()[1], context);
CodeScope* scopeBody=expression.blocks.front();
const std::string& nameEl=expression.bindings[0];
Symbol symbEl{ScopedSymbol
{scopeBody->__identifiers.at(nameEl), versions::VERSION_NONE}, scopeBody};
getSymbolCache().setCachedValue(symbEl, InterpretationResolution(flagInput));
const std::string& nameAccum=expression.bindings[1];
Symbol symbAccum{ScopedSymbol
{scopeBody->__identifiers.at(nameAccum), versions::VERSION_NONE}, scopeBody};
getSymbolCache().setCachedValue(symbAccum, InterpretationResolution(flagAccumInit));
InterpretationResolution flagBody=Parent::process(expression.blocks.front(), context);
//special case: FOLD_INTERPRET_INPUT
if(checkConstraints<QUERY_INTR_ONLY>({flagInput})){
opNo=FOLD_INTERPRET_INPUT;
flagInput=ANY;
}
resolution=unify(flagInput, flagAccumInit, flagBody);
break;
}
case Operator::INDEX:
{
for(const Expression &opNo : expression.getOperands()) {
resolution=unify(resolution, process(opNo, context));
}
break;
}
case Operator::SWITCH:
{
InterpretationResolution flagCondition=process(expression.operands[0], context);
bool hasDefaultCase=expression.operands[1].op==Operator::CASE_DEFAULT;
//determine conditions resolution
InterpretationResolution flagHeaders=flagCondition;
for(size_t size=expression.operands.size(), i=hasDefaultCase?2:1; i<size; ++i) {
const Expression& exprCase=expression.operands[i];
flagHeaders=unify(flagHeaders, Parent::process(exprCase.blocks.front(), context));
}
if(checkConstraints<QUERY_INTR_ONLY>({flagHeaders})){
opNo=SWITCH_INTERPRET_CONDITION;
flagHeaders=ANY;
}
//determine body resolutions
resolution=flagHeaders;
for(size_t size=expression.operands.size(), i=1; i<size; ++i) {
const Expression& exprCase=expression.operands[i];
resolution=unify(resolution, Parent::process(exprCase.blocks.back(), context));
}
break;
}
case Operator::SWITCH_VARIANT:
{
InterpretationResolution resolutionCondition=process(expression.operands.at(0), context);
resolution=resolutionCondition;
if(checkConstraints<QUERY_INTR_ONLY>({resolution})){
opNo=SWITCH_VARIANT;
resolution=ANY;
}
const string identCondition=expression.bindings.front();
for(auto scope : expression.blocks) {
//set binding resolution
- ScopedSymbol symbolInternal=scope->getSymbol(identCondition);
+ ScopedSymbol symbolInternal= scope->findSymbolByAlias(identCondition);
getSymbolCache().setCachedValue(Symbol{symbolInternal, scope}, InterpretationResolution(resolutionCondition));
resolution=unify(resolution, Parent::process(scope, context));
}
for(auto scope : expression.blocks) {
resolution=unify(resolution, Parent::process(scope, context));
}
break;
}
case Operator::LIST:
{
for(const Expression &opNo : expression.getOperands()) {
resolution=unify(resolution, process(opNo, context));
}
break;
}
case Operator::VARIANT:
{
if(expression.getOperands().size()){
resolution=process(expression.getOperands().front(), context);
} else {
resolution=ANY;
}
break;
}
default:
{
resolution=CMPL_ONLY;
for(const Expression &opNo : expression.getOperands()) {
process(opNo, context);
}
for(CodeScope* scope : expression.blocks) {
Parent::process(scope, context);
}
break;
}
}
InterpretationData dataExpected=
Attachments::get<InterpretationData>(expression,{ANY, NONE});
resolution=unify(resolution, dataExpected.resolution);
if(resolution!=dataExpected.resolution || opNo != dataExpected.op ){
Attachments::put<InterpretationData>(expression,{resolution, opNo});
}
return resolution;
}
InterpretationResolution
InterpretationPass::processFnCall(ManagedFnPtr function, PassContext context) {
return process(function);
}
InterpretationResolution
InterpretationPass::process(ManagedFnPtr function) {
CodeScope* entry=function->getEntryScope();
std::vector<std::string> arguments=entry->__bindings;
const Symbol&symbSelfFunc{ScopedSymbol::RetSymbol, function->getEntryScope()};
auto& cache=getSymbolCache();
if(cache.isCached(symbSelfFunc))
return cache.getCachedValue(symbSelfFunc);
const I12nFunctionSpec& fnSignature=FunctionInterpretationHelper::getSignature(function);
InterpretationResolution fnResolutionExpected=details::recognizeTags(function->getTags());
//mark preliminary function resolution as expected
if(fnResolutionExpected!=ANY){
cache.setCachedValue(symbSelfFunc, move(fnResolutionExpected));
} else {
// - in order to recognize indirect recursion mark this function resolution as POSTPONED
cache.setCachedValue(symbSelfFunc, FUNC_POSTPONED);
}
//set resolution for function arguments as expected
for(int argNo=0, size=arguments.size(); argNo<size; ++argNo) {
Symbol symbArg{ScopedSymbol
{entry->__identifiers.at(arguments[argNo]), versions::VERSION_NONE}, entry};
cache.setCachedValue(symbArg, InterpretationResolution(fnSignature.signature[argNo]));
}
PassContext context;
context.function=function;
context.scope=entry;
InterpretationResolution resActual=process(CodeScope::getDefinition(symbSelfFunc), context);
resActual=unify(resActual, fnResolutionExpected);
return cache.setCachedValue(symbSelfFunc, move(resActual));
}
const I12nFunctionSpec
FunctionInterpretationHelper::getSignature(ManagedFnPtr function) {
if(Attachments::exists<I12nFunctionSpec>(function)){
return Attachments::get<I12nFunctionSpec>(function);
}
I12nFunctionSpec&& data=recognizeSignature(function);
Attachments::put<I12nFunctionSpec>(function, data);
return data;
}
I12nFunctionSpec
FunctionInterpretationHelper::recognizeSignature(ManagedFnPtr function) {
CodeScope* entry=function->__entry;
I12nFunctionSpec result;
result.signature.reserve(entry->__bindings.size());
bool flagPartialInterpretation=false;
for(size_t no=0, size=entry->__bindings.size(); no<size; ++no) {
const std::string& argName=entry->__bindings[no];
Symbol symbArg{ScopedSymbol
{entry->__identifiers.at(argName), versions::VERSION_NONE}, entry};
const Expression& arg=CodeScope::getDefinition(symbArg);
InterpretationResolution argResolution=details::recognizeTags(arg.tags);
flagPartialInterpretation|=(argResolution==INTR_ONLY);
result.signature.push_back(argResolution);
}
result.flagPartialInterpretation=flagPartialInterpretation;
return result;
}
bool
FunctionInterpretationHelper::needPartialInterpretation(ManagedFnPtr function) {
const I12nFunctionSpec& data=getSignature(function);
return data.flagPartialInterpretation;
}
}
} //end of namespace xreate::interpretation
/** \class xreate::interpretation::InterpretationPass
*
* The class encapsulates *Interpretation Analysis* to support [Interpretation](/d/concepts/interpretation/).
*
* It recognizes program functions, expressions, instructions eligible for interpretation
* and stores the output in \ref Attachments<I12nFunctionSpec> and \ref Attachments<InterpretationData>
*
* There are number of instructions currently eligible for interpretation:
* - Basic literals: numbers and strings
* - Compounds: lists, structs, variants
* - Non-versioned identifiers
* - Comparison and logic operators
* - %Function calls
* - `query` intrinsic function calls
* - Branching: `if`, `loop fold`, `switch`, `switch variant` statements
*
* Some of these instructions are eligible also for *late interpretation* to allow coupling
* of compiled instructions with interpreted ones, those are:
* - Partial function calls
* - Branching: `if`, `loop fold`, `switch`, `switch variant` statements
*
* \sa xreate::interpretation::TargetInterpretation, [Interpretation Concept](/d/concepts/interpretation/)
*/
diff --git a/cpp/tests/ast.cpp b/cpp/tests/ast.cpp
index 2f76ecf..4e97c6a 100644
--- a/cpp/tests/ast.cpp
+++ b/cpp/tests/ast.cpp
@@ -1,288 +1,307 @@
/* 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}));
+}
+
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 e019829..46688e9 100644
--- a/cpp/tests/compilation.cpp
+++ b/cpp/tests/compilation.cpp
@@ -1,346 +1,378 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* compilation.cpp
*
* Created on: -
* Author: pgess <v.melnychenko@xreate.org>
*/
#include "xreatemanager.h"
#include "supplemental/basics.h"
#include "llvmlayer.h"
#include "pass/compilepass.h"
#include "compilation/lambdas.h"
#include "gtest/gtest.h"
using namespace xreate;
using namespace xreate::compilation;
using namespace std;
//DEBT implement no pkgconfig ways to link libs
//TOTEST FunctionUnit::compileInline
TEST(Compilation, functionEntry1){
std::unique_ptr<XreateManager> program(XreateManager::prepare(
"func1 = function(a:: int):: int {a+8} \
func2 = function::int; entry {12 + func1(4)} \
"));
void* entryPtr = program->run();
int (*entry)() = (int (*)())(intptr_t)entryPtr;
int answer = entry();
ASSERT_EQ(24, answer);
}
TEST(Compilation, full_IFStatementWithVariantType){
XreateManager* man = XreateManager::prepare(
"Color = type variant {RED, BLUE, GREEN}.\n"
"\n"
" main = function(x::int):: bool; entry {\n"
" color = if (x == 0 )::Color {RED()} else {BLUE()}.\n"
" if (color == BLUE())::bool {true} else {false}\n"
" }"
);
bool (*main)(int) = (bool (*)(int)) man->run();
ASSERT_FALSE(main(0));
ASSERT_TRUE(main(1));
}
TEST(Compilation, full_Variant1){
XreateManager* man = XreateManager::prepare(R"Code(
global = type predicate {
entry
}
Command= type variant{
Add(x::int, y::int),
Dec(x::int)
}.
main = function::Command; entry() {
Dec(2) ::Command
}
)Code");
void (*main)() = (void (*)()) man->run();
}
TEST(Compilation, full_SwitchVariant1){
XreateManager* man = XreateManager::prepare(R"Code(
Command= type variant{
Add(x::int, y::int),
Dec(x::int)
}.
main = function::int; entry {
command = Add(3, 5):: Command.
switch variant(command)::int
case(Add){command["x"] + command["y"]}
case(Dec){command["x"]}
}
)Code");
int (*mainFn)() = (int (*)()) man->run();
int result = mainFn();
ASSERT_EQ(8, result);
}
TEST(Compilation, full_SwitchVariantNoArguments2){
XreateManager* man = XreateManager::prepare(R"Code(
Command= type variant{Add, Dec}.
main = function::int; entry {
command = Dec():: Command.
switch variant(command)::int
case(Add){0}
case(Dec){1}
}
)Code");
int (*mainFn)() = (int (*)()) man->run();
int result = mainFn();
ASSERT_EQ(1, result);
}
TEST(Compilation, full_SwitchVariantMixedArguments3){
XreateManager* man = XreateManager::prepare(R"Code(
Command= type variant{
Add(x::int, y::int),
Dec
}.
main = function(arg::int):: int; entry {
command = if (arg > 0)::Command {Dec()} else {Add(1, 2)}.
switch variant(command)::int
case(Add){0}
case(Dec){1}
}
)Code");
int (*mainFn)(int) = (int (*)(int)) man->run();
int result = mainFn(5);
ASSERT_EQ(1, result);
}
TEST(Compilation, full_StructUpdate){
XreateManager* man = XreateManager::prepare(
R"Code(
Rec = type {
a :: int,
b:: int
}.
test= function:: int; entry {
a = {a = 18, b = 20}:: Rec.
b = a + {a = 11}:: Rec.
b["a"]
}
)Code");
int (*main)() = (int (*)()) man->run();
int result = main();
ASSERT_EQ(11, result);
}
TEST(Compilation, AnonymousStruct_init_index){
std::string code =
R"Code(
main = function:: int; entry {
x = {10, 15} :: {int, int}.
x[1]
}
)Code";
std::unique_ptr<XreateManager> man(XreateManager::prepare(move(code)));
int (*main)() = (int (*)()) man->run();
EXPECT_EQ(15, main());
}
TEST(Compilation, AnonymousStruct_init_update){
std::string code =
R"Code(
main = function:: int; entry {
x = {10, 15} :: {int, int}.
y = x + {6}:: {int, int}.
y[0]
}
)Code";
std::unique_ptr<XreateManager> man(XreateManager::prepare(move(code)));
int (*main)() = (int (*)()) man->run();
EXPECT_EQ(6, main());
}
TEST(Compilation, BugIncorrectScopes1){
std::string code =
R"Code(
init = function:: int {10}
main = function(cmd:: int):: int; entry {
x = init():: int.
if(cmd > 0):: int { x + 1 } else { x }
}
)Code";
std::unique_ptr<XreateManager> man(XreateManager::prepare(move(code)));
int (*mainFn)(int) = (int (*)(int)) man->run();
EXPECT_EQ(11, mainFn(1));
}
TEST(Compilation, Sequence1){
std::string code =
R"Code(
interface(extern-c){
libbsd = library:: pkgconfig("libbsd").
include {
libbsd = {"bsd/stdlib.h", "string.h"}
}.
}
start = function:: i32; entry {
seq {
nameNew = "TestingSequence":: string.
setprogname(nameNew)
} {strlen(getprogname())}::i32
}
)Code";
std::unique_ptr<XreateManager> man(XreateManager::prepare(move(code)));
int (*startFn)() = (int (*)()) man->run();
int nameNewLen = startFn();
ASSERT_EQ(15, nameNewLen);
}
TEST(Compilation, BoolInstructions1){
std::string code =
R"Code(
test = function (a:: bool, b:: bool):: bool; entry
{
-a
}
)Code";
std::unique_ptr<XreateManager> man(XreateManager::prepare(move(code)));
Fn2Args startFn = (Fn2Args) man->run();
}
TEST(Compilation, StructIndex1){
std::string code =
R"Code(
Anns = type predicate {
entry()
}
test = function:: int; entry()
{
x = {a = ({b = 3}::{b:: int})}:: {a:: {b:: int}}.
2 + x["a", "b"] + x["a"]["b"]
}
)Code";
std::unique_ptr<XreateManager> man(XreateManager::prepare(move(code)));
FnNoArgs startFn = (FnNoArgs) man->run();
int result = startFn();
ASSERT_EQ(2, result);
}
TEST(Compilation, PreferredInt1){
std::unique_ptr<XreateManager> man(XreateManager::prepare(""));
TypesHelper utils(man->llvm);
int bitwidth = utils.getPreferredIntTy()->getBitWidth();
ASSERT_EQ(64, bitwidth);
}
TEST(Compilation, PredPredicates1){
string code = R"(
my-fn = function:: int; entry() {0}
)";
auto man = XreateManager::prepare(move(code));
FnNoArgs startFn = (FnNoArgs) man->run();
int result = startFn();
ASSERT_EQ(0, result);
}
typedef intmax_t (*FnI_I)(intmax_t);
TEST(Compilation, Lambda1){
string code = R"(
myfn = function:: int {
a = [1..5]:: [int].
loop map(a->x:: int):: [int] { x + 10:: int}
}
)";
auto man = details::tier1::XreateManager::prepare(move(code));
LLVMLayer* llvm = man->llvm;
man->analyse();
std::unique_ptr<CompilePass> compiler(new compilation::CompilePassCustomDecorators<>(man));
compiler->prepare();
LambdaIR compilerLambda(compiler.get());
CodeScope* scopeLoop = man->root->findFunction("myfn")->getEntryScope()->getBody().blocks.front();
auto fnRaw = compilerLambda.compile(scopeLoop, "loop");
llvm->initJit();
FnI_I fn = (FnI_I)llvm->getFunctionPointer(fnRaw);
ASSERT_EQ(20, fn(10));
}
+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");
+ llvm->print();
+ llvm->initJit();
+
+ Fn2Args fn = (Fn2Args)llvm->getFunctionPointer(fnRaw);
+ ASSERT_EQ(30, fn(10, 20));
+}
+
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();
}
\ No newline at end of file
diff --git a/cpp/tests/containers.cpp b/cpp/tests/containers.cpp
index 0049586..7175642 100644
--- a/cpp/tests/containers.cpp
+++ b/cpp/tests/containers.cpp
@@ -1,327 +1,327 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* containers.cpp
*
* Created on: Jun 9, 2015
* Author: pgess <v.melnychenko@xreate.org>
*/
#include "xreatemanager.h"
#include "query/containers.h"
#include "main/Parser.h"
#include "pass/compilepass.h"
#include "llvmlayer.h"
#include "supplemental/docutils.h"
#include "supplemental/basics.h"
#include "gtest/gtest.h"
using namespace std;
using namespace xreate::grammar::main;
using namespace xreate::containers;
using namespace xreate;
struct Tuple2 {intmax_t a; intmax_t b;};
typedef Tuple2 (*FnTuple2)();
struct Tuple4 {intmax_t a; intmax_t b; intmax_t c; intmax_t d;};
typedef Tuple4 (*FnTuple4)();
TEST(Containers, RecInitByList1){
string code = R"(
Rec = type {x:: int, y:: int}.
test = function(a:: int, b::int):: Rec; entry() {
{x = a + b, y = 2}
}
)";
auto man = XreateManager::prepare(move(code));
man->run();
}
TEST(Containers, RecInitByList2){
string code = R"(
Rec = type {x:: int, y:: int}.
test = function(a:: int, b::int):: Rec; entry() {
{a + b, y = 2}
}
)";
auto man = XreateManager::prepare(move(code));
man->run();
}
TEST(Containers, RecUpdateByList1){
string code = R"(
Rec = type {x:: int, y:: int}.
test = function(a:: int, b::int):: Rec; entry() {
r = {0, y = 2}:: Rec.
r : {a + b}
}
)";
auto man = XreateManager::prepare(move(code));
man->run();
}
TEST(Containers, RecUpdateByListIndex1){
string code = R"(
Rec = type {x:: int, y:: int}.
test = function(a:: int, b::int):: int; entry() {
r1 = undef:: Rec.
r2 = r1 : {[1] = b, [0] = a}:: Rec.
r2["x"]
}
)";
auto man = XreateManager::prepare(move(code));
Fn2Args program = (Fn2Args) man->run();
ASSERT_EQ(10, program(10, 11));
}
TEST(Containers, RecUpdateInLoop1){
FILE* code = fopen("scripts/containers/RecUpdateInLoop1.xreate", "r");
assert(code != nullptr);
auto man = XreateManager::prepare(code);
Fn1Args program = (Fn1Args) man->run();
ASSERT_EQ(11, program(10));
}
TEST(Containers, ArrayInit1){
XreateManager* man = XreateManager::prepare(
R"Code(
main = function(x:: int):: int; entry() {
a = {1, 2, 3}:: [int].
a[x]
}
)Code");
void* mainPtr = man->run();
Fn1Args main = (Fn1Args) mainPtr;
ASSERT_EQ(2, main(1));
delete man;
}
TEST(Containers, ArrayUpdate1){
XreateManager* man = XreateManager::prepare(R"(
main = function(x::int):: int; entry()
{
a = {1, 2, 3}:: [int]; csize(5).
b = a : {[1] = x}:: [int]; csize(5).
b[1]
}
)");
void* mainPtr = man->run();
Fn1Args main = (Fn1Args) mainPtr;
ASSERT_EQ(2, main(2));
delete man;
}
TEST(Containers, FlyMap1){
std::unique_ptr<XreateManager> man(XreateManager::prepare(R"(
main = function:: int; entry()
{
x = {1, 2, 3, 4}:: [int].
y = loop map(x->el::int)::[int]; fly(csize(4))
{2 * el:: int }.
loop fold((y::[int]; fly(csize(4)))->el:: int, 0->sum):: int {sum + el}-20
}
)"));
FnNoArgs mainFn = (FnNoArgs) man->run();
intmax_t valueMain = mainFn();
ASSERT_EQ(0, valueMain);
}
TEST(Containers, ArrayArg1){
FILE* code = fopen("scripts/containers/containers-tests.xreate", "r");
assert(code != nullptr);
std::unique_ptr<XreateManager> man(XreateManager::prepare(code));
man->options.requireEntryFn = false;
man->run();
FnNoArgs fnTested = (FnNoArgs) man->getExteriorFn("fn-ArrayArg1");
ASSERT_EQ(1, fnTested());
}
TEST(Containers, FlyArg1){
FILE* code = fopen("scripts/containers/containers-tests.xreate", "r");
assert(code != nullptr);
std::unique_ptr<XreateManager> man(XreateManager::prepare(code));
man->options.requireEntryFn = false;
man->run();
FnNoArgs fnTested = (FnNoArgs) man->getExteriorFn("fn-FlyArg1");
ASSERT_EQ(8, fnTested());
}
TEST(Containers, Range1){
FILE* code = fopen("scripts/containers/containers-tests.xreate", "r");
assert(code != nullptr);
std::unique_ptr<XreateManager> man(XreateManager::prepare(code));
man->options.requireEntryFn = false;
man->run();
{
FnNoArgs fnRange1 = (FnNoArgs) man->getExteriorFn("fn-Range1");
ASSERT_EQ(10, fnRange1());
}
{
FnNoArgs fnRange2 = (FnNoArgs) man->getExteriorFn("fn-Range2");
ASSERT_EQ(20, fnRange2());
}
}
//TEST(Containers, ListAsArray2){
// XreateManager* man = XreateManager::prepare(
//
//R"Code(
// // CONTAINERS
// import raw("scripts/dfa/ast-attachments.lp").
// import raw("scripts/containers/containers.lp").
//
// main = function:: int;entry {
// a= {1, 2, 3}:: [int].
// b= loop map(a->el:: int):: [int]{
// 2 * el
// }.
//
// sum = loop fold(b->el:: int, 0->acc):: int {
// acc + el
// }.
//
// sum
// }
//)Code");
//
// void* mainPtr = man->run();
// FnNoArgs main = (FnNoArgs) mainPtr;
// ASSERT_EQ(12, main());
//
// delete man;
//}
//
//TEST(Containers, Doc_RecField1){
// string code_Variants1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "RecField1");
// XreateManager::prepare(move(code_Variants1));
//
// ASSERT_TRUE(true);
//}
//
//TEST(Containers, Doc_RecUpdate1){
// string code_Variants1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "RecUpdate1");
// XreateManager::prepare(move(code_Variants1));
//
// ASSERT_TRUE(true);
//}
//
//TEST(Containers, ContanierLinkedList1){
// FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r");
// assert(input != nullptr);
//
// Scanner scanner(input);
// Parser parser(&scanner);
// parser.Parse();
//
// AST* ast = parser.root->finalize();
// CodeScope* body = ast->findFunction("test")->getEntryScope();
-// const Symbol symb_chilrenRaw{body->getSymbol("childrenRaw"), body};
+// const Symbol symb_chilrenRaw{body->findSymbolByAlias("childrenRaw"), body};
//
// containers::ImplementationLinkedList iLL(symb_chilrenRaw);
//
// ASSERT_EQ(true, static_cast<bool>(iLL));
// ASSERT_EQ("next", iLL.fieldPointer);
//
// Implementation impl = Implementation::create(symb_chilrenRaw);
// ASSERT_NO_FATAL_FAILURE(impl.extract<ON_THE_FLY>());
//
// ImplementationRec<ON_THE_FLY> recOnthefly = impl.extract<ON_THE_FLY>();
// ASSERT_EQ(symb_chilrenRaw, recOnthefly.source);
//}
//
//TEST(Containers, Implementation_LinkedListFull){
// FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r");
// assert(input != nullptr);
//
// std::unique_ptr<XreateManager> program(XreateManager::prepare(input));
// void* mainPtr = program->run();
// int (*main)() = (int (*)())(intptr_t)mainPtr;
//
// intmax_t answer = main();
// ASSERT_EQ(17, answer);
//
// fclose(input);
//}
//
//TEST(Containers, Doc_Intr_1){
// string example = R"Code(
// import raw("scripts/containers/containers.lp").
//
// test = function:: int; entry
// {
// <BODY>
// x
// }
// )Code";
// string body = getDocumentationExampleById("documentation/Concepts/containers.xml", "Intr_1");
// replace(example, "<BODY>", body);
//
// XreateManager* xreate = XreateManager::prepare(move(example));
// FnNoArgs program = (FnNoArgs) xreate->run();
//
// intmax_t result = program();
// ASSERT_EQ(1, result);
//}
//
//TEST(Containers, Doc_OpAccessSeq_1){
// string example = getDocumentationExampleById("documentation/Concepts/containers.xml", "OpAccessSeq_1");
// XreateManager* xreate = XreateManager::prepare(move(example));
// FnNoArgs program = (FnNoArgs) xreate->run();
//
// intmax_t result = program();
// ASSERT_EQ(15, result);
//}
//
//TEST(Containers, Doc_OpAccessRand_1){
// string example = getDocumentationExampleById("documentation/Concepts/containers.xml", "OpAccessRand_1");
// XreateManager* xreate = XreateManager::prepare(move(example));
// FnNoArgs program = (FnNoArgs) xreate->run();
//
// intmax_t result = program();
// ASSERT_EQ(2, result);
//}
//
//TEST(Containers, Doc_ASTAttach_1){
// string example = getDocumentationExampleById("documentation/Concepts/containers.xml", "ASTAttach_1");
// string outputExpected = "containers_impl(s(1,-2,0),onthefly)";
// XreateManager* xreate = XreateManager::prepare(move(example));
//
// testing::internal::CaptureStdout();
// xreate->run();
// std::string outputActual = testing::internal::GetCapturedStdout();
//
// ASSERT_NE(std::string::npos, outputActual.find(outputExpected));
//}
//
//TEST(Containers, IntrinsicArrInit1){
// XreateManager* man = XreateManager::prepare(
//
//R"Code(
//FnAnns = type predicate {
// entry
//}
//
//main = function(x:: int):: int; entry() {
// a{0} = intrinsic array_init(16):: [int].
// a{1} = a{0} + {15: 12}
//}
//)Code");
//}
diff --git a/cpp/tests/interpretation.cpp b/cpp/tests/interpretation.cpp
index a833453..c7d3d75 100644
--- a/cpp/tests/interpretation.cpp
+++ b/cpp/tests/interpretation.cpp
@@ -1,476 +1,476 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* interpretation.cpp
*
* Created on: -
* Author: pgess <v.melnychenko@xreate.org>
*/
#include "attachments.h"
using namespace xreate;
#include "xreatemanager.h"
#include "compilation/targetinterpretation.h"
#include "supplemental/docutils.h"
#include "gtest/gtest.h"
#include "boost/scoped_ptr.hpp"
//#define FRIENDS_INTERPRETATION_TESTS \
// friend class ::Modules_AST2_Test; \
// friend class ::Modules_Discovery1_Test; \
// friend class ::Modules_Solve1_Test;
#include "pass/interpretationpass.h"
using namespace xreate::grammar::main;
using namespace xreate::interpretation;
using namespace std;
TEST(Interpretation, Analysis_StatementIF_1) {
XreateManager* man = XreateManager::prepare(
R"Code(
main = function::bool {
x = "a":: string.
y = if (x=="b"):: bool; i12n(on()) {
true
} else {
false
}.
y
}
)Code");
InterpretationPass* pass = new InterpretationPass(man);
pass->run();
CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope();
- Symbol symbolY{scopeEntry->getSymbol("y"), scopeEntry};
+ Symbol symbolY{scopeEntry->findSymbolByAlias("y"), scopeEntry};
InterpretationData &dataSymbolY = Attachments::get<InterpretationData>(symbolY);
ASSERT_EQ(INTR_ONLY, dataSymbolY.resolution);
}
TEST(Interpretation, Analysis_StatementIF_InterpretCondition_1) {
XreateManager* man = XreateManager::prepare(
R"Code(
main = function(x:: int):: int {
comm= "inc":: string; i12n(on()).
y = if (comm == "inc")::int {x+1} else {x}.
y
}
)Code");
InterpretationPass* pass = new InterpretationPass(man);
pass->run();
CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope();
- Symbol symbolY{scopeEntry->getSymbol("y"), scopeEntry};
+ Symbol symbolY{scopeEntry->findSymbolByAlias("y"), scopeEntry};
InterpretationData &dataSymbolY = Attachments::get<InterpretationData>(symbolY);
ASSERT_EQ(CMPL_ONLY, dataSymbolY.resolution);
ASSERT_EQ(IF_INTERPRET_CONDITION, dataSymbolY.op);
}
TEST(Interpretation, StatementCall_RecursionIndirect_1) {
XreateManager* man = XreateManager::prepare(
R"Code(
searchNemo = function(data:: Data):: bool
{
if (data == "nemo"):: bool
{false} else {searchDory(data)}
}
searchDory = function(data:: Data):: bool
{
if (data == "dory"):: bool
{true} else {searchNemo(data)}
}
entry = function:: bool; entry() {
searchNemo(""):: bool; i12n(on())
}
)Code");
InterpretationPass* pass = new InterpretationPass(man);
ASSERT_DEATH(pass->run(), "Indirect recursion detected");
}
TEST(Interpretation, PartialIntr_1) {
XreateManager* man = XreateManager::prepare(
R"Code(
evaluate= function(argument:: int, code:: string; i12n(on())):: int {
switch(code):: int
case ("inc") {argument + 1}
case ("dec") {argument - 1}
case ("double") {argument * 2}
case default {argument}
}
main = function:: int; entry() {
commands= {"inc", "double", "dec"}:: [string]; i12n(on()).
loop fold(commands->comm::string, 10->operand):: int
{
evaluate(operand, comm)
}
}
)Code");
InterpretationPass* pass = new InterpretationPass(man);
pass->run();
ManagedFnPtr fnEvaluate = man->root->findFunction("evaluate");
InterpretationResolution resFnEvaluate = pass->process(fnEvaluate);
ASSERT_EQ(CMPL_ONLY, resFnEvaluate);
ASSERT_TRUE(FunctionInterpretationHelper::needPartialInterpretation(fnEvaluate));
const Expression &exprLoop = man->root->findFunction("main")->__entry->getBody();
Symbol symbCallEv{{0, versions::VERSION_NONE}, exprLoop.blocks.front()};
InterpretationData dataCallEv = Attachments::get<InterpretationData>(symbCallEv);
ASSERT_EQ(CMPL_ONLY, dataCallEv.resolution);
ASSERT_EQ(CALL_INTERPRET_PARTIAL, dataCallEv.op);
}
TEST(Interpretation, PartialIntr_3) {
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(
R"Code(
Command= type variant {INC, DEC, DOUBLE}.
evaluate= function(argument:: int, code:: Command; i12n(on())):: int {
switch variant(code)::int
case (INC) {argument + 1}
case (DEC) {argument - 1}
case (DOUBLE) {argument * 2}
}
main = function::int; entry() {
commands= {INC(), DOUBLE(), DEC()}:: [Command]; i12n(on()).
loop fold(commands->comm::Command, 10->operand):: int{
evaluate(operand, comm)
}
}
)Code");
man->analyse();
if(!man->isPassRegistered(PassId::InterpretationPass)) {
InterpretationPass* pass = new InterpretationPass(man);
pass->run();
}
int (* main)() = (int (*)()) man->run();
int result = main();
ASSERT_EQ(21, result);
}
TEST(Interpretation, PartialIntr_4) {
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(
R"Code(
Command= type variant {INC, DEC, DOUBLE}.
evaluate= function(argument:: int, code:: Command; i12n(on())):: int {
switch variant(code)::int
case (INC) {argument + 1}
case (DEC) {argument - 1}
case (DOUBLE) {argument * 2}
}
main = function::int; entry() {
evaluate(4, DEC())
}
)Code");
man->analyse();
if(!man->isPassRegistered(PassId::InterpretationPass)) {
InterpretationPass* pass = new InterpretationPass(man);
pass->run();
}
int (* main)() = (int (*)()) man->run();
int result = main();
ASSERT_EQ(3, result);
}
TEST(Interpretation, SwitchVariant) {
xreate::XreateManager* man = xreate::XreateManager::prepare(
R"Code(
Command= type variant {
ADD(x::int, y::int),
DEC(x::int),
DOUBLE(x::int)
}.
main = function::int; entry(){
program = ADD(2, 3)::Command; i12n(on()).
switch variant(program)::int
case (ADD) {program["x"]+program["y"]}
case (DEC) {1}
case (DOUBLE) {2}
}
)Code");
int (* main)() = (int (*)()) man->run();
int result = main();
ASSERT_EQ(5, result);
}
TEST(Interpretation, SwitchVariantAlias) {
xreate::XreateManager* man = xreate::XreateManager::prepare(
R"Code(
Command= type variant {
ADD(x::int, y::int),
DEC(x::int),
DOUBLE(x::int)
}.
main = function::int; entry(){
program = {ADD(2, 3), DEC(8)}::[Command]; i12n(on()).
switch variant(program[0]->program::Command)::int
case (ADD) {program["x"]+program["y"]}
case (DEC) {1}
case (DOUBLE) {2}
}
)Code");
int (* main)() = (int (*)()) man->run();
int result = main();
ASSERT_EQ(5, result);
}
TEST(Interpretation, Multiindex1) {
std::string script2 =
R"Code(
extract = function(program::unknType)::int; i12n(on()){
program["arguments"][1]
}
main = function::int; entry() {
x = {arguments = {10, 9, 8, 7}}:: unknType; i12n(on()).
extract(x)
}
)Code";
std::unique_ptr<XreateManager> man(XreateManager::prepare(std::move(script2)));
int (* main)() = (int (*)()) man->run();
int result = main();
ASSERT_EQ(9, result);
}
TEST(InterpretationExamples, Regexp1) {
FILE* input = fopen("scripts/dsl/regexp.xreate", "r");
assert(input != nullptr);
std::unique_ptr<XreateManager> man(XreateManager::prepare(input));
int (* main)() = (int (*)()) man->run();
int result = main();
ASSERT_EQ(4, result);
}
TEST(Interpretation, Variant1) {
std::string script =
R"Code(
DataPacked = type variant {
Var1(Num:: [int], String::string),
Var2(Num:: [int], String::string)
}.
extractInt = function(data::DataPacked):: int {
resultWrong = 0 :: int.
switch variant(data)::int
case (Var1) {data["Num", 0]}
case (Var2) {resultWrong}
}
main = function :: int; entry() {
dataActual = {10}:: [int].
dataPacked = Var1(dataActual, "whatever"):: DataPacked.
extractInt(dataPacked):: int; i12n(on())
}
)Code";
std::unique_ptr<XreateManager> man(XreateManager::prepare(std::move(script)));
int (* main)() = (int (*)()) man->run();
int result = main();
ASSERT_EQ(10, result);
}
TEST(Interpretation, Doc_Intr_1) {
string example = getDocumentationExampleById("documentation/Concepts/interpretation.xml", "Intr_1");
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(move(example));
man->analyse();
InterpretationPass* pass;
if(man->isPassRegistered(PassId::InterpretationPass)) {
pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass);
} else {
pass = new InterpretationPass(man);
pass->run();
}
int (* main)() = (int (*)()) man->run();
int result = main();
ASSERT_EQ(0, result);
}
TEST(Interpretation, Doc_FnIntr_1) {
string example1 = getDocumentationExampleById("documentation/Concepts/interpretation.xml", "FnIntr_1");
string example2 = getDocumentationExampleById("documentation/Concepts/interpretation.xml", "Alt_FnIntr_1");
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(move(example1));
man->analyse();
InterpretationPass* pass;
if(man->isPassRegistered(PassId::InterpretationPass)) {
pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass);
} else {
pass = new InterpretationPass(man);
pass->run();
}
unsigned char (* main)() = (unsigned char (*)()) man->run();
unsigned char result = main();
ASSERT_EQ(1, result);
XreateManager* man2 = XreateManager::prepare(move(example2));
ASSERT_TRUE(true);
}
TEST(Interpretation, Doc_FnIntr_2) {
string example = getDocumentationExampleById("documentation/Concepts/interpretation.xml", "FnIntr_2");
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(move(example));
man->analyse();
InterpretationPass* pass;
if(man->isPassRegistered(PassId::InterpretationPass)) {
pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass);
} else {
pass = new InterpretationPass(man);
pass->run();
}
unsigned char (* main)() = (unsigned char (*)()) man->run();
unsigned char result = main();
ASSERT_EQ(1, result);
}
TEST(Interpretation, Doc_FnIntr_3) {
string example = getDocumentationExampleById("documentation/Concepts/interpretation.xml", "FnIntr_3");
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(move(example));
man->analyse();
InterpretationPass* pass;
if(man->isPassRegistered(PassId::InterpretationPass)) {
pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass);
} else {
pass = new InterpretationPass(man);
pass->run();
}
InterpretationResolution resolutionActual = pass->process(man->root->findFunction("unwrap"));
ASSERT_EQ(ANY, resolutionActual);
unsigned char (* main)() = (unsigned char (*)()) man->run();
unsigned char result = main();
ASSERT_NE(0, result);
}
TEST(Interpretation, Doc_LateIntr_1) {
string example = getDocumentationExampleById("documentation/Concepts/interpretation.xml", "LateIntr_1");
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(move(example));
man->analyse();
InterpretationPass* pass;
if(man->isPassRegistered(PassId::InterpretationPass)) {
pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass);
} else {
pass = new InterpretationPass(man);
pass->run();
}
int (* main)(int) = (int (*)(int)) man->run();
int result = main(1);
ASSERT_EQ(2, result);
}
TEST(Interpretation, Doc_LateIntr_2) {
string example = getDocumentationExampleById("documentation/Concepts/interpretation.xml", "LateIntr_2");
string example2 = getDocumentationExampleById("documentation/Concepts/interpretation.xml", "Alt_LateIntr_2");
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(move(example));
man->analyse();
InterpretationPass* pass;
if(man->isPassRegistered(PassId::InterpretationPass)) {
pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass);
} else {
pass = new InterpretationPass(man);
pass->run();
}
const ManagedFnPtr &funcMain = man->root->findFunction("main");
InterpretationData &dataBody = Attachments::get<InterpretationData>(funcMain);
ASSERT_EQ(FOLD_INTERPRET_INPUT, dataBody.op);
int (* main)(int) = (int (*)(int)) man->run();
int result = main(10);
ASSERT_EQ(21, result);
XreateManager* man2 = XreateManager::prepare(move(example2));
ASSERT_TRUE(true);
}
TEST(Interpretation, Doc_LateFnIntr_1) {
string example = getDocumentationExampleById("documentation/Concepts/interpretation.xml", "LateFnIntr_1");
string example2 = getDocumentationExampleById("documentation/Concepts/interpretation.xml", "Alt_LateFnIntr_1");
xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(move(example));
man->analyse();
if(!man->isPassRegistered(PassId::InterpretationPass)) {
InterpretationPass* pass = new InterpretationPass(man);
pass->run();
}
int (* main)(int) = (int (*)(int)) man->run();
int result = main(10);
ASSERT_EQ(21, result);
XreateManager* man2 = XreateManager::prepare(move(example2));
ASSERT_TRUE(true);
}
//TOTEST call indirect recursion(w/o tags)
//TASk implement and test Loop Inf (fix acc types in coco grammar)
diff --git a/cpp/tests/polymorph.cpp b/cpp/tests/polymorph.cpp
index bc35f39..4b847bc 100644
--- a/cpp/tests/polymorph.cpp
+++ b/cpp/tests/polymorph.cpp
@@ -1,266 +1,266 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* polymorph.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on October 11, 2017, 8:37 PM
*/
#include "xreatemanager.h"
#include "ast.h"
#include "transcendlayer.h"
#include "aux/latereasoning.h"
#include <list>
#include "gtest/gtest.h"
#include "query/polymorph.h"
#include "supplemental/docutils.h"
#include "supplemental/basics.h"
using namespace xreate;
using namespace xreate::latereasoning;
using namespace xreate::polymorph;
using namespace std;
TEST(Polymorphs, ast1) {
xreate::XreateManager* man = xreate::XreateManager::prepare(R"CODE(
global-ann = type predicate {
entry
}
context-ann = type predicate {
a, b
}
guard(::a) {
test = function:: int {0}
}
guard(::b) {
test = function:: int {1}
}
main = function:: int; entry() { test() }
)CODE");
const std::list<ManagedFnPtr>& specs = man->root->getFnSpecializations("test");
ASSERT_EQ(2, specs.size());
auto itSpecs = specs.begin();
ASSERT_EQ("a", (*itSpecs)->guard.getValueString());
itSpecs++;
ASSERT_EQ("b", (*itSpecs)->guard.getValueString());
}
TEST(Polymorphs, Compile1){
xreate::XreateManager* man = xreate::XreateManager::prepare(R"CODE(
global-ann = type predicate {
entry, guarded(value::int)
}
context-ann = type predicate {
first(value::int), second
}
guard(data::first) {
test = function:: int {data["value"]}
}
guard(::second) {
test = function:: int {1}
}
main = function:: int; entry()
{
x = 8:: int.
test()::int; guarded(x)
}
)CODE");
man->transcend->addRawScript(R"(func_supply_guard(Site, first(Data), "context-ann"):- bind(Site, guarded(Data)).)");
man->run();
}
TEST(Polymorphs, Compile2){
xreate::XreateManager* man = xreate::XreateManager::prepare(R"CODE(
guard-pred = type predicate {
first(value::int), second
}
global-ann = type predicate {
entry, guarded(guard-pred)
}
guard(data ::first) {
test = function:: int {data["value"]}
}
guard(::second) {
test = function:: int {1}
}
main = function:: int; entry()
{
x = first(8):: guard-pred.
test()::int; guarded(x)
}
)CODE");
man->transcend->addRawScript(R"(func_supply_guard(Site, Guard, "guard-pred"):- bind(Site, guarded(Guard)).)");
man->run();
}
TEST(Polymorphs, CompileException1){
xreate::XreateManager* man = xreate::XreateManager::prepare(R"CODE(
Global-ann = type predicate {
entry
}
HandlerDivByZero = type {
ret:: int
}
Guards = type predicate {
fast,
safe(handlerZeroDiv:: HandlerDivByZero)
}
guard(:: fast) {
div = function(a::int, b::int) { a / b}
}
guard(handlers:: safe) {
div = function(a::int, b::int)::int
{
if (b != 0):: int
{a / b} else { handlers["handlerZeroDiv", "ret"] }
}
}
main = function:: int; entry()
{
handler = { ret = 11 } ::HandlerDivByZero.
div(8, 0):: int; safe(handler)
}
)CODE");
man->transcend->addRawScript(R"(func_supply_guard(Site, Guard, "Guards"):- bind(Site, Guard).)");
FnNoArgs fn = (FnNoArgs) man->run();
int result = fn();
ASSERT_EQ(11, result);
}
//TEST(Polymorphs, PolymorphQuery_Static_1) {
// xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(
// R"CODE(
// import raw("scripts/dfa/polymorphism.lp").
//
// guard:: a {
// test = function:: int {0}
// }
//
// guard:: b {
// test = function:: int {1}
// }
//
// main = function:: int; entry { test()::int; callguard(b); dfa_polym(ret)}
//
//)CODE");
//
// man->analyse();
// PolymorphQuery* query = dynamic_cast<PolymorphQuery*> (man->transcend->getQuery(QueryId::PolymorphQuery));
//
// const Expression& bodyE = man->root->findFunction("main")->getEntryScope()->getBody();
// LateAnnotation decisionLA = query->get(bodyE);
// ASSERT_EQ(1, decisionLA.guardedContent.size());
//
// auto decisionOptSymb = decisionLA.select({}, man->root, man->transcend);
// ASSERT_TRUE(decisionOptSymb);
//
// decisionOptSymb->print(cout);
// cout << endl;
// string guard = query->getValue(*decisionOptSymb).getValueString();
// ASSERT_STREQ("b", guard.c_str());
//}
//
//TEST(Polymorphs, PolymorphQuery_Late_1){
// xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare(
//R"CODE(
// Late = type variant{a, b}.
// main = function:: int; entry{key= a():: Late; test. key::int}
//)CODE");
//
// man->transcend->addRawScript(
//R"RULE(
// late(S, S, a, dfa_callguard(S, a)):-
// bind(S, test).
//
// late(S, S, b, dfa_callguard(S, b)):-
// bind(S, test).
//)RULE");
// man->analyse();
// PolymorphQuery* query = dynamic_cast<PolymorphQuery*> (man->transcend->getQuery(QueryId::PolymorphQuery));
//
// CodeScope* scopeMain = man->root->findFunction("main")->getEntryScope();
-// Symbol keyS = Symbol{scopeMain->getSymbol("key"), scopeMain};
+// Symbol keyS = Symbol{scopeMain->findSymbolByAlias("key"), scopeMain};
//
// Expression keyE = scopeMain->getDefinition(keyS);
// latereasoning::LateAnnotation answerLA = query->get(keyE);
// Expression valueB(Operator::VARIANT, {}); valueB.setValueDouble(1);
// auto answerRaw = answerLA.select({valueB}, man->root, man->transcend);
// ASSERT_TRUE(answerRaw);
// Expression answerE = query->getValue(*answerRaw);
// ASSERT_STREQ("b", answerE.getValueString().c_str());
//}
//
//TEST(Polymorphs, PSCU_1){
// auto man = details::tier1::XreateManager::prepare(R"Code(
// Dom = type variant {guard1, guard2}.
//
// guard:: guard1 {
// compute = function :: int
// {0}
// }
//
// guard:: guard2 {
// compute = function :: int
// {1}
// }
//
// test = function:: int; entry
// {
// xLate = guard2():: Dom.
// y1= switch late (xLate:: Dom; alias(xLate)):: int
// {
// compute():: int; guardkey(xLate)
// }.
// y1
// }
// )Code");
//
// man->transcend->addRawScript(R"RAW(
// dom(guard1; guard2).
// late(Target, Key, Variant, dfa_callguard(Target, Variant)):-
// bind(Target, guardkey(Alias));
// bind(Key, alias(Alias));
// dom(Variant).
// )RAW");
// man->analyse();
// int (*program)() = (int (*)())man->run();
// int result = program();
//
// ASSERT_EQ(1, result);
//}
//
//TEST(Polymorphs, Doc_FnLvlPoly_1){
// string example = getDocumentationExampleById("documentation/Concepts/polymorphism.xml", "FnLvlPoly_1");
// auto man = XreateManager::prepare(move(example));
// ASSERT_TRUE(true);
//}
//
//TEST(Polymorphs, Doc_LatePoly_1){
// string example = getDocumentationExampleById("documentation/Concepts/polymorphism.xml", "LatePoly_1");
// auto man = XreateManager::prepare(move(example));
// ASSERT_TRUE(true);
//}
\ No newline at end of file
diff --git a/cpp/tests/types.cpp b/cpp/tests/types.cpp
index 5592981..05f671f 100644
--- a/cpp/tests/types.cpp
+++ b/cpp/tests/types.cpp
@@ -1,311 +1,311 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* types.cpp
*
* Created on: Jun 4, 2015
* Author: pgess <v.melnychenko@xreate.org>
*/
#include "gtest/gtest.h"
#include "xreatemanager.h"
#include "llvmlayer.h"
#include "main/Parser.h"
#include "transcendlayer.h"
#include "analysis/typeinference.h"
#include "analysis/utils.h"
using namespace std;
using namespace xreate;
using namespace xreate::grammar::main;
TEST(Types, DependantTypes1) {
string&& code = "XmlNode = type {\n"
" tag:: string,\n"
" attrs:: [string], \n"
" content:: string\n"
"}.\n";
std::unique_ptr<XreateManager> program(XreateManager::prepare(move(code)));
ExpandedType typeXmlNode = program->root->findType("XmlNode");
ASSERT_EQ(TypeOperator::RECORD, typeXmlNode->__operator);
ASSERT_EQ(3, typeXmlNode->__operands.size());
ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(0).__value);
ASSERT_EQ(TypeOperator::ARRAY, typeXmlNode->__operands.at(1).__operator);
ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(2).__value);
}
TEST(Types, ast_ParameterizedTypes_FeatureTypeIndex_1) {
string&& code = "XmlNode = type {\n"
" tag:: string,\n"
" attrs:: [string],\n"
" content:: string\n"
"}.\n"
""
"Template = type(Leaf) {Leaf, [Leaf[\"content\"]]}."
"Concrete = type Template(XmlNode).";
std::unique_ptr<XreateManager> program(XreateManager::prepare(move(code)));
ExpandedType typeConcrete = program->root->findType("Concrete");
ASSERT_EQ(TypeOperator::RECORD, typeConcrete->__operator);
ASSERT_EQ(2, typeConcrete->__operands.size());
ASSERT_EQ(TypeOperator::RECORD, typeConcrete->__operands.at(0).__operator);
ASSERT_EQ(TypeOperator::ARRAY, typeConcrete->__operands.at(1).__operator);
ASSERT_EQ(TypePrimitive::String, typeConcrete->__operands.at(1).__operands.at(0).__value);
}
TEST(Types, TreeType1) {
string&& code = "XmlNode = type {\n"
" tag:: string,\n"
" attrs:: [string],\n"
" content:: string\n"
"}.\n"
""
"Tree = type(Leaf) {Leaf, [Tree(Leaf)]}."
"Concrete = type Tree(XmlNode).";
std::unique_ptr<XreateManager> program(XreateManager::prepare(move(code)));
ExpandedType typeConcrete = program->root->findType("Concrete");
ASSERT_EQ(TypeOperator::RECORD, typeConcrete->__operator);
ASSERT_EQ(2, typeConcrete->__operands.size());
ASSERT_EQ(TypeOperator::RECORD, typeConcrete->__operands.at(0).__operator);
ASSERT_EQ(TypeOperator::ARRAY, typeConcrete->__operands.at(1).__operator);
auto typeLink = typeConcrete->__operands.at(1).__operands.at(0);
// ASSERT_EQ(TypeOperator::LINK, typeLink.__operator);
// ASSERT_EQ(typeConcrete->linkId, typeLink.linkId);
}
TEST(Types, TreeType1LLvm) {
string&& code = "XmlNode = type {\n"
" tag:: string,\n"
" /* attrs:: [string],*/\n"
" content:: string\n"
"}.\n"
""
"Tree = type(Leaf) {Leaf, [Tree(Leaf)]}."
"Concrete = type Tree(XmlNode).";
std::unique_ptr<XreateManager> program(XreateManager::prepare(move(code)));
ExpandedType typeConcrete = program->root->findType("Concrete");
llvm::Type* raw = program->llvm->toLLVMType(typeConcrete);
}
TEST(Types, ArrayOfExternal1) {
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 ExpandedType& t2 = ast->getType(body->getDefinition(body->getSymbol("childrenRaw")));
+ const ExpandedType& t2 = ast->getType(body->getDefinition(body->findSymbolByAlias("childrenRaw")));
EXPECT_EQ(t2->__operator, TypeOperator::ARRAY);
}
TEST(Types, ExternType1) {
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 ExpandedType& t2 = ast->getType(body->getDefinition(body->getSymbol("tree")));
+ const ExpandedType& t2 = ast->getType(body->getDefinition(body->findSymbolByAlias("tree")));
EXPECT_EQ(t2->__operator, TypeOperator::ALIAS);
}
TEST(Types, ast_VariantType1) {
string&& code =
" colors = type variant {RED, BLUE, GREEN}.\n"
" test = function:: colors; entry {GREEN()}";
std::unique_ptr<XreateManager> program(XreateManager::prepare(move(code)));
ExpandedType typ = program->root->findType("colors");
EXPECT_EQ(TypeOperator::VARIANT, typ->__operator);
Expression eRed = program->root->findFunction("test")->getEntryScope()->getBody();
EXPECT_EQ(Operator::VARIANT, eRed.op);
const ExpandedType& typ2 = program->root->getType(eRed);
EXPECT_EQ(TypeOperator::VARIANT, typ2->__operator);
}
TEST(Types, full_VariantType_Switch1) {
string&& code =
"colors = type variant{RED, BLUE, GREEN}. \n"
" test = function:: colors {GREEN()} \n"
"main = function:: int; entry { \n"
" switch(test()):: int \n"
" case (GREEN()) {0} \n"
" case default {1} \n"
"}";
XreateManager* man = XreateManager::prepare(move(code));
int (*main)() = (int (*)()) man->run();
EXPECT_EQ(0, main());
}
TEST(Types, ast_VariantType2) {
std::string script =
R"Code(
Annotation = type
variant {
Num(int),
String(string),
Func(name::string, arguments::[Expression])
}.
)Code";
std::unique_ptr<XreateManager> program(XreateManager::prepare(move(script)));
ExpandedType typ = program->root->findType("Annotation");
ASSERT_EQ(3, typ.get().fields.size());
}
TEST(Types, SlaveTypes_UnwrapSlaveType1) {
auto man = details::tier1::XreateManager::prepare(R"Code(
AtomNumT = type slave atomNumT.
AtomStrT = type slave atomStrT.
CmpndIntStrT = type slave cmpndIntStrT.
VariantT = type slave variantT.
VariantComplicatedT = type slave variantComplicatedT.
)Code");
man->transcend->addRawScript(R"RAW(
atomNumT(5). atomNumT(8).
atomStrT("a"). atomStrT("b").
cmpndIntStrT(1, "a").
cmpndIntStrT(2, "b").
variantT(first).
variantT(second).
variantT(third).
variantComplicatedT(first(1, "a")).
variantComplicatedT(second("b")).
)RAW");
man->analyse();
ExpandedType AtomNumT = man->root->findType("AtomNumT");
ASSERT_EQ(AtomNumT->__operator, TypeOperator::SLAVE);
ExpandedType ContentAtomNumT = analysis::dereferenceSlaveType(AtomNumT, man->transcend);
ASSERT_EQ(TypePrimitive::Int, ContentAtomNumT->__value);
ExpandedType AtomStrT = man->root->findType("AtomStrT");
ExpandedType ContentAtomStrT = analysis::dereferenceSlaveType(AtomStrT,
man->transcend);
ASSERT_EQ(TypePrimitive::String, ContentAtomStrT->__value);
ExpandedType CmpndIntStrT = man->root->findType("CmpndIntStrT");
ExpandedType ContentCmpndIntStrT = analysis::dereferenceSlaveType(CmpndIntStrT,
man->transcend);
ASSERT_EQ(TypeOperator::RECORD, ContentCmpndIntStrT->__operator);
ASSERT_EQ(2, ContentCmpndIntStrT->__operands.size());
ExpandedType VariantT = man->root->findType("VariantT");
ExpandedType ContentVariantT = analysis::dereferenceSlaveType(VariantT,
man->transcend);
ASSERT_EQ(TypeOperator::VARIANT, ContentVariantT->__operator);
ASSERT_EQ(3, ContentVariantT->fields.size());
ExpandedType VariantComplicatedT = man->root->findType("VariantComplicatedT");
ExpandedType ContentVariantComplicatedT = analysis::dereferenceSlaveType(VariantComplicatedT,
man->transcend);
ASSERT_EQ(TypeOperator::VARIANT, ContentVariantComplicatedT->__operator);
ASSERT_EQ(2, ContentVariantComplicatedT->fields.size());
ASSERT_EQ(2, ContentVariantComplicatedT->__operands.at(0).__operands.size());
}
TEST(Types, IndexNumber_1)
{
string&& code =
R"CODE(
Tuple = type {string, int}.
Int = type Tuple[1].
)CODE";
std::unique_ptr<XreateManager> program(XreateManager::prepare(move(code)));
ExpandedType typeInt = program->root->findType("Int");
}
TEST(Types, RecursiveTypes_1){
string&& code =
R"CODE(
Node = type {
data:: int,
next:: ref(Node)
}
)CODE";
std::string outputExpected = "{ i32, %Node* }";
std::unique_ptr<XreateManager> program(XreateManager::prepare(move(code)));
ExpandedType typNode = program->root->findType("Node");
llvm::Type* typNodeRaw = program->llvm->toLLVMType(typNode);
std::string outputActual;
llvm::raw_string_ostream os(outputActual);
typNodeRaw->print(os);
os.flush();
ASSERT_NE(std::string::npos, outputActual.find(outputExpected));
}
TEST(Types, RecursiveTypes_2){
string&& code =
R"CODE(
Tree = type(NodeData) variant {
LEAF(data:: NodeData),
GROUP(nodes:: [ref(Tree(NodeData))])
}
Guard = type variant {
a, b
}.
DecisionTree = type Tree(Guard).
)CODE";
std::string outputExpected = "{ i8, { { i8 } } ";
std::unique_ptr<XreateManager> program(XreateManager::prepare(move(code)));
ExpandedType typNode = program->root->findType("DecisionTree");
llvm::Type* typNodeRaw = program->llvm->toLLVMType(typNode);
std::string outputActual;
llvm::raw_string_ostream os(outputActual);
typNodeRaw->print(os);
os.flush();
cout << outputActual << endl;
ASSERT_NE(std::string::npos, outputActual.find(outputExpected));
}
TEST(Types, NestedList1){
string code = R"(
test = function:: int; entry()
{
x = {a = {b = 3}}:: {a:: {b:: int}}.
x["a", "b"]
}
)";
std::unique_ptr<XreateManager> program(XreateManager::prepare(move(code)));
program->run();
}
\ No newline at end of file
diff --git a/grammar/xreate.ATG b/grammar/xreate.ATG
index 307d0a6..80c548f 100644
--- a/grammar/xreate.ATG
+++ b/grammar/xreate.ATG
@@ -1,836 +1,837 @@
//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;
.)
"loop"
(
"map" lparen Expr<eIn> implic Ident<varEl>
(. e = Expression(Operator::MAP, {eIn}); .)
tagcolon ExprAnnotations<tagsEl> rparen tagcolon ExprAnnotations<e>
(.
e.addBindings({Atom<Identifier_t>(varEl)});
block->addBinding(Atom<Identifier_t>(varEl), move(tagsEl));
.)
BDecl<&*block>
(. e.addBlock(block); .)
| "fold" lparen Expr<eIn> implic Ident<varEl> tagcolon ExprAnnotations<tagsEl>
['|' Expr<eFilters> ] comma Expr<eAcc> implic Ident<varAcc>rparen
(.
e = Expression(Operator::FOLD, {eIn, eAcc});
e.addBindings({Atom<Identifier_t>(varEl), Atom<Identifier_t>(varAcc)});
.)
tagcolon ExprAnnotations<e>
(.
Expression varAccBindingE; varAccBindingE.type = e.type;
block->addBinding(Atom<Identifier_t>(varEl), move(tagsEl));
block->addBinding(Atom<Identifier_t>(varAcc), move(varAccBindingE));
.)
BDecl<&*block>
(. e.addBlock(block); .)
| lparen Expr<eAcc> implic Ident<varAcc> rparen
(.
e = Expression(Operator::FOLD_INF, {eAcc});
e.addBindings({Atom<Identifier_t>(varAcc)});
.)
tagcolon ExprAnnotations<e>
(.
Expression varAccBindingE; varAccBindingE.type = e.type;
block->addBinding(Atom<Identifier_t>(varAcc), move(varAccBindingE));
.)
BDecl<&*block>
(. e.addBlock(block); .)
).
// Switches
SwitchDecl<Expression& eSwitch, SwitchKind flagSwitchKind> = (. TypeAnnotation typ; eSwitch = Expression(Operator::SWITCH, {}); Expression eCondition; Expression tag;.)
"switch"
(
SwitchVariantDecl<eSwitch>
| SwitchLateDecl<eSwitch>
| lparen ExprTyped<eCondition> rparen tagcolon ExprAnnotations<eSwitch> (. eSwitch.operands.push_back(eCondition);.)
CaseDecl<eSwitch, flagSwitchKind> {CaseDecl<eSwitch, flagSwitchKind>}
)
.
CaseDecl<Expression& outer, SwitchKind flagSwitchKind> = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); Expression condition; .)
"case"
( IF(flagSwitchKind == SWITCH_META)
lparen MetaSimpExpr<condition> rparen BDecl<&*scope> (. Expression exprCase(Operator::CASE, {}); exprCase.addTags({condition}); exprCase.addBlock(scope); outer.addArg(move(exprCase));.)
| "default" BDecl<&*scope> (. Expression exprCase(Operator::CASE_DEFAULT, {});
exprCase.addBlock(scope);
outer.operands.insert(++outer.operands.begin(), exprCase); .)
| lparen CaseParams<&*scope> rparen (. ManagedScpPtr scopeBody = root->add(new CodeScope(&*scope)); Expression exprCase(Operator::CASE, {}); .)
BDecl<&*scopeBody> (. exprCase.addBlock(scope); exprCase.addBlock(scopeBody); outer.addArg(move(exprCase)); .)
).
CaseParams<CodeScope* scope> = (. Expression condition; Expression guard(Operator::LOGIC_AND, {}); pushContextScope(scope); .)
ExprTyped<condition> (. guard.addArg(Expression(condition)); .)
{comma ExprTyped<condition> (. guard.addArg(Expression(condition)); .)
} (. scope->setBody(guard); popContextScope(); .)
.
SwitchLateDecl<Expression& expr> =
(.
std::wstring aliasCondition; Expression exprCondition, aliasAnns;
expr = Expression(Operator::SWITCH_LATE, {});
ManagedScpPtr scope = root->add(new CodeScope(context.scope));
.)
"late" lparen Expr<exprCondition> [implic Ident<aliasCondition>] [tagcolon ExprAnnotations<aliasAnns>] rparen
tagcolon ExprAnnotations<expr> BDecl<&*scope>
(.
expr.addArg(Expression(exprCondition));
expr.addBlock(scope);
std::string alias;
if(aliasCondition.empty()){
if(exprCondition.__state != Expression::IDENT){
SemErr(coco_string_create("An identifier expected in the short form"));
return;
}
//Use exprCondition as identifier
alias = exprCondition.getValueString();
} else {
//Use aliasCondition
alias = Atom<Identifier_t>(move(aliasCondition)).get();
}
expr.addBindings({Atom<Identifier_t>(string(alias))});
scope->addBinding(Atom<Identifier_t>(move(alias)), move(aliasAnns));
.)
.
SwitchVariantDecl<Expression& expr> =
(. Expression varTested; std::wstring varAlias; bool flagAliasFound = false; expr = Expression(Operator::SWITCH_VARIANT, {}); .)
"variant" lparen Expr<varTested> [implic Ident<varAlias>
(. flagAliasFound = true; .)
] [tagcolon ExprAnnotations<varTested>] rparen tagcolon ExprAnnotations<expr>
(. expr.addArg(std::move(varTested));
if (flagAliasFound) {
expr.addBindings({Atom<Identifier_t>(varAlias)});
} else {
if(varTested.__state == Expression::IDENT){
expr.addBindings({Atom<Identifier_t>(string(varTested.getValueString()))});
}
}
.)
CaseVariantDecl<expr> {CaseVariantDecl<expr>}
.
CaseVariantDecl<Expression& expr> = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); std::wstring key; scope->addBinding(Atom<Identifier_t>(string(expr.bindings.front())), Expression()); .)
"case" lparen Ident<key> rparen (. expr.addArg(root->recognizeVariantConstructor(Atom<Identifier_t>(std::move(key)))); .)
BDecl<&*scope> (. expr.addBlock(scope); .)
.
IntrinsicDecl<Expression& outer>= (. std::wstring name; .)
"intrinsic"
(
Ident< name>
(. outer = Expression(Operator::CALL_INTRINSIC, {});
outer.setValue(Atom<Identifier_t>(name));
root->recognizeIntrinsic(outer);
.)
lparen [CalleeParams<outer>] rparen
| "query" (. outer = Expression(Operator::QUERY, {}); .)
(
"late" IntrinsicQueryLateDecl<outer>
| lparen [CalleeParams<outer>] rparen
)
).
IntrinsicQueryLateDecl<Expression& expr> =
(.
std::wstring predicateAlias; Expression predicateE, predicateAnns;
expr = Expression(Operator::QUERY_LATE, {});
ManagedScpPtr scope = root->add(new CodeScope(context.scope));
.)
lparen Expr<predicateE> implic Ident<predicateAlias> tagcolon ExprAnnotations<predicateAnns> rparen
tagcolon ExprAnnotations<expr> BDecl<&*scope>
(.
expr.addArg(move(predicateE));
expr.addBindings({Atom<Identifier_t>(wstring(predicateAlias))});
scope->addBinding(Atom<Identifier_t>(move(predicateAlias)), move(predicateAnns));
expr.addBlock(scope);
.)
.
SequenceDecl<Expression& sequence> = (. sequence = Expression(); sequence.setOp(Operator::SEQUENCE); ManagedScpPtr scope = root->add(new CodeScope(context.scope)); .)
"seq" BDecl<&*scope> (. sequence.blocks.push_back(&*scope); scope = root->add(new CodeScope(&*scope)); .)
{ (. scope = root->add(new CodeScope(&*scope)); .)
BDecl<&*scope> (. sequence.blocks.push_back(&*scope); .)
}.
/*============================ INTERFACES ===============================*/
Imprt<> =
"import" "raw" lparen string (. root->__rawImports.push_back(Atom<String_t>(t->val).get()); .)
rparen period.
InterfaceData<> = "interface" lparen
( "dfa" rparen InterfaceDFA
// | "extern-c" rparen InterfaceExternC
| "cfa" rparen InterfaceCFA
).
// InterfaceExternC<> = (. ExternData data; .)
// lcurbrack {ExternHeadersDecl<data> | ExternAliasDecl<data> } rcurbrack
// (. root->addExternData(move(data)); .)
// .
//
// ExternPkgDecl<std::wstring& package> =
// "pkgconfig" lparen
// string (. package = t->val.)
// rparen
// .
//
// ExternAliasDecl<ExternData& data> = (. std::wstring alias, package; .)
// Ident<alias> assign "library" lparen ExternPkgDecl<package> rparen period
// (. data.addLibAlias(Atom<Identifier_t>(alias), Atom<String_t>(package)); .)
// .
//
// ExternHeadersDecl<ExternData& data> = (. std::list<std::string> listInc; std::wstring& package; .)
// "include"
// [lparen
// (
// Ident<alias> (. data.requireLibAlias(Atom<Identifier_t>(alias)); .)
// | ExternPkgDecl<package> (. data.requireLibPackage(Atom<String_t>(package)); .)
// )
// rparen]
// lcurbrack { string (. listInc.push_back(Atom<String_t>(t->val).get()); .)
// [comma] } rcurbrack [period] (. data.requireHeaders(listInc); .)
// .
InterfaceDFA<> = lcurbrack { InstructDecl } rcurbrack .
InstructDecl = (.Operator op; Expression tag;
Expression scheme;
std::vector<Expression>& tags = scheme.operands;
tags.push_back(Expression()); /* return value */ .)
"operator" InstructAlias<op> tagcolon lparen (.scheme.setOp(op); .)
[
MetaSimpExpr<tag> (. tags.push_back(tag); .)
{
comma MetaSimpExpr<tag> (. tags.push_back(tag); .)
}
] rparen [ implic MetaSimpExpr<tag> (. tags[0] = tag; .)
] (. root->addDFAData(move(scheme)); .)
period.
InstructAlias<Operator& op> =
(
"map" (. op = Operator::MAP; .)
| "list_range" (. op = Operator::LIST_RANGE; .)
| "list" (. op = Operator::LIST; .)
| "fold" (. op = Operator::FOLD; .)
| "index" (. op = Operator::INDEX; .)
).
InterfaceCFA<> = lcurbrack { InstructCFADecl } rcurbrack .
InstructCFADecl<> = (.Operator op; Expression tag;
Expression scheme;
std::vector<Expression>& tags = scheme.operands; .)
"operator" InstructAlias<op> tagcolon (. scheme.setOp(op); .)
[
MetaSimpExpr<tag> (. tags.push_back(tag); .)
{
comma MetaSimpExpr<tag> (. tags.push_back(tag); .)
}
] period (. root->addInterfaceData(CFA, move(scheme)); .).
/*============================ METAPROGRAMMING ===============================*/
// TagsDecl<CodeScope* f> = (. Expression tag; TagModifier mod = TagModifier::NONE; .)
// ':' { MetaSimpExpr<tag> (. /*f.addTag(std::move(tag), mod); */ .)
// }.
FnTag<Function* f> = (. Expression tag; TagModifier mod = TagModifier::NONE; .)
MetaSimpExpr<tag>
['-' TagMod<mod>] (. f->addTag(std::move(tag), mod); .).
TagMod<TagModifier& mod> =
( "assert" (. mod = TagModifier::ASSERT; .)
| "require" (. mod = TagModifier::REQUIRE; .)
).
// RuleDecl<> =
// "rule" tagcolon (. RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg; .)
// lparen Ident<arg> tagcolon Domain<typ> (. args.add(arg, typ); .)
// {comma Ident<arg> tagcolon Domain<typ> (. args.add(arg, typ); .)
// } rparen
// ["case" RGuard<guards> {comma RGuard<guards>}]
// lcurbrack RBody<args, guards> rcurbrack .
/* - TODO use RGuard for guards-*/
// RuleContextDecl<CodeScope* scope> = (.Expression eHead, eGuards, eBody; .)
// "rule" "context" tagcolon MetaSimpExpr<eHead>
// "case" lparen MetaSimpExpr<eGuards> rparen
// lcurbrack MetaSimpExpr<eBody> rcurbrack (.scope->contextRules.push_back(Expression(Operator::CONTEXT_RULE, {eHead, eGuards, eBody})); .).
// Domain<DomainAnnotation& dom> =
// (
// "function" (. dom = DomainAnnotation::FUNCTION; .)
// | "variable" (. dom = DomainAnnotation::VARIABLE; .)
// ).
// RGuard<RuleGuards& guards>= (. Expression e; .)
// MetaExpr<e> (. guards.add(std::move(e)); .).
// MetaExpr<Expression& e>= (.Operator op; Expression e2; .)
// MetaExpr2<e>
// [MetaOp<op> MetaExpr2<e2> (. e = Expression(op, {e, e2}); .)
// ].
// MetaExpr2<Expression& e>=
// (
// lparen MetaExpr<e> rparen
// | MetaSimpExpr<e>
// ).
MetaSimpExpr<Expression& e>= (. std::wstring i1, infix; Expression e2; .)
(
'-' MetaSimpExpr<e2> (. e = Expression(Operator::NEG, {e2}); .)
| IF(checkParametersList()) Ident<i1>
(. e = Expression(Operator::CALL, {Expression(Atom<Identifier_t>(i1))});
if (!root->recognizeVariantConstructor(e))
SemErr({L"Undefined predicate: ", i1});
.)
lparen [ MetaCalleeParams<e> ] rparen
| IF(checkInfix()) Ident<i1> Ident<infix> MetaSimpExpr<e2>
(. e = Expression(Operator::CALL, {Expression(Atom<Identifier_t>(infix))});
e.addArg(Expression(Atom<Identifier_t>(i1)));
e.addArg(std::move(e2));
.)
| IdentR<e>
| number (. e = Expression(Atom<Number_t>(t->val)); .)
).
MetaCalleeParams<Expression& e> = (. Expression e2; .)
MetaSimpExpr<e2> (. e.addArg(Expression(e2)); .)
{comma MetaSimpExpr<e2> (. e.addArg(Expression(e2)); .)
}.
// RBody<const RuleArguments& args, const RuleGuards& guards> =
// (. Expression e; std::wstring msg; .)
// "warning" MetaExpr<e> ["message" string (. msg = t->val; .)
// ] (. root->add(new RuleWarning(RuleArguments(args), RuleGuards(guards), std::move(e), Atom<String_t>(msg))); .)
// .
// MetaOp< Operator& op> =
// implic (. op = Operator::IMPL; .)
// .
/*============================ Expressions ===============================*/
ExprAnnotations<Expression& e> = (. TypeAnnotation typ; std::list<Expression> tags; Expression tag; e.tags.clear();.)
Type<typ> (. e.bindType(move(typ)); .)
{';' MetaSimpExpr<tag> (. tags.push_back(tag); .)
} (. e.addTags(tags); .)
.
ExprTyped<Expression&e> = Expr<e> [tagcolon ExprAnnotations<e>].
Expr< Expression& e> (. Expression e2; .)
= ExprLogicAnd<e>
[ ("or" | "OR") Expr<e2> (. e = Expression(Operator::OR, {e, e2}); .)
]
.
ExprLogicAnd< Expression& e> (. Expression e2; .)
= ExprRel<e>
[ ("and" | "AND") ExprLogicAnd <e2> (. e = Expression(Operator::AND, {e, e2}); .)
]
.
ExprRel< Expression& e> (. Operator op; Expression e2; .)
= ExprArithmAdd<e>
[ RelOp<op> ExprRel<e2> (. e = Expression(op, {e, e2}); .)
]
.
ExprArithmAdd< Expression& e>= (. Operator op; Expression e2; .)
ExprArithmMul< e>
[
AddOp<op>ExprArithmAdd< e2> (. e = Expression(op, {e, e2});.)
].
ExprArithmMul< Expression& e> (. Operator op; Expression e2; .)
= ExprUpdate<e>
[ MulOp< op>
ExprArithmMul< e2> (. e = Expression(op, {e, e2}); .)
].
ExprUpdate<Expression& e>= (. Expression e2; .)
ExprPostfix< e>
[
colon
( IF(checkListIndex()) ListIndexLiteral<e2>
| ListLiteral<e2>) (. e = Expression(Operator::UPDATE, {e, e2}); .)
].
ExprPostfix<Expression& e>
= Term<e>
[ (. e = Expression(Operator::INDEX, {e}); .)
{lbrack CalleeParams<e> rbrack }
].
Term< Expression& e> (. std::wstring name; e = Expression(); .)
=
(IF (checkParametersList()) Ident< name>
(. e = Expression(Operator::CALL, {Atom<Identifier_t>(name)}); root->recognizeVariantConstructor(e); .)
lparen [CalleeParams<e>] rparen
| IdentVR<e>
| ListLiteral<e>
| ListRangeLiteral<e>
| LoopDecl<e>
| IfDecl<e>
| SwitchDecl<e, SWITCH_NORMAL>
| IntrinsicDecl<e>
| SequenceDecl<e>
| number (. e = Expression(Atom<Number_t>(t->val)); .)
| string (. e = Expression(Atom<String_t>(t->val)); .)
| "true" (. e = Expression(Atom<Number_t>(1)); e.bindType(TypePrimitive::Bool); .)
| "false" (. e = Expression(Atom<Number_t>(0)); e.bindType(TypePrimitive::Bool); .)
| "undef" (. e = Expression(Operator::UNDEF, {}); .)
| '-' Term<e> (. e = Expression(Operator::NEG, {e}); .)
| lparen ExprTyped<e> rparen
).
ListLiteral<Expression& e> = (. std::wstring key;
Expression val;
std::list<Atom<Identifier_t>> keys;
e = Expression(Operator::LIST, {});
.)
lcurbrack {
( IF(checkTokenAfterIdent(_assign)) Ident<key> assign
| (. key = L""; .)
) Expr<val> (. keys.push_back(Atom<Identifier_t>(key));
e.operands.push_back(val);
.)
[comma] } rcurbrack (. e.addBindings(keys.begin(), keys.end()); .)
.
ListIndexLiteral<Expression& e> = (. e = Expression(Operator::LIST_INDEX, {});Expression valE;.)
lcurbrack
{ (. Expression idxE(Operator::LIST, {});.)
lbrack CalleeParams<idxE> rbrack
assign Expr<valE>[comma] (. e.operands.push_back(idxE); e.operands.push_back(valE); .)
}
rcurbrack
.
ListRangeLiteral<Expression& e> = (. Expression eFrom, eTo; .)
lbrack Expr<eFrom> ".." Expr<eTo> rbrack (. e = Expression(Operator::LIST_RANGE, {eFrom, eTo}); .)
.
CalleeParams<Expression& e> = (. Expression e2; .)
ExprTyped<e2> (. e.addArg(Expression(e2)); .)
{comma ExprTyped<e2> (. e.addArg(Expression(e2)); .)
}.
AddOp< Operator& op>
= (. op = Operator::ADD; .)
( '+'
| '-' (. op = Operator::SUB; .)
).
MulOp< Operator& op>
= (. op = Operator::MUL; .)
( '*'
| '/' (. op = Operator::DIV; .)
| '%' (. op = Operator::MOD; .)
).
RelOp< Operator& op>
= (. op = Operator::EQU; .)
( equal
| (ne1 | ne2) (. op = Operator::NE; .)
| lse (. op = Operator::LSE; .)
| lss (. op = Operator::LSS; .)
| gte (. op = Operator::GTE; .)
| gtr (. op = Operator::GTR; .)
).
SkipModulesSection = "module" {ANY} (lcurbrack {ANY} rcurbrack | '.').
END Xreate.
diff --git a/scripts/compilation/llvmaliases.xreate b/scripts/compilation/llvmaliases.xreate
new file mode 100644
index 0000000..e02cbaf
--- /dev/null
+++ b/scripts/compilation/llvmaliases.xreate
@@ -0,0 +1,5 @@
+Rec = type {x:: int, y:: int}.
+
+test = function(a:: int, b::int):: Rec; entry() {
+ {x = a + b, y = 2}
+}
Event Timeline
Log In to Comment