Page Menu
Home
Xreate
Search
Configure Global Search
Log In
Docs
Questions
Repository
Issues
Patches
Internal API
Files
F419504
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, Dec 22, 1:31 AM
Size
109 KB
Mime Type
text/x-diff
Expires
Tue, Dec 24, 1:31 AM (1 d, 7 h)
Engine
blob
Format
Raw Data
Handle
133007
Attached To
rXR Xreate
View Options
diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp
index cee486b..87c974b 100644
--- a/cpp/src/ast.cpp
+++ b/cpp/src/ast.cpp
@@ -1,928 +1,928 @@
#include "ast.h"
#include "ExternLayer.h"
#include "analysis/typeinference.h"
#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));
}
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;
+
+ case Expression::COMPOUND:{
+ switch (e.op) {
+ case Operator::VARIANT:
+ return true;
+ default: 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>&& packOperands = expandOperands(t.__operands);
auto typNew = TypeAnnotation(TypeOperator::STRUCT, move(packOperands));
typNew.fields = t.fields;
return ExpandedType(move(typNew));
};
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::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++)
{ }
namespace details { namespace incomplete {
AST::AST() {
Attachments::init<versions::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);
}
-bool
-AST::recognizeVariantIdentifier(Expression& identifier) {
- assert(identifier.__state == Expression::IDENT);
+void
+AST::recognizeVariantConstructor(Expression& function) {
+ assert(function.op == Operator::CALL);
- std::string variant = identifier.getValueString();
+ std::string variant = function.getValueString();
if (!__dictVariants.count(variant)) {
- return false;
+ return;
}
auto record = __dictVariants.at(variant);
const TypeAnnotation& typ = record.first;
- identifier.__state = Expression::VARIANT;
- identifier.setValueDouble(record.second);
- identifier.type = typ;
-
- return true;
+ function.op = Operator::VARIANT;
+ function.setValueDouble(record.second);
+ function.type = typ;
}
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 symbol: "<< identifier.second.getValueString() << std::endl;
assert(false && "Symbol not found");
}
}
}
xreate::AST*
AST::finalize() {
//all finalization steps:
recognizePostponedIdentifiers();
return reinterpret_cast<xreate::AST*>(this);
}
}} //namespace details::incomplete
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));
}
Expanded<TypeAnnotation>
AST::expandType(const TypeAnnotation &t) const {
return TypesResolver(this)(t);
}
ExpandedType
AST::getType(const Expression& expression){
return typeinference::getType(expression, *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) {
__entry->addBinding(move(name), move(argument));
}
const std::string&
Function::getName() const {
return __name;
}
ScopedSymbol
CodeScope::registerIdentifier(const Expression& identifier) {
versions::VariableVersion version = Attachments::get<versions::VariableVersion>(identifier, versions::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{
versions::VariableVersion version = Attachments::get<versions::VariableVersion>(identifier, versions::VERSION_NONE);
const std::string& name = identifier.getValueString();
//search identifier in the current block
if (__identifiers.count(name)){
VNameId id = __identifiers.at(name);
Symbol s;
s.identifier = ScopedSymbol{id, version};
s.scope = const_cast<CodeScope*>(this);
Attachments::put<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, versions::VERSION_NONE};
}
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.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};
}
diff --git a/cpp/src/ast.h b/cpp/src/ast.h
index f7cbb79..5a71e8e 100644
--- a/cpp/src/ast.h
+++ b/cpp/src/ast.h
@@ -1,577 +1,577 @@
#ifndef AST_H
#define AST_H
#include "attachments.h"
#include <vector>
#include <stdlib.h>
#include <string>
#include <list>
#include <unordered_map>
#include <unordered_set>
#include <climits>
#include "utils.h"
#include <algorithm>
namespace llvm {
class Value;
}
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 hold for all atoms/identifiers Parser::Token data, like line:col position
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);
const std::string& get() const;
private:
std::string __value;
};
enum class TypePrimitive {
Invalid, Bool, I8, I32, I64, Num, Int, Float, String
};
enum class TypeOperator {
NONE, CALL, CUSTOM, VARIANT, ARRAY, STRUCT, ACCESS, LINK
};
struct llvm_array_tag {
};
struct struct_tag {
};
const llvm_array_tag tag_array = llvm_array_tag();
const struct_tag tag_struct = struct_tag();
class TypeAnnotation {
public:
TypeAnnotation();
TypeAnnotation(const Atom<Type_t>& typ);
TypeAnnotation(TypePrimitive typ);
TypeAnnotation(llvm_array_tag, TypeAnnotation typ, int size);
TypeAnnotation(TypeOperator op, std::initializer_list<TypeAnnotation> operands);
TypeAnnotation(TypeOperator op, std::vector<TypeAnnotation>&& operands);
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;
int conjuctionId = -1; //conjunction point id (relevant for recursive types)
uint64_t __size = 0;
std::vector<std::string> fields;
std::vector<std::string> bindings;
private:
};
enum class Operator {
ADD, SUB, MUL, DIV,
EQU, NE, NEG, LSS,
LSE, GTR, GTE, LIST,
LIST_RANGE, LIST_NAMED,
CALL, CALL_INTRINSIC, NONE,
IMPL/* implication */, MAP,
FOLD, FOLD_INF, LOOP_CONTEXT,
INDEX, IF, SWITCH, SWITCH_ADHOC,
CASE, CASE_DEFAULT, LOGIC_AND,
- ADHOC, CONTEXT_RULE
+ ADHOC, CONTEXT_RULE, VARIANT
};
class Function;
class AST;
class CodeScope;
class MetaRuleAbstract;
template<class Target>
struct ManagedPtr {
static ManagedPtr<Target> Invalid() {
return ManagedPtr<Target>();
}
ManagedPtr() : __storage(0) {
}
ManagedPtr(unsigned int id, const std::vector<Target*>* storage)
: __id(id), __storage(storage) {
}
Target&
operator*() const {
assert(isValid() && "Invalid Ptr");
return *__storage->at(__id);
}
void operator=(const ManagedPtr<Target>& other) {
__id = other.__id;
__storage = other.__storage;
}
bool
operator==(const ManagedPtr<Target>& other) {
return isValid() && (__id == other.__id);
}
Target*
operator->() const noexcept {
assert(isValid() && "Invalid Ptr");
return __storage->at(__id);
}
inline bool isValid() const {
return (__storage) && (0 <= __id) && (__id < __storage->size());
}
inline operator bool() const {
return isValid();
}
ManagedPtr<Target>& operator++() {
++__id;
return *this;
}
inline unsigned int id() const {
return __id;
}
private:
unsigned int __id = 0;
const std::vector<Target*> * __storage = 0;
};
typedef ManagedPtr<Function> ManagedFnPtr;
typedef ManagedPtr<CodeScope> ManagedScpPtr;
typedef ManagedPtr<MetaRuleAbstract> ManagedRulePtr;
const ManagedScpPtr NO_SCOPE = ManagedScpPtr(UINT_MAX, 0);
//To update ExpressionHints in case of any changes
struct Expression {
friend class CodeScope;
friend class ClaspLayer;
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;
enum {
- INVALID, COMPOUND, IDENT, NUMBER, STRING, VARIANT, BINDING
+ INVALID, COMPOUND, IDENT, NUMBER, STRING, BINDING
} __state = INVALID;
Operator op;
unsigned int id;
std::vector<std::string> bindings;
std::map<std::string, size_t> __indexBindings;
std::vector<Expression> operands;
TypeAnnotation type;
mutable std::map<std::string, Expression> tags;
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();
this->__indexBindings[key] = index++;
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 ClaspLayer;
class LLVMLayer;
class MetaRuleAbstract {
public:
MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards);
virtual ~MetaRuleAbstract();
virtual void compile(ClaspLayer& layer) = 0;
protected:
RuleArguments __args;
RuleGuards __guards;
};
class RuleWarning : public MetaRuleAbstract {
friend class ClaspLayer;
public:
RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom<String_t>&& message);
virtual void compile(ClaspLayer& 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;
CodeScope * scope;
};
template<>
struct AttachmentsDict<Symbol>
{
typedef Symbol Data;
static const unsigned int key = 7;
};
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);
class CodeScope {
friend class Function;
friend class PassManager;
public:
CodeScope(CodeScope* parent = 0);
void setBody(const Expression& body);
Expression& getBody();
void addDeclaration(Expression&& var, Expression&& body);
void addBinding(Expression&& var, Expression&& argument);
static const Expression& getDeclaration(const Symbol& symbol);
const Expression& getDeclaration(const ScopedSymbol& symbol);
~CodeScope();
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 zero(0) variable index
std::unordered_map<ScopedSymbol, Expression> __declarations;
std::vector<Expression> tags;
std::vector<Expression> contextRules;
private:
VNameId __vCounter = 1;
ScopedSymbol registerIdentifier(const Expression& identifier);
public:
bool recognizeIdentifier(const Expression& identifier) const;
ScopedSymbol getSymbol(const std::string& alias);
};
class Function {
friend class Expression;
friend class CodeScope;
friend class AST;
public:
Function(const Atom<Identifier_t>& name);
void addBinding(Atom <Identifier_t>&& name, Expression&& argument);
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;
bool isPrefunction = false; //SECTIONTAG adhoc Function::isPrefunction flag
Expression guardContext;
private:
std::map<std::string, Expression> __tags;
};
class ExternData;
struct ExternEntry {
std::string package;
std::vector<std::string> headers;
};
typedef Expanded<TypeAnnotation> ExpandedType;
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);
}
};
namespace details { namespace incomplete {
class AST {
public:
AST();
//TASK extern and DFA interfaces move into addInterfaceData
/**
* DFA Interface
*/
void addDFAData(Expression&& data);
/**
* Extern Interface
*/
void addExternData(ExternData&& data);
void addInterfaceData(const ASTInterface& interface, Expression&& data);
void add(Function* f);
void add(MetaRuleAbstract* r);
ManagedScpPtr add(CodeScope* scope);
std::string getModuleName();
ManagedPtr<Function> findFunction(const std::string& name);
typedef std::multimap<std::string, unsigned int> FUNCTIONS_REGISTRY;
std::list<ManagedFnPtr> getAllFunctions() const;
std::list<ManagedFnPtr> getFunctionVariants(const std::string& name) const;
template<class Target>
ManagedPtr<Target> begin();
std::vector<ExternEntry> __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 __indexFunctions;
// ***** TYPES SECTION *****
public:
std::map<std::string, TypeAnnotation> __indexTypeAliases;
ExpandedType getType(const Expression& expression);
void add(TypeAnnotation t, Atom<Identifier_t> alias);
// ***** SYMBOL RECOGNITION *****
//TODO revisit enums/variants, move to codescope
- bool recognizeVariantIdentifier(Expression& identifier);
+ void recognizeVariantConstructor(Expression& function);
private:
std::map<std::string, std::pair<TypeAnnotation, int>> __dictVariants;
public:
std::set<std::pair<CodeScope*, Expression>> bucketUnrecognizedIdentifiers;
public:
void postponeIdentifier(CodeScope* scope, const Expression& id);
void recognizePostponedIdentifiers();
xreate::AST* finalize();
};
template<>
ManagedPtr<Function>
AST::begin<Function>();
template<>
ManagedPtr<CodeScope>
AST::begin<CodeScope>();
template<>
ManagedPtr<MetaRuleAbstract>
AST::begin<MetaRuleAbstract>();
} } // namespace details::incomplete
class AST: public details::incomplete::AST{
public:
AST(): details::incomplete::AST() {}
ExpandedType expandType(const TypeAnnotation &t) const;
ExpandedType findType(const std::string& name);
ExpandedType getType(const Expression& expression);
};
}
#endif // AST_H
diff --git a/cpp/src/compilation/targetinterpretation.cpp b/cpp/src/compilation/targetinterpretation.cpp
index 513a3a2..b47498c 100644
--- a/cpp/src/compilation/targetinterpretation.cpp
+++ b/cpp/src/compilation/targetinterpretation.cpp
@@ -1,442 +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;
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));
//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), versions::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();
ICodeScopeUnit* 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(IFunctionUnit* 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 BasicFunctionUnit 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, versions::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;
ICodeScopeUnit* 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)), versions::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, versions::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/adhocpass.cpp b/cpp/src/pass/adhocpass.cpp
index 411efa3..ee71b28 100644
--- a/cpp/src/pass/adhocpass.cpp
+++ b/cpp/src/pass/adhocpass.cpp
@@ -1,95 +1,96 @@
/*
* adhoc.cpp
*
* Created on: Nov 28, 2015
* Author: pgess
*/
#include "pass/adhocpass.h"
#include "query/context.h"
+//TODO use ADT/templated types rather than adhocs. remove adhocs.
namespace xreate { namespace adhoc {
AdhocExpression::AdhocExpression(): Expression(Operator::ADHOC, {})
{}
AdhocExpression::AdhocExpression(const Expression& base): Expression(base)
{}
void
AdhocExpression::setCommand(const Expression& comm){
this->addTags({Expression(Operator::CALL, {Atom<Identifier_t>("adhoc"), comm})});
}
Expression
AdhocExpression::getCommand() const{
assert(this->tags.count("adhoc"));
return this->tags.at("adhoc").getOperands().at(0);
}
AdhocScheme*
AdhocPass::findAssotiatedScheme(CodeScope* entry){
const ScopePacked scopeId = man->clasp->pack(entry);
const context::Domain& domain = queryContext->getContext(scopeId);
AdhocScheme* scheme = nullptr;
for (const Expression& context: domain){
if (!(context.__state == Expression::COMPOUND && context.op == Operator::CALL)) continue;
if (__schemes.count(context.getValueString())){
assert(!scheme && "Can't determine relevant scheme, ambiguous context");
scheme = __schemes.at(context.getValueString());
}
}
assert(scheme && "Context doesn't define any ad hoc scheme");
return scheme;
}
const TypeAnnotation&
AdhocScheme::getResultType(){
return __resultType;
}
CodeScope*
AdhocScheme::getCommandImplementation(const Expression& comm) {
assert(comm.__state == Expression::COMPOUND && comm.op == Operator::CALL && comm.operands.size() == 0);
const std::string commSerialized = comm.getValueString();
assert(__commands.count(commSerialized) && "Command isn't defined for a selected scheme");
return __commands.at(commSerialized);
}
AdhocScheme::AdhocScheme(const Expression& scheme):
__resultType(scheme.type), __name(scheme.getValueString()) {
Expression exprCasesList = scheme.getOperands()[0];
for (const Expression& exprSingleCase: exprCasesList.getOperands()){
std::string command = exprSingleCase.tags.begin()->second.getValueString();
CodeScope* blockImpl = *(exprSingleCase.blocks.begin());
__commands.emplace(command, blockImpl);
}
}
const std::string&
AdhocScheme::getName(){
return __name;
}
void
AdhocPass::run(){
queryContext = reinterpret_cast<context::ContextQuery*>(man->clasp->registerQuery(new context::ContextQuery(), QueryId::ContextQuery));
auto range = man->root->__interfacesData.equal_range(ASTInterface::Adhoc);
for (auto i=range.first; i!= range.second; ++i){
AdhocScheme* scheme = new AdhocScheme(i->second);
__schemes.emplace(scheme->getName(), scheme);
}
}
}} //end of namespace xreate::adhoc
diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp
index 8d094fa..4f49948 100644
--- a/cpp/src/pass/compilepass.cpp
+++ b/cpp/src/pass/compilepass.cpp
@@ -1,788 +1,791 @@
#include "compilepass.h"
#include "clasplayer.h"
#include <ast.h>
#include "llvmlayer.h"
#include "query/containers.h"
#include "query/context.h"
#include "compilation/containers.h"
#include "compilation/latecontextcompiler2.h"
#include "ExternLayer.h"
#include "pass/adhocpass.h"
#include "compilation/targetinterpretation.h"
#include "pass/versionspass.h"
#include "compilation/scopedecorators.h"
#include "compilation/adhocfunctiondecorator.h"
#include "compilation/operators.h"
#include "analysis/typeinference.h"
#include <boost/optional.hpp>
#include <memory>
#include <iostream>
using namespace std;
using namespace llvm;
//TODO use Scope<TargetLlvm>
//SECTIONTAG late-context FunctionDecorator
namespace xreate{namespace context{
template<class Parent>
class LateContextFunctionDecorator : public Parent {
public:
LateContextFunctionDecorator(ManagedFnPtr f, CompilePass* p)
: Parent(f, p), contextCompiler(this, p) {
}
protected:
std::vector<llvm::Type*> prepareArguments() {
std::vector<llvm::Type*>&& arguments = Parent::prepareArguments();
size_t sizeLateContextDemand = contextCompiler.getFunctionDemandSize();
if (sizeLateContextDemand) {
llvm::Type* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext());
llvm::Type* tyDemand = llvm::ArrayType::get(ty32, sizeLateContextDemand);
arguments.push_back(tyDemand);
}
return arguments;
}
llvm::Function::arg_iterator prepareBindings() {
llvm::Function::arg_iterator fargsI = Parent::prepareBindings();
size_t sizeLateContextDemand = contextCompiler.getFunctionDemandSize();
if (sizeLateContextDemand) {
fargsI->setName("latecontext");
contextCompiler.rawContextArgument = &*fargsI;
++fargsI;
}
return fargsI;
}
public:
context::LateContextCompiler2 contextCompiler;
};
}} //end of namespace xreate::context
namespace xreate { namespace compilation{
std::string
BasicFunctionUnit::prepareName(){
AST* ast = IFunctionUnit::pass->man->root;
string name = ast->getFunctionVariants(IFunctionUnit::function->__name).size() > 1 ?
IFunctionUnit::function->__name + std::to_string(IFunctionUnit::function.id()) :
IFunctionUnit::function->__name;
return name;
}
std::vector<llvm::Type*>
BasicFunctionUnit::prepareArguments() {
LLVMLayer* llvm = IFunctionUnit::pass->man->llvm;
AST* ast = IFunctionUnit::pass->man->root;
CodeScope* entry = IFunctionUnit::function->__entry;
std::vector<llvm::Type*> signature;
std::transform(entry->__bindings.begin(), entry->__bindings.end(), std::inserter(signature, signature.end()),
[llvm, ast, entry](const std::string & arg)->llvm::Type* {
assert(entry->__identifiers.count(arg));
ScopedSymbol argid{entry->__identifiers.at(arg), versions::VERSION_NONE};
return llvm->toLLVMType(ast->expandType(entry->__declarations.at(argid).type));
});
return signature;
}
llvm::Type*
BasicFunctionUnit::prepareResult() {
LLVMLayer* llvm = IFunctionUnit::pass->man->llvm;
AST* ast = IFunctionUnit::pass->man->root;
CodeScope* entry = IFunctionUnit::function->__entry;
return llvm->toLLVMType(ast->expandType(entry->__declarations.at(ScopedSymbol::RetSymbol).type));
}
llvm::Function::arg_iterator
BasicFunctionUnit::prepareBindings() {
CodeScope* entry = IFunctionUnit::function->__entry;
ICodeScopeUnit* entryCompilation = IFunctionUnit::getScopeUnit(entry);
llvm::Function::arg_iterator fargsI = IFunctionUnit::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;
}
//DEBT compiler rigidly depends on exact definition of DefaultFunctionUnit
typedef context::LateContextFunctionDecorator<
adhoc::AdhocFunctionDecorator<
BasicFunctionUnit>> DefaultFunctionUnit;
ICodeScopeUnit::ICodeScopeUnit(CodeScope* codeScope, IFunctionUnit* f, CompilePass* compilePass)
: pass(compilePass), function(f), scope(codeScope) {
}
llvm::Value*
CallStatementRaw::operator()(std::vector<llvm::Value *>&& args, const std::string& hintDecl) {
llvm::Function* calleeInfo = dyn_cast<llvm::Function>(__callee);
if (calleeInfo) {
auto argsFormal = calleeInfo->args();
int pos = 0;
//SECTIONTAG types/convert function ret value
for (auto argFormal = argsFormal.begin(); argFormal != argsFormal.end(); ++argFormal, ++pos) {
args[pos] = typeinference::doAutomaticTypeConversion(args[pos], argFormal->getType(), llvm->builder);
}
}
return llvm->builder.CreateCall(__calleeTy, __callee, args, hintDecl);
}
//DESABLEDFEATURE implement inlining
class CallStatementInline : public CallStatement {
public:
CallStatementInline(IFunctionUnit* caller, IFunctionUnit* callee, LLVMLayer* l)
: __caller(caller), __callee(callee), llvm(l) {
}
llvm::Value* operator()(std::vector<llvm::Value *>&& args, const std::string& hintDecl) {
//TOTEST inlining
// CodeScopeUnit* entryCompilation = outer->getScopeUnit(function->__entry);
// for(int i=0, size = args.size(); i<size; ++i) {
// entryCompilation->bindArg(args.at(i), string(entryCompilation->scope->__bindings.at(i)));
// }
//
//
// return entryCompilation->compile();
return nullptr;
}
private:
IFunctionUnit* __caller;
IFunctionUnit* __callee;
LLVMLayer* llvm;
bool isInline() {
// Symbol ret = Symbol{0, function->__entry};
// bool flagOnTheFly = SymbolAttachments::get<IsImplementationOnTheFly>(ret, false);
//TODO consider inlining
return false;
}
};
BasicCodeScopeUnit::BasicCodeScopeUnit(CodeScope* codeScope, IFunctionUnit* f, CompilePass* compilePass)
: ICodeScopeUnit(codeScope, f, compilePass) {
}
llvm::Value*
BasicCodeScopeUnit::processSymbol(const Symbol& s, std::string hintRetVar) {
Expression declaration = CodeScope::getDeclaration(s);
CodeScope* scope = s.scope;
ICodeScopeUnit* self = ICodeScopeUnit::function->getScopeUnit(scope);
return self->process(declaration, hintRetVar);
}
//SECTIONTAG late-context find callee function
//TOTEST static late context decisions
//TOTEST dynamic late context decisions
CallStatement*
BasicCodeScopeUnit::findFunction(const std::string& calleeName) {
LLVMLayer* llvm = pass->man->llvm;
ClaspLayer* clasp = pass->man->clasp;
DefaultFunctionUnit* function = dynamic_cast<DefaultFunctionUnit*> (this->function);
context::ContextQuery* queryContext = pass->queryContext;
const std::list<ManagedFnPtr>& specializations = pass->man->root->getFunctionVariants(calleeName);
//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 CallStatementRaw(external, llvm);
}
//no decisions required
if (specializations.size() == 1) {
if (!specializations.front()->guardContext.isValid()) {
return new CallStatementRaw(pass->getFunctionUnit(specializations.front())->compile(), llvm);
}
}
//TODO move dictSpecialization over to a separate function in order to perform cache, etc.
//prepare specializations dictionary
std::map<Expression, ManagedFnPtr> dictSpecializations;
boost::optional<ManagedFnPtr> variantDefault;
boost::optional<ManagedFnPtr> variant;
for (const ManagedFnPtr& f : specializations) {
const Expression& guard = f->guardContext;
//default case:
if (!guard.isValid()) {
variantDefault = f;
continue;
}
assert(dictSpecializations.emplace(guard, f).second && "Found several identical specializations");
}
//check static context
ScopePacked scopeCaller = clasp->pack(this->scope);
const string atomSpecialization = "specialization";
const Expression topicSpecialization(Operator::CALL,{(Atom<Identifier_t>(string(atomSpecialization))),
Expression(Operator::CALL,
{Atom<Identifier_t>(string(calleeName))}),
Atom<Number_t>(scopeCaller)});
const context::Decisions& decisions = queryContext->getFinalDecisions(scopeCaller);
if (decisions.count(topicSpecialization)) {
variant = dictSpecializations.at(decisions.at(topicSpecialization));
}
//TODO check only demand for this particular topic.
size_t sizeDemand = function->contextCompiler.getFunctionDemandSize();
//decision made if static context found or no late context exists(and there is default variant)
bool flagHasStaticDecision = variant || (variantDefault && !sizeDemand);
//if no late context exists
if (flagHasStaticDecision) {
IFunctionUnit* calleeUnit = pass->getFunctionUnit(variant ? *variant : *variantDefault);
//inlining possible based on static decision only
// if (calleeUnit->isInline()) {
// return new CallStatementInline(function, calleeUnit);
// }
return new CallStatementRaw(calleeUnit->compile(), llvm);
}
//require default variant if no static decision made
assert(variantDefault);
llvm::Function* functionVariantDefault = this->pass->getFunctionUnit(*variantDefault)->compile();
llvm::Value* resultFn = function->contextCompiler.findFunction(calleeName, functionVariantDefault, scopeCaller);
llvm::PointerType *resultPTy = cast<llvm::PointerType>(resultFn->getType());
llvm::FunctionType *resultFTy = cast<llvm::FunctionType>(resultPTy->getElementType());
return new CallStatementRaw(resultFn, resultFTy, llvm);
}
//DISABLEDFEATURE transformations
// if (pass->transformations->isAcceptable(expr)){
// return pass->transformations->transform(expr, result, ctx);
// }
llvm::Value*
BasicCodeScopeUnit::process(const Expression& expr, const std::string& hintVarDecl) {
#define DEFAULT(x) (hintVarDecl.empty()? x: hintVarDecl)
llvm::Value *left;
llvm::Value *right;
LLVMLayer& l = *pass->man->llvm;
xreate::compilation::Advanced instructions = xreate::compilation::Advanced({this, function, pass});
switch (expr.op) {
case Operator::SUB: case Operator::MUL:
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);
left = process(expr.operands[0]);
right = process(expr.operands[1]);
//SECTIONTAG types/convert binary operation
right = typeinference::doAutomaticTypeConversion(right, left->getType(), l.builder);
break;
default:;
}
switch (expr.op) {
case Operator::ADD:
{
left = process(expr.operands[0]);
Context context{this, function, pass};
llvm::Value* resultSU = StructUpdate::add(expr.operands[0], left, expr.operands[1], context, DEFAULT("tmp_add"));
if (resultSU) return resultSU;
right = process(expr.operands[1]);
llvm::Value* resultAddPA = pointerarithmetic::PointerArithmetic::add(left, right, context, DEFAULT("tmp_add"));
if (resultAddPA) {
return resultAddPA;
}
return l.builder.CreateAdd(left, right, DEFAULT("tmp_add"));
break;
}
case Operator::SUB:
return l.builder.CreateSub(left, right, DEFAULT("tmp_sub"));
break;
case Operator::MUL:
return l.builder.CreateMul(left, right, DEFAULT("tmp_mul"));
break;
case Operator::DIV:
return l.builder.CreateSDiv(left, right, DEFAULT("tmp_div"));
break;
case Operator::EQU:
if (left->getType()->isIntegerTy()) return l.builder.CreateICmpEQ(left, right, DEFAULT("tmp_equ"));
if (left->getType()->isFloatingPointTy()) return l.builder.CreateFCmpOEQ(left, right, DEFAULT("tmp_equ"));
break;
case Operator::NE:
return l.builder.CreateICmpNE(left, right, DEFAULT("tmp_ne"));
break;
case Operator::LSS:
return l.builder.CreateICmpSLT(left, right, DEFAULT("tmp_lss"));
break;
case Operator::LSE:
return l.builder.CreateICmpSLE(left, right, DEFAULT("tmp_lse"));
break;
case Operator::GTR:
return l.builder.CreateICmpSGT(left, right, DEFAULT("tmp_gtr"));
break;
case Operator::GTE:
return l.builder.CreateICmpSGE(left, right, DEFAULT("tmp_gte"));
break;
case Operator::NEG:
left = process(expr.operands[0]);
return l.builder.CreateNeg(left, DEFAULT("tmp_neg"));
break;
case Operator::CALL:
{
assert(expr.__state == Expression::COMPOUND);
std::string nameCallee = expr.getValueString();
shared_ptr<CallStatement> callee(findFunction(nameCallee));
//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);
}
);
ScopePacked outerScopeId = pass->man->clasp->pack(this->scope);
//TASK a) refactor CALL/ADHOC/find function
//SECTIONTAG late-context propagation arg
size_t calleeDemandSize = pass->queryContext->getFunctionDemand(nameCallee).size();
if (calleeDemandSize) {
DefaultFunctionUnit* function = dynamic_cast<DefaultFunctionUnit*> (this->function);
llvm::Value* argLateContext = function->contextCompiler.compileContextArgument(nameCallee, outerScopeId);
args.push_back(argLateContext);
}
return (*callee)(move(args), DEFAULT("res_" + nameCallee));
}
case Operator::IF:
{
return instructions.compileIf(expr, DEFAULT("tmp_if"));
}
case Operator::SWITCH:
{
return instructions.compileSwitch(expr, DEFAULT("tmp_switch"));
}
case Operator::LOOP_CONTEXT:
{
assert(false);
return nullptr;
//return instructions.compileLoopContext(expr, DEFAULT("tmp_loop"));
}
case Operator::LOGIC_AND:
{
assert(expr.operands.size() == 1);
return process(expr.operands[0]);
}
case Operator::LIST:
{
return instructions.compileListAsSolidArray(expr, DEFAULT("tmp_list"));
};
case Operator::LIST_RANGE:
{
assert(false); //no compilation phase for a range list
// return InstructionList(this).compileConstantArray(expr, l, hintRetVar);
};
case Operator::LIST_NAMED:
{
typedef Expanded<TypeAnnotation> ExpandedType;
ExpandedType tyStructLiteral = l.ast->getType(expr);
const std::vector<string> fieldsFormal = (tyStructLiteral.get().__operator == TypeOperator::CUSTOM) ?
l.layerExtern->getStructFields(l.layerExtern->lookupType(tyStructLiteral.get().__valueCustom))
: tyStructLiteral.get().fields;
std::map<std::string, size_t> indexFields;
for (size_t i = 0, size = fieldsFormal.size(); i < size; ++i) {
indexFields.emplace(fieldsFormal[i], i);
}
llvm::StructType* tyLiteralRaw = llvm::cast<llvm::StructType>(l.toLLVMType(tyStructLiteral));
llvm::Value* record = llvm::UndefValue::get(tyLiteralRaw);
for (size_t i = 0; i < expr.operands.size(); ++i) {
const Expression& operand = expr.operands.at(i);
unsigned int fieldId = indexFields.at(expr.bindings.at(i));
llvm::Value* result = 0;
//TODO Null ad hoc llvm implementation (related code: operators/StructUpdate/add)
// if (operand.isNone()){
// llvm::Type* tyNullField = tyRecord->getElementType(fieldId);
// result = llvm::UndefValue::get(tyNullField);
//
// } else {
result = process(operand);
// }
assert(result);
record = l.builder.CreateInsertValue(record, result, llvm::ArrayRef<unsigned>({fieldId}));
}
return record;
};
case Operator::MAP:
{
assert(expr.blocks.size());
return instructions.compileMapSolidOutput(expr, DEFAULT("map"));
};
case Operator::FOLD:
{
return instructions.compileFold(expr, DEFAULT("fold"));
};
case Operator::FOLD_INF:
{
return instructions.compileFoldInf(expr, DEFAULT("fold"));
};
case Operator::INDEX:
{
//TODO allow multiindex
assert(expr.operands.size() == 2);
assert(expr.operands[0].__state == Expression::IDENT);
const std::string& hintIdent = expr.operands[0].getValueString();
Symbol s = Attachments::get<Symbol>(expr.operands[0]);
const ExpandedType& t2 = pass->man->root->getType(expr.operands[0]);
llvm::Value* aggr = processSymbol(s, hintIdent);
switch (t2.get().__operator) {
case TypeOperator::STRUCT: case TypeOperator::CUSTOM:
{
std::string idxField;
const Expression& idx = expr.operands.at(1);
switch (idx.__state) {
//named struct field
case Expression::STRING:
idxField = idx.getValueString();
break;
//anonymous struct field
case Expression::NUMBER:
idxField = to_string((int) idx.getValueDouble());
break;
default:
assert(false && "Wrong index for a struct");
}
return instructions.compileStructIndex(aggr, t2, idxField);
};
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);
}
);
return instructions.compileArrayIndex(aggr, indexes, DEFAULT(string("el_") + hintIdent));
};
default:
assert(false);
}
};
//SECTIONTAG adhoc actual compilation
//TODO a) make sure that it's correct: function->adhocImplementation built for Entry scope and used in another scope
case Operator::ADHOC:
{
DefaultFunctionUnit* function = dynamic_cast<DefaultFunctionUnit*> (this->function);
assert(function->adhocImplementation && "Adhoc implementation not found");
const Expression& comm = adhoc::AdhocExpression(expr).getCommand();
CodeScope* scope = function->adhocImplementation->getCommandImplementation(comm);
ICodeScopeUnit* unitScope = function->getScopeUnit(scope);
//SECTIONTAG types/convert ADHOC ret convertation
llvm::Type* resultTy = l.toLLVMType(pass->man->root->expandType(function->adhocImplementation->getResultType()));
return typeinference::doAutomaticTypeConversion(unitScope->compile(), resultTy, l.builder);
};
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.builder.CreateLoad(storage, hintVarDecl);
}
assert(false && "undefined intrinsic");
}
+ case Operator::VARIANT:
+ {
+ //TASK Variant compilation to implement
+ assert(false&& "Variant compilation not implemented yet");
+ return nullptr;
+// const ExpandedType& typVariant = pass->man->root->getType(expr);
+// llvm::Type* typRaw = l.toLLVMType(typVariant);
+// int value = expr.getValueDouble();
+// return llvm::ConstantInt::get(typRaw, value);
+ }
+
case Operator::NONE:
assert(expr.__state != Expression::COMPOUND);
switch (expr.__state) {
case Expression::IDENT:
{
Symbol s = Attachments::get<Symbol>(expr);
return processSymbol(s, expr.getValueString());
}
case Expression::NUMBER:
{
llvm::Type* typConst;
if (expr.type.isValid()) {
typConst = l.toLLVMType(pass->man->root->getType(expr));
} else {
typConst = llvm::Type::getInt32Ty(llvm::getGlobalContext());
}
int literal = expr.getValueDouble();
return llvm::ConstantInt::get(typConst, literal);
}
case Expression::STRING:
{
return instructions.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str"));
};
- case Expression::VARIANT:
- {
- const ExpandedType& typVariant = pass->man->root->getType(expr);
- llvm::Type* typRaw = l.toLLVMType(typVariant);
- int value = expr.getValueDouble();
- return llvm::ConstantInt::get(typRaw, value);
- }
-
default:
{
break;
}
};
break;
default: break;
}
assert(false && "Can't compile expression");
return 0;
}
llvm::Value*
BasicCodeScopeUnit::compile(const std::string& hintBlockDecl) {
if (!hintBlockDecl.empty()) {
llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm::getGlobalContext(), hintBlockDecl, function->raw);
pass->man->llvm->builder.SetInsertPoint(block);
}
Symbol symbScope = Symbol{ScopedSymbol::RetSymbol, scope};
return processSymbol(symbScope);
}
ICodeScopeUnit::~ICodeScopeUnit() {
}
IFunctionUnit::~IFunctionUnit() {
}
llvm::Function*
IFunctionUnit::compile() {
if (raw != nullptr) return raw;
LLVMLayer* llvm = pass->man->llvm;
llvm::IRBuilder<>& builder = llvm->builder;
string&& functionName = prepareName();
std::vector<llvm::Type*>&& types = prepareArguments();
llvm::Type* expectedResultType = prepareResult();
llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false);
raw = llvm::cast<llvm::Function>(llvm->module->getOrInsertFunction(functionName, ft));
prepareBindings();
const std::string&blockName = "entry";
llvm::BasicBlock* blockCurrent = builder.GetInsertBlock();
llvm::Value* result = getScopeUnit(function->__entry)->compile(blockName);
assert(result);
//SECTIONTAG types/convert function ret value
builder.CreateRet(typeinference::doAutomaticTypeConversion(result, expectedResultType, llvm->builder));
if (blockCurrent) {
builder.SetInsertPoint(blockCurrent);
}
llvm->moveToGarbage(ft);
return raw;
}
ICodeScopeUnit*
IFunctionUnit::getScopeUnit(CodeScope* scope) {
if (__scopes.count(scope)) {
auto result = __scopes.at(scope).lock();
if (result) {
return result.get();
}
}
std::shared_ptr<ICodeScopeUnit> unit(pass->buildCodeScopeUnit(scope, this));
if (scope->__parent != nullptr) {
auto parentUnit = Decorators<CachedScopeDecoratorTag>::getInterface(getScopeUnit(scope->__parent));
parentUnit->registerChildScope(unit);
} else {
__orphanedScopes.push_back(unit);
}
if (!__scopes.emplace(scope, unit).second) {
__scopes[scope] = unit;
}
return unit.get();
}
ICodeScopeUnit*
IFunctionUnit::getScopeUnit(ManagedScpPtr scope) {
return getScopeUnit(&*scope);
}
ICodeScopeUnit*
IFunctionUnit::getEntry() {
return getScopeUnit(function->getEntryScope());
}
template<>
compilation::IFunctionUnit*
CompilePassCustomDecorators<void, void>::buildFunctionUnit(const ManagedFnPtr& function){
return new DefaultFunctionUnit(function, this);
}
template<>
compilation::ICodeScopeUnit*
CompilePassCustomDecorators<void, void>::buildCodeScopeUnit(CodeScope* scope, IFunctionUnit* function){
return new DefaultCodeScopeUnit(scope, function, this);
}
} // emf of compilation
IFunctionUnit*
CompilePass::getFunctionUnit(const ManagedFnPtr& function) {
unsigned int id = function.id();
if (!functions.count(id)) {
IFunctionUnit* unit = buildFunctionUnit(function);
functions.emplace(id, unit);
return unit;
}
return functions.at(id);
}
void
CompilePass::run() {
managerTransformations = new TransformationsManager();
targetInterpretation = new interpretation::TargetInterpretation(this->man->root, this);
queryContext = reinterpret_cast<context::ContextQuery*> (man->clasp->getQuery(QueryId::ContextQuery));
//Find out main function;
ClaspLayer::ModelFragment model = man->clasp->query(Config::get("function-entry"));
assert(model && "Error: No entry function found");
assert(model->first != model->second && "Error: Ambiguous entry function");
string nameMain = std::get<0>(ClaspLayer::parse<std::string>(model->first->second));
IFunctionUnit* unitMain = getFunctionUnit(man->root->findFunction(nameMain));
entry = unitMain->compile();
}
llvm::Function*
CompilePass::getEntryFunction() {
assert(entry);
return entry;
}
void
CompilePass::prepareQueries(ClaspLayer* clasp) {
clasp->registerQuery(new containers::Query(), QueryId::ContainersQuery);
clasp->registerQuery(new context::ContextQuery(), QueryId::ContextQuery);
}
} //end of namespace xreate
diff --git a/cpp/src/pass/interpretationpass.cpp b/cpp/src/pass/interpretationpass.cpp
index 69bb3b1..b1bc4d4 100644
--- a/cpp/src/pass/interpretationpass.cpp
+++ b/cpp/src/pass/interpretationpass.cpp
@@ -1,414 +1,413 @@
/*
* 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{
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){
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;
}
}
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<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), 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})){
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){
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]), versions::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), versions::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;
}
}} //end of namespace xreate::interpretation
diff --git a/cpp/tests/types.cpp b/cpp/tests/types.cpp
index 1287263..8f0613f 100644
--- a/cpp/tests/types.cpp
+++ b/cpp/tests/types.cpp
@@ -1,165 +1,179 @@
/*
* types.cpp
*
* Created on: Jun 4, 2015
* Author: pgess
*/
#include "gtest/gtest.h"
#include "xreatemanager.h"
#include "llvmlayer.h"
#include "main/Parser.h"
using namespace std;
using namespace xreate;
using namespace xreate::grammar::main;
TEST(Types, DependantTypes1) {
- string&& code = "XmlNode = type alias {\n"
+ string&& code = "XmlNode = type {\n"
" tag:: string,\n"
- " /* attrs:: [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::STRUCT, typeXmlNode->__operator);
- ASSERT_EQ(2, typeXmlNode->__operands.size());
+ ASSERT_EQ(3, typeXmlNode->__operands.size());
ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(0).__value);
- ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(1).__value);
+ ASSERT_EQ(TypeOperator::ARRAY, typeXmlNode->__operands.at(1).__operator);
+ ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(2).__value);
}
-TEST(Types, DependantTypes_FeatureTypeIndex_2) {
- string&& code = "XmlNode = type alias {\n"
+TEST(Types, ast_ParameterizedTypes_FeatureTypeIndex_1) {
+ string&& code = "XmlNode = type {\n"
" tag:: string,\n"
- " /* attrs:: [string],*/\n"
+ " attrs:: [string],\n"
" content:: string\n"
"}.\n"
""
- "Template = type Template(Leaf) {Leaf, [Leaf[content]]}."
- "Concrete = type alias Template(XmlNode).";
+ "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::STRUCT, typeConcrete->__operator);
ASSERT_EQ(2, typeConcrete->__operands.size());
ASSERT_EQ(TypeOperator::STRUCT, 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 alias {\n"
+ string&& code = "XmlNode = type {\n"
" tag:: string,\n"
- " /* attrs:: [string],*/\n"
+ " attrs:: [string],\n"
" content:: string\n"
"}.\n"
""
- "Tree = type Tree(Leaf) {Leaf, [Tree(Leaf)]}."
- "Concrete = type alias Tree(XmlNode).";
+ "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::STRUCT, typeConcrete->__operator);
ASSERT_EQ(2, typeConcrete->__operands.size());
ASSERT_EQ(TypeOperator::STRUCT, 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->conjuctionId,typeLink.conjuctionId);
}
TEST(Types, TreeType1LLvm){
- string&& code = "XmlNode = type alias {\n"
+ string&& code = "XmlNode = type {\n"
" tag:: string,\n"
" /* attrs:: [string],*/\n"
" content:: string\n"
"}.\n"
""
- "Tree = type Tree(Leaf) {Leaf, [Tree(Leaf)]}."
- "Concrete = type alias Tree(XmlNode).";
+ "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->getDeclaration(body->getSymbol("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->getDeclaration(body->getSymbol("tree")));
EXPECT_EQ(t2->__operator, TypeOperator::CUSTOM);
}
TEST(Types, ast_VariantType1){
string&& code =
- " colors = type variant (RED, BLUE, GREEN).\n"
- " test = function:: colors; entry {GREEN}";
+ " 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(Expression::VARIANT, eRed.__state);
+ EXPECT_EQ(Operator::VARIANT, eRed.op);
const ExpandedType& typ2 = program->root->getType(eRed);
EXPECT_EQ(TypeOperator::VARIANT, typ2->__operator);
-
- program->run();
}
TEST(Types, full_VariantType_Switch1){
string&& code =
- " colors = type variant (RED, BLUE, GREEN). \n"
- " test = function:: colors {GREEN} \n"
+ " 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 (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(
+ Expression = 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("Expression");
+ ASSERT_EQ(3, typ.get().fields.size());
+}
+
//TEST(Types, A)
//TOTEST string type
Event Timeline
Log In to Comment