No OneTemporary

File Metadata

Created
Sat, Mar 14, 4:44 AM
diff --git a/config/default.json b/config/default.json
index f928097..807e420 100644
--- a/config/default.json
+++ b/config/default.json
@@ -1,69 +1,69 @@
{
"containers": {
"id": {
"implementations": "impl_fulfill_cluster",
"clusters": "var_cluster",
"prototypes": "proto_cluster",
"linkedlist": "linkedlist"
},
"impl": {
"solid": "solid",
"onthefly": "on_the_fly"
}
},
"logging": {
"id": "logging"
},
"function-entry": "entry",
"clasp": {
"bindings" : {
"variable": "bind",
"function": "bind_func",
"scope": "bind_scope",
"function_demand" : "bind_function_demand",
"scope_decision": "bind_scope_decision"
},
"context" : {
"decisions":{
"dependent": "resolution_dependency"
},
},
"nonevalue": "nonevalue",
"ret": {
"symbol": "retv",
"tag": "ret"
}
},
"tests": {
"template": "default",
"templates": {
"default": "*-",
"adhocs": "Adhoc.*",
"effects": "Effects.*",
"basic": "Attachments.*",
"ast": "AST.*",
"cfa": "CFA.*",
"dfa": "DFA.*",
"compilation": "Compilation.functionEntry1*",
"diagnostic": "Diagnostic.*",
"ExpressionSerializer": "ExpressionSerializer.*",
"externc": "InterfaceExternC.*",
"types": "Types.*-",
"vendorsAPI/clang": "ClangAPI.*",
"vendorsAPI/xml2": "libxml2*",
- "dsl": "InterpretationExamples.*",
+ "dsl": "Interpretation.*:InterpretationExamples.*",
"context": "Context.*",
"containers": "Containers.*",
"loops": "Loop.*"
}
}
}
diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp
index 95f4f66..6a6cccf 100644
--- a/cpp/src/ast.cpp
+++ b/cpp/src/ast.cpp
@@ -1,890 +1,915 @@
#include "ast.h"
#include "ExternLayer.h"
#include <stdexcept>
#include <iostream>
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; }
}
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));
}
const std::string&
Atom<String_t>::get() const {
return __value;
}
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:
case Expression::VARIANT:
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:
case Expression::VARIANT:
return true;
case Expression::INVALID:
assert(false);
case Expression::IDENT:
case Expression::STRING:
case Expression::COMPOUND:
case Expression::BINDING:
return false;
}
return false;
}
};
class TypesResolver {
private:
const AST* ast;
std::map<std::string, TypeAnnotation> scope;
std::map<TypeAnnotation, int> signatures;
ExpandedType expandType(const TypeAnnotation &t, const std::vector<TypeAnnotation> &args = std::vector<TypeAnnotation>()) {
return TypesResolver(ast, scope, signatures)(t, args);
}
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 expandType(t);
});
return pack;
}
public:
TypesResolver(const AST* root, const std::map<std::string, TypeAnnotation>& scopeOuter = std::map<std::string, TypeAnnotation>(),
std::map<TypeAnnotation, int> signaturesOuter = std::map<TypeAnnotation, int>())
: ast(root), scope(scopeOuter), signatures(signaturesOuter) {
}
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 = expandType(t.__operands.at(0));
return ExpandedType(TypeAnnotation(tag_array, elTy, 0));
}
case TypeOperator::STRUCT:
{
assert(t.__operands.size());
std::vector<TypeAnnotation>&& pack = expandOperands(t.__operands);
auto tnew = TypeAnnotation(TypeOperator::STRUCT, move(pack));
tnew.fields = t.fields;
return ExpandedType(move(tnew));
};
case TypeOperator::CALL:
{
std::string alias = t.__valueCustom;
//find in local scope:
TypeAnnotation ty;
if (scope.count(alias)) {
ty = scope.at(alias);
} else if (ast->__indexTypeAliases.count(alias)) {
ty = ast->__indexTypeAliases.at(alias);
} else {
assert(false && "Undefined or external type");
}
std::vector<TypeAnnotation>&& operands = expandOperands(t.__operands);
TypeAnnotation signature(TypeOperator::CALL, move(operands));
signature.__valueCustom = alias;
if (signatures.count(signature)) {
auto link = TypeAnnotation(TypeOperator::LINK,{});
link.conjuctionId = signatures.at(signature);
return ExpandedType(move(link));
}
int cid = signatures.size();
signatures[signature] = cid;
TypeAnnotation tyResult = expandType(ty, operands);
tyResult.conjuctionId = cid;
return ExpandedType(move(tyResult));
};
case TypeOperator::CUSTOM:
{
std::string alias = t.__valueCustom;
/*
if (signatures.count(alias)) {
return ExpandedType(TypeAnnotation(TypeOperator::LINK, {t}));
}
signatures[alias].emplace(t);
*/
//find in local scope:
if (scope.count(alias)) {
return expandType(scope.at(alias));
}
// find in general scope:
if (ast->__indexTypeAliases.count(alias)) {
return expandType(ast->__indexTypeAliases.at(t.__valueCustom));
}
//if type is unknown keep it as is.
return ExpandedType(TypeAnnotation(t));
};
case TypeOperator::ACCESS:
{
std::string alias = t.__valueCustom;
ExpandedType tyAlias = ExpandedType(TypeAnnotation());
//find in local scope:
if (scope.count(alias)) {
tyAlias = expandType(scope.at(alias));
//find in global scope:
} else if ((ast->__indexTypeAliases.count(alias))) {
tyAlias = expandType(ast->__indexTypeAliases.at(alias));
} else {
assert(false && "Undefined or external type");
}
assert(tyAlias->__operator == TypeOperator::STRUCT);
for (const string& field : t.fields) {
auto fieldIt = std::find(tyAlias->fields.begin(), tyAlias->fields.end(), field);
assert(fieldIt != tyAlias->fields.end() && "unknown field");
int fieldId = fieldIt - tyAlias->fields.begin();
tyAlias = expandType(tyAlias->__operands.at(fieldId));
}
return tyAlias;
}
case TypeOperator::TUPLE:
{
assert(t.__operands.size());
std::vector<TypeAnnotation> pack;
pack.reserve(t.__operands.size());
std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(pack, pack.end()),
[this](const TypeAnnotation & t) {
return expandType(t);
});
return ExpandedType(TypeAnnotation(TypeOperator::TUPLE, move(pack)));
}
case TypeOperator::VARIANT:
{
return ExpandedType(TypeAnnotation(t));
}
case TypeOperator::NONE:
{
return ExpandedType(TypeAnnotation(t));
}
default:
assert(false);
}
assert(false);
return ExpandedType(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) {
}
TypeAnnotation::TypeAnnotation(llvm_array_tag, TypeAnnotation typ, int size)
: TypeAnnotation(TypeOperator::ARRAY,{typ}) {
__size = size;
}
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::CALL || __operator == TypeOperator::CUSTOM || __operator == TypeOperator::ACCESS) {
if (__valueCustom != t.__valueCustom)
return __valueCustom < t.__valueCustom;
}
return __operands < t.__operands;
}
/*
TypeAnnotation (struct_tag, std::initializer_list<TypeAnnotation>)
{}
*/
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::NONE; __valueD=number.get();
}
Expression::Expression(const Atom<String_t>& a)
: Expression(){
__state=STRING; op=Operator::NONE; __valueS=a.get();
}
Expression::Expression(const Atom<Identifier_t> &ident)
: Expression() {
__state=IDENT; op=Operator::NONE; __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::NONE:
__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);
}
Expression::Expression()
: __state(INVALID), op(Operator::NONE), id(nextVacantId++)
{ }
- 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;
- }
-
AST::AST() {
Attachments::init<VariableVersion>();
Attachments::init<Symbol>();
}
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 &&data) {
__externdata.insert(__externdata.end(), data.entries.begin(), data.entries.end());
}
void
AST::add(Function* f) {
__functions.push_back(f);
__indexFunctions.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) {
__dictVariants.emplace(t.fields[i], make_pair(t, i));
}
}
__indexTypeAliases.emplace(alias.get(), move(t));
}
ManagedScpPtr
AST::add(CodeScope* scope) {
this->__scopes.push_back(scope);
return ManagedScpPtr(this->__scopes.size() - 1, &this->__scopes);
}
std::string
AST::getModuleName() {
const std::string name = "moduleTest";
return name;
}
ManagedPtr<Function>
AST::findFunction(const std::string& name) {
int count = __indexFunctions.count(name);
if (!count) {
return ManagedFnPtr::Invalid();
}
assert(count == 1);
auto range = __indexFunctions.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::getFunctionVariants(const std::string& name) const {
auto functions = __indexFunctions.equal_range(name);
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);
}
Expanded<TypeAnnotation>
AST::expandType(const TypeAnnotation &t) const {
return TypesResolver(this)(t);
}
Expanded<TypeAnnotation>
AST::findType(const std::string& name) {
// find in general scope:
if (__indexTypeAliases.count(name))
return expandType(__indexTypeAliases.at(name));
//if type is unknown keep it as is.
TypeAnnotation t(TypeOperator::CUSTOM,{});
t.__valueCustom = name;
return ExpandedType(move(t));
}
bool
AST::recognizeVariantIdentifier(Expression& identifier) {
assert(identifier.__state == Expression::IDENT);
std::string variant = identifier.getValueString();
if (!__dictVariants.count(variant)) {
return false;
}
auto record = __dictVariants.at(variant);
const TypeAnnotation& typ = record.first;
identifier.__state = Expression::VARIANT;
identifier.setValueDouble(record.second);
identifier.type = typ;
return true;
}
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) {
__entry->addBinding(move(name), move(argument));
}
const std::string&
Function::getName() const {
return __name;
}
ScopedSymbol
CodeScope::registerIdentifier(const Expression& identifier) {
VariableVersion version = Attachments::get<VariableVersion>(identifier, VERSION_NONE);
auto result = __identifiers.emplace(identifier.getValueString(), __vCounter);
if (result.second){
++__vCounter;
return {__vCounter-1, version};
}
return {result.first->second, version};
}
bool
CodeScope::recognizeIdentifier(const Expression& identifier) const{
VariableVersion version = Attachments::get<VariableVersion>(identifier, VERSION_NONE);
const std::string& name = identifier.getValueString();
//search identifier in the current block
if (__identifiers.count(name)){
VNameId id = __identifiers.at(name);
Symbol s;
s.identifier = ScopedSymbol{id, version};
s.scope = const_cast<CodeScope*>(this);
Attachments::put<Symbol>(identifier, s);
return true;
}
//search in the parent scope
if (__parent)
{
return __parent->recognizeIdentifier(identifier);
}
return false;
}
ScopedSymbol
CodeScope::getSymbol(const std::string& alias){
assert(__identifiers.count(alias));
VNameId id = __identifiers.at(alias);
return {id, VERSION_NONE};
}
void
AST::postponeIdentifier(CodeScope* scope, const Expression& id) {
binUnrecognizedIdentifiers.emplace(scope, id);
}
void
AST::recognizePostponedIdentifiers() {
for(const auto& identifier: binUnrecognizedIdentifiers){
if (!identifier.first->recognizeIdentifier(identifier.second)){
//exception: Ident not found
std::cout << "Unknown symbol: "<< identifier.second.getValueString() << std::endl;
assert(false && "Symbol not found");
}
}
}
void
CodeScope::addBinding(Expression&& var, Expression&& argument) {
argument.__state = Expression::BINDING;
__bindings.push_back(var.getValueString());
ScopedSymbol binding = registerIdentifier(var);
__declarations[binding] = move(argument);
}
void
CodeScope::addDeclaration(Expression&& var, Expression&& body) {
ScopedSymbol s = registerIdentifier(var);
__declarations[s] = move(body);
}
CodeScope::CodeScope(CodeScope* parent)
: __parent(parent) {
}
CodeScope::~CodeScope() {
}
void
CodeScope::setBody(const Expression &body) {
__declarations[ScopedSymbol::RetSymbol] = body;
}
Expression&
CodeScope::getBody() {
return __declarations[ScopedSymbol::RetSymbol];
}
const Expression&
CodeScope::getDeclaration(const Symbol& symbol) {
CodeScope* self = symbol.scope;
return self->getDeclaration(symbol.identifier);
}
const Expression&
CodeScope::getDeclaration(const ScopedSymbol& symbol){
assert(__declarations.count(symbol) && "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(ClaspLayer& 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 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:
case Expression::VARIANT:
return a.getValueString() < b.getValueString();
case Expression::NUMBER:
return a.getValueDouble() < b.getValueDouble();
case Expression::COMPOUND:
{
- assert(a.op == Operator::CALL);
assert(a.blocks.size() == 0);
assert(b.blocks.size() == 0);
- if (a.operands.size() != b.operands.size()) {
- return (a.operands.size() < b.operands.size());
+ 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();
+ }
}
- 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, VERSION_NONE};
}
diff --git a/cpp/src/compilation/targetinterpretation.cpp b/cpp/src/compilation/targetinterpretation.cpp
index 937a400..047f4ef 100644
--- a/cpp/src/compilation/targetinterpretation.cpp
+++ b/cpp/src/compilation/targetinterpretation.cpp
@@ -1,436 +1,441 @@
/*
* File: targetinterpretation.cpp
* Author: pgess
*
* Created on June 29, 2016, 6:45 PM
*/
#include "compilation/targetinterpretation.h"
#include "pass/interpretationpass.h"
#include "llvmlayer.h"
#include "compilation/scopedecorators.h"
#include <boost/scoped_ptr.hpp>
#include <iostream>
#include <clang/AST/DeclBase.h>
using namespace std;
namespace xreate{ namespace compilation {
const Expression EXPRESSION_FALSE = Expression(Atom<Number_t>(0));
const Expression EXPRESSION_TRUE = Expression(Atom<Number_t>(1));
//Expression
//InterpretationScope::compile(const Expression& expression){}
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(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;
}
llvm::Value*
InterpretationScope::compileHybrid(const InterpretationOperator& op, const Expression& expression, const Context& context){
switch(op){
case IF_INTERPRET_CONDITION: {
CodeScope* scopeResult = processOperatorIf(expression);
llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile();
return result;
}
case SWITCH_INTERPRET_CONDITION:{
CodeScope* scopeResult = processOperatorSwitch(expression);
llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile();
return result;
}
case FOLD_INTERPRET_INPUT: {
//initialization
const Expression& exprInput = process(expression.getOperands()[0]);
assert(exprInput.op == Operator::LIST);
CodeScope* scopeBody = expression.blocks.front();
const string& nameEl = expression.bindings[0];
Symbol symbEl{ScopedSymbol{scopeBody->__identifiers.at(nameEl), VERSION_NONE}, scopeBody};
const std::string& idAccum = expression.bindings[1];
llvm::Value* rawAccum = context.scope->process(expression.getOperands()[1]);
InterpretationScope* intrBody = function->getScope(scopeBody);
auto unitBody = Decorators<CachedScopeDecoratorTag>::getInterface(context.function->getScopeUnit(scopeBody));
const std::vector<Expression> elementsInput= exprInput.getOperands();
for (size_t i=0; i<elementsInput.size(); ++i){
intrBody->reset();
unitBody->reset();
Expression exprElement = elementsInput[i];
intrBody->overrideBinding(exprElement, nameEl);
unitBody->overrideDeclaration(symbEl, move(exprElement));
unitBody->bindArg(rawAccum, string(idAccum));
rawAccum = unitBody->compile();
}
return rawAccum;
}
+ /*
+ case FOLD_INF_INTERPRET_INOUT{
+ }
+ */
+
case CALL_INTERPRET_PARTIAL: {
const std::string &calleeName = expression.getValueString();
AbstractCodeScopeUnit* scopeUnitSelf = context.scope;
ManagedFnPtr callee = this->function->man->ast->findFunction(calleeName);
const FunctionInterpretationData& calleeData = FunctionInterpretationHelper::getSignature(callee);
std::vector<llvm::Value *> argsActual;
PIFSignature 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->man);
PIFunction* pifunction = man->getFunction(move(sig));
llvm::Function* raw = pifunction->compile();
boost::scoped_ptr<CallStatementRaw> statement(new CallStatementRaw(raw, man->pass->man->llvm));
return (*statement)(move(argsActual));
}
default: break;
}
assert(false&& "Unknown hybrid operator");
return nullptr;
}
llvm::Value*
InterpretationScope::compile(const Expression& expression, const Context& context){
const InterpretationData& data = Attachments::get<InterpretationData>(expression);
if (data.op != InterpretationOperator::NONE){
return compileHybrid(data.op, expression, context);
}
Expression result = process(expression);
return context.scope->process(result);
}
Expression
InterpretationScope::process(const Expression& expression){
switch (expression.__state){
case Expression::INVALID:
assert(false);
case Expression::VARIANT:
case Expression::NUMBER:
case Expression::STRING:
return expression;
case Expression::IDENT:{
Symbol s = Attachments::get<Symbol>(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 = this->function->man->ast->findFunction(fnName);
InterpretationFunction* fnUnit = this->function->man->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::IF:{
CodeScope* scopeResult = processOperatorIf(expression);
return function->getScope(scopeResult)->processScope();
}
case Operator::SWITCH: {
CodeScope* scopeResult = processOperatorSwitch(expression);
return function->getScope(scopeResult)->processScope();
}
case Operator::INDEX: {
const Expression& exprKey = process(expression.operands[1]);
const Expression& exprData = process(expression.operands[0]);
if (exprKey.__state == Expression::STRING){
const string& key = exprKey.getValueString();
assert(exprData.__indexBindings.count(key));
return exprData.operands[exprData.__indexBindings.at(key)];
}
if (exprKey.__state == Expression::NUMBER){
int key = exprKey.getValueDouble();
return exprData.operands[key];
}
assert(false);
}
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->overrideBinding(exprInput.getOperands()[i], argEl);
body->overrideBinding(accum, argAccum);
accum = body->processScope();
}
return accum;
}
// case Operator::MAP: {
// break;
// }
default: break;
}
return expression;
}
InterpretationFunction*
TargetInterpretation::getFunction(FunctionUnit* unit){
if (__dictFunctionsByUnit.count(unit)) {
return __dictFunctionsByUnit.at(unit);
}
InterpretationFunction* f = new InterpretationFunction(unit->function, this);
__dictFunctionsByUnit.emplace(unit, f);
assert(__functions.emplace(unit->function.id(), f).second);
return f;
}
PIFunction*
TargetInterpretation::getFunction(PIFSignature&& sig){
auto f = __pifunctions.find(sig);
if (f != __pifunctions.end()){
return f->second;
}
PIFunction* result = new PIFunction(PIFSignature(sig), __pifunctions.size(), this);
__pifunctions.emplace(move(sig), result);
assert(__dictFunctionsByUnit.emplace(result->functionUnit, 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){
return transformContext(ctx)->compile(expression, ctx);
}
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);
for(size_t i=0, size = args.size(); i<size; ++i) {
body->overrideBinding(args.at(i), string(body->scope->__bindings.at(i)));
}
return body->processScope();
}
// Partial function interpretation
typedef BasicFunctionDecorator PIFunctionUnitParent;
class PIFunctionUnit: public PIFunctionUnitParent{
public:
PIFunctionUnit(ManagedFnPtr f, std::set<size_t>&& arguments, size_t id, CompilePass* p)
: PIFunctionUnitParent(f, p), argumentsActual(move(arguments)), __id(id)
{}
protected:
std::vector<llvm::Type*> prepareArguments(){
LLVMLayer* llvm = PIFunctionUnitParent::pass->man->llvm;
AST* ast = PIFunctionUnitParent::pass->man->root;
CodeScope* entry = PIFunctionUnitParent::function->__entry;
std::vector<llvm::Type*> signature;
for(size_t no: argumentsActual){
VNameId argId = entry->__identifiers.at(entry->__bindings.at(no));
ScopedSymbol arg{argId, VERSION_NONE};
signature.push_back(llvm->toLLVMType(ast->expandType(entry->__declarations.at(arg).type)));
}
return signature;
}
llvm::Function::arg_iterator prepareBindings(){
CodeScope* entry = PIFunctionUnitParent::function->__entry;
AbstractCodeScopeUnit* entryCompilation = PIFunctionUnitParent::getScopeUnit(entry);
llvm::Function::arg_iterator fargsI = PIFunctionUnitParent::raw->arg_begin();
for(size_t no: argumentsActual){
ScopedSymbol arg{entry->__identifiers.at(entry->__bindings.at(no)), VERSION_NONE};
entryCompilation->bindArg(&*fargsI, arg);
fargsI->setName(entry->__bindings.at(no));
++fargsI;
}
return fargsI;
}
virtual std::string prepareName(){
return PIFunctionUnitParent::prepareName() + "_" + std::to_string(__id);
}
private:
std::set<size_t> argumentsActual;
size_t __id;
};
PIFunction::PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target)
: InterpretationFunction(sig.declaration, target), signatureInstance(move(sig))
{
const FunctionInterpretationData& functionData = FunctionInterpretationHelper::getSignature(signatureInstance.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);
}
}
functionUnit = new PIFunctionUnit(signatureInstance.declaration, move(argumentsActual), id, target->pass);
CodeScope* entry = signatureInstance.declaration->__entry;
auto entryUnit = Decorators<CachedScopeDecoratorTag>::getInterface<>(functionUnit->getEntry());
InterpretationScope* entryIntrp = InterpretationFunction::getScope(entry);
for(size_t no=0, sigNo=0, size = entry->__bindings.size(); no < size; ++no){
if (functionData.signature.at(no) == INTR_ONLY){
entryIntrp->overrideBinding(signatureInstance.bindings[sigNo], entry->__bindings[no]);
VNameId argId = entry->__identifiers.at(entry->__bindings[no]);
Symbol argSymbol{ScopedSymbol{argId, VERSION_NONE}, entry};
entryUnit->overrideDeclaration(argSymbol, Expression(signatureInstance.bindings[sigNo]));
++sigNo;
}
}
}
llvm::Function*
PIFunction::compile(){
llvm::Function* raw = functionUnit->compile();
return raw;
}
bool operator<(const PIFSignature& lhs, const PIFSignature& rhs){
if (lhs.declaration.id() != rhs.declaration.id()) {
return lhs.declaration.id() < rhs.declaration.id();
}
return lhs.bindings < rhs.bindings;
}
bool operator<(const PIFSignature& lhs, PIFunction* const rhs){
return lhs < rhs->signatureInstance;
}
bool operator<(PIFunction* const lhs, const PIFSignature& rhs){
return lhs->signatureInstance < rhs;
}
}}
diff --git a/cpp/src/pass/interpretationpass.cpp b/cpp/src/pass/interpretationpass.cpp
index e75520f..f079129 100644
--- a/cpp/src/pass/interpretationpass.cpp
+++ b/cpp/src/pass/interpretationpass.cpp
@@ -1,423 +1,416 @@
/*
* File: interpretationpass.cpp
* Author: pgess
*
* Created on July 5, 2016, 5:21 PM
*/
#include "pass/interpretationpass.h"
//#include "compilation/transformations.h"
#include <compilation/targetinterpretation.h>
#include "ast.h"
//DEBT implement InterpretationPass purely in clasp
//DEBT represent InterpretationPass as general type inference
using namespace std;
namespace xreate{
enum InterpretationQuery{QUERY_INTR_ONLY, QUERY_CMPL_ONLY};
template<>
InterpretationResolution
defaultValue<InterpretationResolution>(){
return CMPL_ONLY;
}
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;
}
namespace detail {
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));
}
}
template<InterpretationQuery FLAG_REQUIRED>
bool checkConstraints(std::vector<InterpretationResolution>&& flags) {
assert(flags.size());
InterpretationResolution flag = flags.front();
return detail::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 (detail::checkConstraints<FLAG_REQUIRED_A>(flag)){
return checkConstraints<FLAG_REQUIRED_B, FLAGS...>(move(flags));
}
return false;
}
bool
InterpretationData::isDefault() const{
return (resolution == ANY && op == NONE);
}
namespace details {
InterpretationResolution
recognizeTags(const map<std::string, Expression>& tags){
auto i = tags.find("interpretation");
if (i== tags.end()){
return ANY;
}
assert(i->second.op == Operator::CALL);
const string& cmd = i->second.operands.at(0).getValueString();
//TODO make consistent names of annotation and resolution
if (cmd == "force"){
return INTR_ONLY;
} else if (cmd == "suppress"){
return CMPL_ONLY;
}
return ANY;
}
}
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<FunctionInterpretationData>();
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 op = NONE;
switch (expression.__state){
case Expression::VARIANT:
case Expression::NUMBER:
case Expression::STRING: {
break;
}
case Expression::IDENT: {
resolution = Parent::processSymbol(Attachments::get<Symbol>(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: {
//TODO cope with static/dynamic context
//TODO BUG here: if several variants they all are processed as CMPL careless of signature
list<ManagedFnPtr> callees = man->root->getFunctionVariants(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 FunctionInterpretationData& calleeSignature = FunctionInterpretationHelper::getSignature(callee);
for (size_t op=0, size = expression.operands.size(); op < size; ++op){
const Expression &operand = expression.operands[op];
InterpretationResolution argActual = process(operand, context);
InterpretationResolution argExpected = calleeSignature.signature[op];
//TODO use args unification result to properly process function call
unify(argActual, argExpected);
}
if (FunctionInterpretationHelper::needPartialInterpretation(callee)){
op= CALL_INTERPRET_PARTIAL;
}
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})){
op= 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), VERSION_NONE}, scopeBody};
getSymbolCache().setCachedValue(symbEl, InterpretationResolution(flagInput));
const std::string& nameAccum = expression.bindings[1];
Symbol symbAccum{ScopedSymbol{scopeBody->__identifiers.at(nameAccum), 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})){
op= FOLD_INTERPRET_INPUT;
flagInput = ANY;
}
resolution = unify(flagInput, flagAccumInit, flagBody);
break;
}
case Operator::INDEX: {
resolution = unify(
process(expression.operands[0], context),
process(expression.operands[1], 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})){
op= 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::LIST:
case Operator::LIST_NAMED: {
for (const Expression &op: expression.getOperands()) {
resolution = unify(resolution, process(op, context));
}
break;
}
default: {
resolution = CMPL_ONLY;
for (const Expression &op: expression.getOperands()) {
process(op, context);
}
for (CodeScope* scope: expression.blocks) {
Parent::process(scope, context);
}
break;
}
}
InterpretationResolution resolutionExpected =
Attachments::get<InterpretationData>(expression, {ANY, NONE}).resolution;
resolution = unify(resolution, resolutionExpected);
if (resolution != resolutionExpected && (op!=NONE || resolution == INTR_ONLY)){
Attachments::put<InterpretationData>(expression, {resolution, op});
}
return resolution;
}
InterpretationResolution
InterpretationPass::processFnCall(ManagedFnPtr function, PassContext context){
- const Symbol symbolFunction{ScopedSymbol::RetSymbol, function->getEntryScope()};
- auto& visitedSymbols = getSymbolCache();
-
- if (visitedSymbols.isCached(symbolFunction))
- return visitedSymbols.getCachedValue(symbolFunction);
-
- PassContext context2;
- context2.function = function;
-
- return visitedSymbols.setCachedValue(symbolFunction,
- Parent::process(function->getEntryScope(), context2));
+ 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 FunctionInterpretationData& 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]), VERSION_NONE}, entry};
cache.setCachedValue(symbArg, InterpretationResolution(fnSignature.signature[argNo]));
}
PassContext context;
context.function = function;
context.scope = entry;
InterpretationResolution resActual = process(CodeScope::getDeclaration(symbSelfFunc), context);
resActual = unify(resActual, fnResolutionExpected);
return cache.setCachedValue(symbSelfFunc, move(resActual));
}
const FunctionInterpretationData
FunctionInterpretationHelper::getSignature(ManagedFnPtr function){
if (Attachments::exists<FunctionInterpretationData>(function)){
return Attachments::get<FunctionInterpretationData>(function);
}
FunctionInterpretationData&& data = recognizeSignature(function);
Attachments::put<FunctionInterpretationData>(function, data);
return data;
}
FunctionInterpretationData
FunctionInterpretationHelper::recognizeSignature(ManagedFnPtr function){
CodeScope* entry = function->__entry;
FunctionInterpretationData 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), VERSION_NONE}, entry};
const Expression& arg = CodeScope::getDeclaration(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 FunctionInterpretationData& data = getSignature(function);
return data.flagPartialInterpretation;
}
}
diff --git a/cpp/tests/interpretation.cpp b/cpp/tests/interpretation.cpp
index 62419e9..21cdc9f 100644
--- a/cpp/tests/interpretation.cpp
+++ b/cpp/tests/interpretation.cpp
@@ -1,381 +1,381 @@
#include "attachments.h"
using namespace xreate;
#include "passmanager.h"
#include "compilation/targetinterpretation.h"
#include "gtest/gtest.h"
#include "boost/scoped_ptr.hpp"
#define private public
#include "Parser.h"
#include "pass/interpretationpass.h"
using namespace xreate;
using namespace xreate::compilation;
TEST(Interpretation, Analysis_StatementIF_1){
PassManager* man = PassManager::prepareForCode(
R"Code(
main = function::bool {
x = "a":: string.
y = if (x=="b"):: bool; interpretation(force) {
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};
InterpretationData& dataSymbolY = Attachments::get<InterpretationData>(symbolY);
ASSERT_EQ(INTR_ONLY, dataSymbolY.resolution);
}
TEST(Interpretation, Compilation_StatementIF_1){
PassManager* man = PassManager::prepareForCode(
R"Code(
main = function::int; entry {
x = "a":: string.
y = if (x=="b"):: string; interpretation(force) {
1
} else {
0
}.
y
}
)Code" );
man->runWithoutCompilation();
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, Analysis_StatementIF_InterpretCondition_1){
PassManager* man = PassManager::prepareForCode(
R"Code(
main = function(x:: int):: int {
comm= "inc":: string; interpretation(force).
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};
InterpretationData& dataSymbolY = Attachments::get<InterpretationData>(symbolY);
ASSERT_EQ(CMPL_ONLY, dataSymbolY.resolution);
ASSERT_EQ(IF_INTERPRET_CONDITION, dataSymbolY.op);
}
TEST(Interpretation, Compilation_StatementIF_InterpretCondition_1){
PassManager* man = PassManager::prepareForCode(
R"Code(
main = function(x:: int):: int; entry {
comm= "inc":: string; interpretation(force).
y = if (comm == "inc")::int {x+1} else {x}.
y
}
)Code" );
man->runWithoutCompilation();
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, Compilation_StatementFOLD_INTERPRET_INPUT_1){
PassManager* man = PassManager::prepareForCode(
R"Code(
main = function(x:: int):: int; entry {
commands = ["inc", "double", "dec"]:: [string]; interpretation(force).
loop fold(commands->comm::string, x->operand):: int{
switch(comm)::int
case ("inc"){
operand + 1
}
case ("dec"){
operand - 1
}
case ("double"){
operand * 2
}
}
}
)Code" );
man->runWithoutCompilation();
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);
}
TEST(Interpretation, StatementCall_RecursionNo_1){
PassManager* man = PassManager::prepareForCode(
R"Code(
unwrap = function(data::undef, keys::undef):: undef; interpretation(force){
loop fold(keys->key::string, data->a):: undef {
a[key]
}
}
start = function::num; entry{
result = unwrap(
{
a = {
b =
{
c = "core"
}
}
}, ["a", "b", "c"])::undef.
result == "core"
}
)Code" );
man->runWithoutCompilation();
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(1, result);
}
TEST(Interpretation, StatementCall_RecursionDirect_1){
PassManager* man = PassManager::prepareForCode(
R"Code(
unwrap = function(data:: X):: Y {
if (data[0] == "a")::Y {0} else {unwrap(data[0])}
}
entry = function:: i8; entry {
unwrap([[[["a"]]]]):: i8; interpretation(force)
}
)Code" );
man->runWithoutCompilation();
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);
int (*main)() = (int (*)())man->run();
int result = main();
ASSERT_EQ(0, result);
}
TEST(Interpretation, StatementCall_RecursionIndirect_1){
PassManager* man = PassManager::prepareForCode(
R"Code(
funcA = function(data:: X):: Y {
if (data == "a")::Y {0} else {funcB(data)}
}
funcB = function(data:: X):: Y {
if (data == "b")::Y {1} else {funcA(data)}
}
entry = function:: i8; entry {
funcA(""):: i8; interpretation(force)
}
)Code" );
InterpretationPass* pass = new InterpretationPass(man);
ASSERT_DEATH(pass->run(), "Indirect recursion detected");
}
TEST(Interpretation, PartialIntr_1){
PassManager* man = PassManager::prepareForCode(
R"Code(
evaluate= function(argument:: num, code:: string; interpretation(force)):: num {
switch(code)::int
case ("inc") {argument + 1}
case ("dec") {argument - 1}
case ("double") {argument * 2}
}
main = function::int; entry {
commands= ["inc", "double", "dec"]:: [string]; interpretation(force).
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, 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, Compilation_PartialIntr_2){
PassManager* man = PassManager::prepareForCode(
R"Code(
evaluate= function(argument:: num, code:: string; interpretation(force)):: num {
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]; interpretation(force).
loop fold(commands->comm::string, 10->operand):: int{
evaluate(operand, comm)
}
}
)Code" );
man->runWithoutCompilation();
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_3){
PassManager* man = PassManager::prepareForCode(
R"Code(
Command= type variant (INC, DEC, DOUBLE).
evaluate= function(argument:: num, code:: Command; interpretation(force)):: num {
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]:: [Command]; interpretation(force).
loop fold(commands->comm::Command, 10->operand):: int{
evaluate(operand, comm)
}
}
)Code" );
man->runWithoutCompilation();
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(InterpretationExamples, Regexp1){
FILE* input = fopen("scripts/dsl/regexp.xreate","r");
assert(input != nullptr);
std::unique_ptr<PassManager> man(PassManager::prepareForCode(input));
int (*main)() = (int (*)())man->run();
int result = main();
- ASSERT_EQ(9, result);
+ ASSERT_EQ(4, result);
}
//TOTEST call indirect recursion(w/o tags)
//TASk implement and test Loop Inf (fix acc types in coco grammar)
diff --git a/scripts/dsl/regexp.xreate b/scripts/dsl/regexp.xreate
new file mode 100644
index 0000000..a313ccb
--- /dev/null
+++ b/scripts/dsl/regexp.xreate
@@ -0,0 +1,72 @@
+interface(extern-c){
+ xml2 = library:: pkgconfig("libxml-2.0").
+
+ include {
+ xml2 = ["string.h"]
+ }.
+}
+
+Matcher = type variant (Sequence, ZeroOrMore, Text).
+
+matchText = function(text::string, matcher::string, posStart::i64):: i64 {
+ textLength = strlen(text):: i64.
+ matcherLength = strlen(matcher):: i64.
+
+ if(textLength >= posStart + matcherLength):: i64{
+ if(strncmp(text + posStart, matcher, matcherLength) == 0):: i64 {
+ matcherLength
+
+ } else {-1:: i64}
+ } else {-2:: i64}
+}
+
+
+matchSequence = function(text::string, pattern::undef; interpretation(force), posStart::i64):: i64; interpretation(suppress){
+ textLength = length(text):: i64.
+
+ loop fold(pattern-> matcher:: undef, posStart->pos):: i64{
+ recognizedSymbols = match(text, matcher, pos):: i64.
+
+ if (recognizedSymbols > 0):: i64{
+ pos+recognizedSymbols
+
+ } else {
+ pos:: i64; break
+ }
+ }
+}
+
+matchZeroOrMore= function(text::string, matcher::undef; interpretation(force), posStart::i64):: i64; interpretation(suppress){
+ textLength = length(text):: i64.
+
+ loop fold inf(posStart->pos):: i64{
+ recognizedSymbols = match(text, matcher, pos):: i64.
+
+ if (recognizedSymbols > 0):: i64{
+ pos+recognizedSymbols
+
+ } else {
+ pos:: i64; break
+ }
+ }
+}
+
+match = function(text::string, pattern::undef; interpretation(force), posStart::i64)::i64; interpretation(suppress){
+
+ switch (pattern[0]) :: int
+ case (Sequence) {matchSequence(text, pattern[1], posStart)}
+ case (ZeroOrMore) {matchZeroOrMore(text, pattern[1], posStart)}
+ case (Text) {matchText(text, pattern[1], posStart)}
+ case default {-1}
+}
+
+main = function:: i64; entry {
+ patternAB =
+ [Sequence,
+ [[ZeroOrMore, [Text, "a"]],
+ [Text, "b"]]] :: undef; interpretation(force).
+
+
+// matchers = ["The ", "only ", "way "] :: [string]; interpretation(force).
+ match("aaab", patternAB, 0):: i64
+}

Event Timeline