Page Menu
Home
Xreate
Search
Configure Global Search
Log In
Docs
Questions
Repository
Issues
Patches
Internal API
Files
F2718205
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sun, Feb 15, 5:14 PM
Size
68 KB
Mime Type
text/x-diff
Expires
Tue, Feb 17, 5:14 PM (1 d, 17 h)
Engine
blob
Format
Raw Data
Handle
237569
Attached To
rXR Xreate
View Options
diff --git a/cpp/Configurations.cmake b/cpp/Configurations.cmake
index df7021e..be0d21d 100644
--- a/cpp/Configurations.cmake
+++ b/cpp/Configurations.cmake
@@ -1,157 +1,158 @@
cmake_minimum_required(VERSION 2.8.11)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -fprofile-arcs -ftest-coverage -O0")
set(XREATE_DEFINITIONS_COMMON
-D_GNU_SOURCE
-D__STDC_CONSTANT_MACROS
-D__STDC_FORMAT_MACROS
-D__STDC_LIMIT_MACROS
-DWITH_THREADS=1
)
#------------------------------------------------------
# CONFIGURATION: Min
set(XREATE_SOURCE_FILES_MIN
analysis/typeinference.cpp
xreatemanager.cpp
transcendlayer.cpp
llvmlayer.cpp
pass/compilepass.cpp
analysis/utils.cpp
ast.cpp
aux/xreatemanager-decorators.cpp
compilation/transformations.cpp
compilation/transformersaturation.cpp
attachments.cpp
compilation/control.cpp
utils.cpp
pass/abstractpass.cpp
aux/serialization/expressionserializer.cpp
analysis/transcendtarget.cpp analysis/resources.cpp
query/containers.cpp
modules.cpp
compilation/containers.cpp
compilation/containers/arrays.cpp
)
set(XREATE_TEST_FILES_MIN
universal.cpp
introduction.cpp
unit-test-example.cpp
supplemental/docutils
transcend.cpp
association.cpp
main.cpp
attachments.cpp
ast.cpp
compilation.cpp
ExpressionSerializer.cpp
types.cpp
#vendorsAPI/clangAPI.cpp
#vendorsAPI/xml2.cpp
#vendorsAPI/json.cpp
loops.cpp
#supplemental/versions-algorithm-data_dependency.cpp
supplemental/basics.cpp
+ arithmetics.cpp
)
IF(XREATE_CONFIG STREQUAL "Min")
set(XREATE_SOURCE_FILES
${XREATE_SOURCE_FILES_MIN}
)
set(XREATE_TEST_FILES ${XREATE_TEST_FILES_MIN})
set(XREATE_DEFINITIONS ${XREATE_DEFINITIONS_COMMON}
-DXREATE_CONFIG_MIN
)
ENDIF()
#------------------------------------------------------
# CONFIGURATION: Default
set(XREATE_SOURCE_FILES_DEFAULT ${XREATE_SOURCE_FILES_MIN}
compilation/targetinterpretation.cpp
analysis/temporalseqgraph.cpp
pass/cfatemporalseqpass.cpp
analysis/cfagraph.cpp
pass/cfapass.cpp
compilation/interpretation-instructions.cpp
ExternLayer.cpp
analysis/cfagraph.cpp
compilation/latetranscend.cpp
query/latex.cpp
aux/latereasoning.cpp
analysis/dfagraph.cpp
pass/dfapass.cpp
pass/interpretationpass.cpp
pass/versionspass.cpp
contextrule.cpp
compilation/demand.cpp
analysis/predefinedanns.cpp
)
set(XREATE_TEST_FILES_DEFAULT ${XREATE_TEST_FILES_MIN}
interpretation.cpp
transcend-ast.cpp
cfa.cpp
latetranscend.cpp
latex.cpp
polymorph.cpp
virtualization.cpp
exploitation.cpp
effects-communication.cpp
modules.cpp
dfa.cpp
effects-versions.cpp
containers.cpp
externc.cpp
aux/expressions.cpp
polymorphism-dt.cpp
)
IF(XREATE_CONFIG STREQUAL "Default")
set(XREATE_SOURCE_FILES
${XREATE_SOURCE_FILES_DEFAULT}
)
set(XREATE_TEST_FILES ${XREATE_TEST_FILES_DEFAULT})
set(XREATE_DEFINITIONS ${XREATE_DEFINITIONS_COMMON}
XREATE_ENABLE_EXTERN
)
ENDIF()
#------------------------------------------------------
# CONFIGURATION: Dimensions
IF(XREATE_CONFIG STREQUAL "Dimensions")
set(XREATE_SOURCE_FILES ${XREATE_SOURCE_FILES_MIN}
query/demand.cpp
compilation/demand.cpp
query/polymorph.cpp
compilation/polymorph.cpp
aux/expressions.cpp
pass/interpretationpass.cpp
compilation/targetinterpretation.cpp
compilation/intrinsics.cpp
# compilation/containerinst.cpp
analysis/predefinedanns.cpp
analysis/typehints.cpp
)
set(XREATE_TEST_FILES ${XREATE_TEST_FILES_MIN}
interpretation.cpp
dimensions.cpp
polymorph.cpp
polymorphism-dt.cpp
containers.cpp
problems.cpp
)
set(XREATE_DEFINITIONS ${XREATE_DEFINITIONS_COMMON}
-DXREATE_CONFIG_MIN
)
ENDIF()
diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp
index 65afc4b..18bca00 100644
--- a/cpp/src/pass/compilepass.cpp
+++ b/cpp/src/pass/compilepass.cpp
@@ -1,826 +1,846 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Author: pgess <v.melnychenko@xreate.org>
*
* compilepass.cpp
*/
/**
* \file compilepass.h
* \brief Main compilation routine. See \ref xreate::CompilePass
*/
#include "compilepass.h"
#include "transcendlayer.h"
#include "ast.h"
#include "llvmlayer.h"
#include "compilation/decorators.h"
#include "compilation/pointers.h"
#include "analysis/typeinference.h"
#include "compilation/control.h"
#include "compilation/demand.h"
#include "analysis/resources.h"
#ifdef XREATE_ENABLE_EXTERN
#include "ExternLayer.h"
#endif
#include "compilation/containers.h"
#include "compilation/containers/arrays.h"
#ifndef XREATE_CONFIG_MIN
#include "query/containers.h"
#include "pass/versionspass.h"
#include "compilation/targetinterpretation.h"
#endif
#include <boost/optional.hpp>
#include <memory>
using namespace std;
using namespace llvm;
namespace xreate{
namespace compilation{
#define DEFAULT(x) (hintAlias.empty()? x: hintAlias)
std::string
BasicBruteFunction::prepareName() {
AST* ast = IBruteFunction::pass->man->root;
string name = ast->getFnSpecializations(IBruteFunction::function->__name).size() > 1 ?
IBruteFunction::function->__name + std::to_string(IBruteFunction::function.id()) :
IBruteFunction::function->__name;
return name;
}
std::vector<llvm::Type*>
BasicBruteFunction::prepareSignature() {
LLVMLayer* llvm = IBruteFunction::pass->man->llvm;
AST* ast = IBruteFunction::pass->man->root;
CodeScope* entry = IBruteFunction::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*
BasicBruteFunction::prepareResult() {
LLVMLayer* llvm = IBruteFunction::pass->man->llvm;
AST* ast = IBruteFunction::pass->man->root;
CodeScope* entry = IBruteFunction::function->__entry;
return llvm->toLLVMType(ast->expandType(entry->__declarations.at(ScopedSymbol::RetSymbol).type));
}
llvm::Function::arg_iterator
BasicBruteFunction::prepareBindings() {
CodeScope* entry = IBruteFunction::function->__entry;
IBruteScope* entryCompilation = IBruteFunction::getScopeUnit(entry);
llvm::Function::arg_iterator fargsI = IBruteFunction::raw->arg_begin();
for (std::string &arg : entry->__bindings) {
ScopedSymbol argid{entry->__identifiers[arg], versions::VERSION_NONE};
entryCompilation->bindArg(&*fargsI, argid);
fargsI->setName(arg);
++fargsI;
}
return fargsI;
}
IBruteScope::IBruteScope(const CodeScope * const codeScope, IBruteFunction* f, CompilePass* compilePass)
: pass(compilePass), function(f), scope(codeScope), currentBlockRaw(nullptr) { }
llvm::Value*
BruteFnInvocation::operator()(std::vector<llvm::Value *>&& args, const std::string& hintDecl) {
llvm::Function* calleeInfo = dyn_cast<llvm::Function>(__callee);
if (calleeInfo) {
auto argsFormal = calleeInfo->args();
size_t sizeArgsF = std::distance(argsFormal.begin(), argsFormal.end());
assert(args.size() >= sizeArgsF);
assert(calleeInfo->isVarArg() || args.size() == sizeArgsF);
auto argFormal = argsFormal.begin();
for(size_t argId = 0; argId < args.size(); ++argId){
if(argFormal != argsFormal.end()){
args[argId] = typeinference::doAutomaticTypeConversion(
args.at(argId), argFormal->getType(), llvm->irBuilder);
++argFormal;
}
}
}
//Do not name function call that returns Void.
std::string nameStatement = hintDecl;
if (calleeInfo->getReturnType()->isVoidTy()) {
nameStatement.clear();
}
return llvm->irBuilder.CreateCall(__calleeTy, __callee, args, nameStatement);
}
llvm::Value*
HiddenArgsFnInvocation::operator() (std::vector<llvm::Value *>&& args, const std::string& hintDecl) {
args.insert(args.end(), __args.begin(), __args.end());
return __parent->operator ()(std::move(args), hintDecl);
}
class CallStatementInline : public IFnInvocation{
public:
CallStatementInline(IBruteFunction* caller, IBruteFunction* callee, LLVMLayer* l)
: __caller(caller), __callee(callee), llvm(l) { }
llvm::Value* operator()(std::vector<llvm::Value *>&& args, const std::string& hintDecl) {
return nullptr;
}
private:
IBruteFunction* __caller;
IBruteFunction* __callee;
LLVMLayer* llvm;
bool
isInline() {
// Symbol ret = Symbol{0, function->__entry};
// bool flagOnTheFly = SymbolAttachments::get<IsImplementationOnTheFly>(ret, false);
//TODO consider inlining
return false;
}
} ;
BasicBruteScope::BasicBruteScope(const CodeScope * const codeScope, IBruteFunction* f, CompilePass* compilePass)
: IBruteScope(codeScope, f, compilePass) { }
llvm::Value*
BasicBruteScope::processSymbol(const Symbol& s, std::string hintRetVar) {
Expression declaration = CodeScope::getDefinition(s);
const CodeScope* scopeExternal = s.scope;
IBruteScope* scopeBruteExternal = IBruteScope::function->getScopeUnit(scopeExternal);
assert(scopeBruteExternal->currentBlockRaw);
llvm::Value* resultRaw;
llvm::BasicBlock* blockOwn = pass->man->llvm->irBuilder.GetInsertBlock();
if (scopeBruteExternal->currentBlockRaw == blockOwn) {
resultRaw = scopeBruteExternal->process(declaration, hintRetVar);
scopeBruteExternal->currentBlockRaw = currentBlockRaw =
pass->man->llvm->irBuilder.GetInsertBlock();
} else {
pass->man->llvm->irBuilder.SetInsertPoint(scopeBruteExternal->currentBlockRaw);
resultRaw = scopeBruteExternal->processSymbol(s, hintRetVar);
pass->man->llvm->irBuilder.SetInsertPoint(blockOwn);
}
return resultRaw;
}
IFnInvocation*
BasicBruteScope::findFunction(const Expression& opCall) {
const std::string& calleeName = opCall.getValueString();
LLVMLayer* llvm = pass->man->llvm;
const std::list<ManagedFnPtr>& specializations = pass->man->root->getFnSpecializations(calleeName);
#ifdef XREATE_ENABLE_EXTERN
//if no specializations registered - check external function
if (specializations.size() == 0) {
llvm::Function* external = llvm->layerExtern->lookupFunction(calleeName);
llvm::outs() << "Debug/External function: " << calleeName;
external->getType()->print(llvm::outs(), true);
llvm::outs() << "\n";
return new BruteFnInvocation(external, llvm);
}
#endif
//There should be only one specialization without any valid guards at this point
return new BruteFnInvocation(pass->getFunctionUnit(
pass->man->root->findFunction(calleeName))->compile(),
llvm);
}
//DISABLEDFEATURE transformations
// if (pass->transformations->isAcceptable(expr)){
// return pass->transformations->transform(expr, result, ctx);
// }
llvm::Value*
BasicBruteScope::process(const Expression& expr, const std::string& hintAlias, const TypeAnnotation& expectedT) {
llvm::Value *leftRaw;
llvm::Value *rightRaw;
LLVMLayer& l = *pass->man->llvm;
Context ctx{this, function, pass};
xreate::compilation::ControlIR controlIR = xreate::compilation::ControlIR({this, function, pass});
switch (expr.op) {
case Operator::ADD:
case Operator::SUB: case Operator::MUL:
case Operator::DIV: case Operator::EQU: case Operator::LSS:
case Operator::GTR: case Operator::NE: case Operator::LSE:
case Operator::GTE:
assert(expr.__state == Expression::COMPOUND);
assert(expr.operands.size() == 2);
- leftRaw = process(expr.operands[0]);
- rightRaw = process(expr.operands[1]);
+ leftRaw = process(expr.operands.at(0));
+ rightRaw = process(expr.operands.at(1));
break;
default:;
}
switch (expr.op) {
+ case Operator::AND:
+ {
+ assert(expr.operands.size());
+ llvm::Value* resultRaw = process(expr.operands[0]);
+ for(size_t i=1; i< expr.operands.size()-1; ++i){
+ resultRaw = l.irBuilder.CreateAnd(resultRaw, process(expr.operands.at(i)));
+ }
+ return l.irBuilder.CreateAnd(resultRaw, process(expr.operands.at(expr.operands.size()-1)), hintAlias);
+ }
+
+ case Operator::OR:
+ {
+ assert(expr.operands.size());
+ llvm::Value* resultRaw = process(expr.operands[0]);
+ for(size_t i=1; i< expr.operands.size()-1; ++i){
+ resultRaw = l.irBuilder.CreateOr(resultRaw, process(expr.operands.at(i)));
+ }
+ return l.irBuilder.CreateOr(resultRaw, process(expr.operands.at(expr.operands.size()-1)), hintAlias);
+ }
+
case Operator::ADD:
{
return l.irBuilder.CreateAdd(leftRaw, rightRaw, DEFAULT("addv"));
}
case Operator::SUB:
return l.irBuilder.CreateSub(leftRaw, rightRaw, DEFAULT("tmp_sub"));
break;
case Operator::MUL:
return l.irBuilder.CreateMul(leftRaw, rightRaw, DEFAULT("tmp_mul"));
break;
case Operator::DIV:
if (leftRaw->getType()->isIntegerTy()) return l.irBuilder.CreateSDiv(leftRaw, rightRaw, DEFAULT("tmp_div"));
if (leftRaw->getType()->isFloatingPointTy()) return l.irBuilder.CreateFDiv(leftRaw, rightRaw, DEFAULT("tmp_div"));
break;
case Operator::EQU: {
if (leftRaw->getType()->isIntegerTy()) return l.irBuilder.CreateICmpEQ(leftRaw, rightRaw, DEFAULT("tmp_equ"));
if (leftRaw->getType()->isFloatingPointTy()) return l.irBuilder.CreateFCmpOEQ(leftRaw, rightRaw, DEFAULT("tmp_equ"));
const ExpandedType& leftT = pass->man->root->getType(expr.operands[0]);
const ExpandedType& rightT = pass->man->root->getType(expr.operands[1]);
if(leftT->__operator == TypeOperator::VARIANT && rightT->__operator == TypeOperator::VARIANT){
llvm::Type* selectorT = llvm::cast<llvm::StructType>(leftRaw->getType())->getElementType(0);
llvm::Value* leftUnwapped = typeinference::doAutomaticTypeConversion(leftRaw, selectorT, l.irBuilder);
llvm::Value* rightUnwapped = typeinference::doAutomaticTypeConversion(rightRaw, selectorT, l.irBuilder);
return l.irBuilder.CreateICmpEQ(leftUnwapped, rightUnwapped, DEFAULT("tmp_equ"));
}
break;
}
case Operator::NE:
return l.irBuilder.CreateICmpNE(leftRaw, rightRaw, DEFAULT("tmp_ne"));
break;
case Operator::LSS:
return l.irBuilder.CreateICmpSLT(leftRaw, rightRaw, DEFAULT("tmp_lss"));
break;
case Operator::LSE:
return l.irBuilder.CreateICmpSLE(leftRaw, rightRaw, DEFAULT("tmp_lse"));
break;
case Operator::GTR:
return l.irBuilder.CreateICmpSGT(leftRaw, rightRaw, DEFAULT("tmp_gtr"));
break;
case Operator::GTE:
return l.irBuilder.CreateICmpSGE(leftRaw, rightRaw, DEFAULT("tmp_gte"));
break;
case Operator::NEG:
{
leftRaw = process(expr.operands[0]);
ExpandedType leftTy = pass->man->root->getType(expr.operands[0]);
if (leftTy->__value == TypePrimitive::Bool){
- return l.irBuilder.CreateNot(leftRaw, DEFAULT("tmp_not"));
+ return l.irBuilder.CreateNot(leftRaw, hintAlias);
} else {
- return l.irBuilder.CreateNeg(leftRaw, DEFAULT("tmp_neg"));
+ return l.irBuilder.CreateNeg(leftRaw, hintAlias);
}
break;
}
case Operator::CALL:
{
assert(expr.__state == Expression::COMPOUND);
shared_ptr<IFnInvocation> callee(findFunction(expr));
const std::string& nameCallee = expr.getValueString();
//prepare arguments
std::vector<llvm::Value *> args;
args.reserve(expr.operands.size());
std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()),
[this](const Expression & operand) {
return process(operand);
}
);
return (*callee)(move(args), DEFAULT("res_" + nameCallee));
}
case Operator::IF:
{
return controlIR.compileIf(expr, DEFAULT("tmp_if"));
}
case Operator::SWITCH:
{
return controlIR.compileSwitch(expr, DEFAULT("tmp_switch"));
}
case Operator::LOGIC_AND:
{
assert(expr.operands.size() == 1);
return process(expr.operands[0]);
}
case Operator::LIST: //init record or array
{
ExpandedType exprT = l.ast->getType(expr, expectedT);
TypesHelper helper(pass->man->llvm);
enum {RECORD, ARRAY} kind;
if (helper.isArrayT(exprT)){
kind = ARRAY;
} else if (helper.isRecordT(exprT)){
kind = RECORD;
} else {
assert(false && "Inapproriate type");
}
#ifdef XREATE_ENABLE_EXTERN
if (exprT->__operator == TypeOperator::ALIAS){
if (l.layerExtern->isArrayType(exprT->__valueCustom)){
flagIsArray = true;
break;
}
if (l.layerExtern->isRecordType(exprT->__valueCustom)){
flagIsArray = false;
break;
}
assert(false && "Inapproriate external type");
}
#endif
switch(kind){
case RECORD:{
const std::vector<string> fieldsFormal = helper.getRecordFields(exprT);
containers::RecordIR irRecords(ctx);
llvm::StructType *recordTRaw = llvm::cast<llvm::StructType>(l.toLLVMType(exprT));
llvm::Value *resultRaw = irRecords.init(recordTRaw);
return irRecords.update(resultRaw, exprT, expr);
}
case ARRAY: {
std::unique_ptr<containers::IContainersIR> containerIR(
containers::IContainersIR::create(expr, expectedT, ctx));
llvm::Value* aggrRaw = containerIR->init(hintAlias);
return containerIR->update(aggrRaw, expr, hintAlias);
}
}
break;
};
case Operator::LIST_RANGE:
{
assert(false); //no compilation phase for a range list
// return InstructionList(this).compileConstantArray(expr, l, hintRetVar);
};
case Operator::MAP:
{
assert(expr.blocks.size());
return controlIR.compileMapSolidOutput(expr, DEFAULT("map"));
};
case Operator::FOLD:
{
return controlIR.compileFold(expr, DEFAULT("fold"));
};
case Operator::FOLD_INF:
{
return controlIR.compileFoldInf(expr, DEFAULT("fold"));
};
case Operator::INDEX:
{
assert(expr.operands.size() > 1);
const Expression& aggrE = expr.operands[0];
const ExpandedType& aggrT = pass->man->root->getType(aggrE);
llvm::Value* aggrRaw = process(aggrE);
switch (aggrT->__operator) {
case TypeOperator::RECORD:
{
list<string> fieldsList;
for(auto opIt = ++expr.operands.begin(); opIt!=expr.operands.end(); ++opIt){
fieldsList.push_back(getIndexStr(*opIt));
}
return controlIR.compileStructIndex(aggrRaw, aggrT, fieldsList);
};
case TypeOperator::ARRAY:
{
std::vector<llvm::Value*> indexes;
std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()),
[this] (const Expression & op) {
return process(op);
}
);
std::unique_ptr<containers::IContainersIR> containersIR(
containers::IContainersIR::create(aggrE, expectedT, ctx)
);
containers::ArrayIR* arraysIR = static_cast<containers::ArrayIR*>(containersIR.get());
return arraysIR->get(aggrRaw, indexes, hintAlias);
};
default:
assert(false);
}
};
case Operator::CALL_INTRINSIC:
{
// const std::string op = expr.getValueString();
//
// if (op == "copy") {
// llvm::Value* result = process(expr.getOperands().at(0));
//
// auto decoratorVersions = Decorators<VersionsScopeDecoratorTag>::getInterface(this);
// llvm::Value* storage = decoratorVersions->processIntrinsicInit(result->getType());
// decoratorVersions->processIntrinsicCopy(result, storage);
//
// return l.irBuilder.CreateLoad(storage, hintAlias);
// }
assert(false && "undefined intrinsic");
}
case Operator::QUERY:
case Operator::QUERY_LATE:
{
assert(false && "Should be processed by interpretation");
}
case Operator::VARIANT:
{
const ExpandedType& typResult = pass->man->root->getType(expr);
llvm::Type* typResultRaw = l.toLLVMType(typResult);
llvm::Type* typIdRaw = llvm::cast<llvm::StructType>(typResultRaw)->getElementType(0);
uint64_t id = expr.getValueDouble();
llvm::Value* resultRaw = llvm::UndefValue::get(typResultRaw);
resultRaw = l.irBuilder.CreateInsertValue(resultRaw, llvm::ConstantInt::get(typIdRaw, id), llvm::ArrayRef<unsigned>({0}));
const ExpandedType& typVariant = ExpandedType(typResult->__operands.at(id));
llvm::Type* typVariantRaw = l.toLLVMType(typVariant);
llvm::Value* variantRaw = llvm::UndefValue::get(typVariantRaw);
assert(expr.operands.size() == typVariant->__operands.size() && "Wrong variant arguments count");
if (!typVariant->__operands.size()) return resultRaw;
for (unsigned int fieldId = 0; fieldId < expr.operands.size(); ++fieldId) {
const ExpandedType& typField = ExpandedType(typVariant->__operands.at(fieldId));
Attachments::put<TypeInferred>(expr.operands.at(fieldId), typField);
llvm::Value* fieldRaw = process(expr.operands.at(fieldId));
assert(fieldRaw);
variantRaw = l.irBuilder.CreateInsertValue(variantRaw, fieldRaw, llvm::ArrayRef<unsigned>({fieldId}));
}
llvm::Type* typStorageRaw = llvm::cast<llvm::StructType>(typResultRaw)->getElementType(1);
llvm::Value* addrAsStorage = l.irBuilder.CreateAlloca(typStorageRaw);
llvm::Value* addrAsVariant = l.irBuilder.CreateBitOrPointerCast(addrAsStorage, typVariantRaw->getPointerTo());
l.irBuilder.CreateStore(variantRaw, addrAsVariant);
llvm::Value* storageRaw = l.irBuilder.CreateLoad(typStorageRaw, addrAsStorage);
resultRaw = l.irBuilder.CreateInsertValue(resultRaw, storageRaw, llvm::ArrayRef<unsigned>({1}));
return resultRaw;
}
case Operator::SWITCH_VARIANT:
{
return controlIR.compileSwitchVariant(expr, DEFAULT("tmpswitch"));
}
case Operator::SWITCH_LATE:
{
assert(false && "Instruction's compilation should've been redirected to interpretation");
return nullptr;
}
case Operator::SEQUENCE:
{
return controlIR.compileSequence(expr);
}
case Operator::UNDEF:
{
llvm::Type* typExprUndef = l.toLLVMType(pass->man->root->getType(expr, expectedT));
return llvm::UndefValue::get(typExprUndef);
}
case Operator::UPDATE:
{
TypesHelper helper(pass->man->llvm);
containers::RecordIR irRecords(ctx);
const Expression& aggrE = expr.operands.at(0);
const Expression& updE = expr.operands.at(1);
const ExpandedType& aggrT = pass->man->root->getType(aggrE);
llvm::Value* aggrRaw = process(aggrE);
if (helper.isRecordT(aggrT)){
return irRecords.update(aggrRaw, aggrT, updE);
}
if (helper.isArrayT(aggrT)){
if (updE.op == Operator::LIST_INDEX){
std::unique_ptr<containers::IContainersIR> containersIR(
containers::IContainersIR::create(aggrE, TypeAnnotation(), ctx
));
return containersIR->update(aggrRaw, updE, hintAlias);
}
}
assert(false);
return nullptr;
}
case Operator::INVALID:
assert(expr.__state != Expression::COMPOUND);
switch (expr.__state) {
case Expression::IDENT:
{
Symbol s = Attachments::get<IdentifierSymbol>(expr);
return processSymbol(s, expr.getValueString());
}
case Expression::NUMBER:
{
llvm::Type* typConst = l.toLLVMType(pass->man->root->getType(expr, expectedT));
int literal = expr.getValueDouble();
if (typConst->isFloatingPointTy()) return llvm::ConstantFP::get(typConst, literal);
if (typConst->isIntegerTy()) return llvm::ConstantInt::get(typConst, literal);
assert(false && "Can't compile literal");
}
case Expression::STRING:
{
return controlIR.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str"));
};
default:
{
break;
}
};
break;
default: break;
}
assert(false && "Can't compile expression");
return 0;
}
llvm::Value*
BasicBruteScope::compile(const std::string& hintBlockDecl) {
LLVMLayer* llvm = pass->man->llvm;
if (!hintBlockDecl.empty()) {
llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm->llvmContext, hintBlockDecl, function->raw);
pass->man->llvm->irBuilder.SetInsertPoint(block);
}
currentBlockRaw = pass->man->llvm->irBuilder.GetInsertBlock();
Symbol symbScope = Symbol{ScopedSymbol::RetSymbol, scope};
return processSymbol(symbScope);
}
IBruteScope::~IBruteScope() { }
IBruteFunction::~IBruteFunction() { }
llvm::Function*
IBruteFunction::compile() {
if (raw != nullptr) return raw;
LLVMLayer* llvm = pass->man->llvm;
llvm::IRBuilder<>& builder = llvm->irBuilder;
string&& functionName = prepareName();
std::vector<llvm::Type*>&& types = prepareSignature();
llvm::Type* expectedResultType = prepareResult();
llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false);
raw = llvm::cast<llvm::Function>(llvm->module->getOrInsertFunction(functionName, ft));
prepareBindings();
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->irBuilder));
if (blockCurrent) {
builder.SetInsertPoint(blockCurrent);
}
llvm->moveToGarbage(ft);
return raw;
}
IBruteScope*
IBruteFunction::getScopeUnit(const CodeScope * const scope) {
if (__scopes.count(scope)) {
auto result = __scopes.at(scope).lock();
if (result) {
return result.get();
}
}
std::shared_ptr<IBruteScope> unit(pass->buildCodeScopeUnit(scope, this));
if (scope->__parent != nullptr) {
auto parentUnit = Decorators<CachedScopeDecoratorTag>::getInterface(getScopeUnit(scope->__parent));
parentUnit->registerChildScope(unit);
} else {
__orphanedScopes.push_back(unit);
}
if (!__scopes.emplace(scope, unit).second) {
__scopes[scope] = unit;
}
return unit.get();
}
IBruteScope*
IBruteFunction::getScopeUnit(ManagedScpPtr scope) {
return getScopeUnit(&*scope);
}
IBruteScope*
IBruteFunction::getEntry() {
return getScopeUnit(function->getEntryScope());
}
template<>
compilation::IBruteFunction*
CompilePassCustomDecorators<void, void>
::buildFunctionUnit(const ManagedFnPtr& function) {
return new BruteFunctionDefault(function, this);
}
template<>
compilation::IBruteScope*
CompilePassCustomDecorators<void, void>
::buildCodeScopeUnit(const CodeScope * const scope, IBruteFunction* function) {
return new DefaultCodeScopeUnit(scope, function, this);
}
std::string
BasicBruteScope::getIndexStr(const Expression& index){
switch(index.__state){
//named struct field
case Expression::STRING:
return index.getValueString();
break;
//anonymous struct field
case Expression::NUMBER:
return to_string((int) index.getValueDouble());
break;
default:
assert(false && "Wrong index for a struct");
}
return "";
}
} // end of compilation
compilation::IBruteFunction*
CompilePass::getFunctionUnit(const ManagedFnPtr& function) {
unsigned int id = function.id();
if (!functions.count(id)) {
compilation::IBruteFunction* unit = buildFunctionUnit(function);
functions.emplace(id, unit);
return unit;
}
return functions.at(id);
}
void
CompilePass::prepare(){
//Initialization:
#ifndef XREATE_CONFIG_MIN
#endif
managerTransformations = new xreate::compilation::TransformationsManager();
targetInterpretation = new interpretation::TargetInterpretation(man, this);
}
void
CompilePass::run() {
prepare();
//Determine entry function:
StaticModel model = man->transcend->query(analysis::FN_ENTRY_PREDICATE);
assert(model.size() && "Error: No entry function found");
assert(model.size() == 1 && "Error: Ambiguous entry function");
string nameMain = std::get<0>(TranscendLayer::parse<std::string>(model.begin()->second));
compilation::IBruteFunction* unitMain = getFunctionUnit(man->root->findFunction(nameMain));
//Compilation itself:
entry = unitMain->compile();
}
llvm::Function*
CompilePass::getEntryFunction() {
assert(entry);
return entry;
}
void
CompilePass::prepareQueries(TranscendLayer* transcend) {
#ifndef XREATE_CONFIG_MIN
transcend->registerQuery(new latex::LatexQuery(), QueryId::LatexQuery);
#endif
transcend->registerQuery(new containers::Query(), QueryId::ContainersQuery);
transcend->registerQuery(new demand::DemandQuery(), QueryId::DemandQuery);
transcend->registerQuery(new polymorph::PolymorphQuery(), QueryId::PolymorphQuery);
}
} //end of namespace xreate
/**
* \class xreate::CompilePass
* \brief The owner of the compilation process. Performs fundamental compilation activities along with the xreate::compilation's routines
*
* xreate::CompilePass traverses over xreate::AST tree and produces executable code.
* The pass performs compilation using the following data sources:
* - %Attachments: the data gathered by the previous passes. See \ref xreate::Attachments.
* - Transcend solutions accessible via queries. See \ref xreate::IQuery, \ref xreate::TranscendLayer.
*
* The pass generates a bytecode by employing \ref xreate::LLVMLayer(wrapper over LLVM toolchain).
* Many compilation activities are delegated to more specific routines. Most notable delegated compilation aspects are:
* - Containers support. See \ref xreate::containers.
* - Latex compilation. See \ref xreate::latex.
* - Interpretation support. See \ref xreate::interpretation.
* - Loop saturation support. See \ref xreate::compilation::TransformationsScopeDecorator.
* - External code interaction support. See \ref xreate::ExternLayer (wrapper over Clang library).
*
* \section adaptability_sect Adaptability
* xreate::CompilePass's behaviour can be adapted in several ways:
* - %Function Decorators to alter function-level compilation. See \ref xreate::compilation::IBruteFunction
* - Code Block Decorators to alter code block level compilation. See \ref xreate::compilation::ICodeScopeUnit.
* Default functionality defined by \ref xreate::compilation::DefaultCodeScopeUnit
* - Targets to allow more versitile extensions.
* Currently only xreate::interpretation::TargetInterpretation use Targets infrastructure. See \ref xreate::compilation::Target.
* - Altering %function invocation. See \ref xreate::compilation::IFnInvocation.
*
* Clients are free to construct a compiler instantiation with the desired decorators by using \ref xreate::compilation::CompilePassCustomDecorators.
* As a handy alias, `CompilePassCustomDecorators<void, void>` constructs the default compiler.
*
*/
diff --git a/cpp/tests/arithmetics.cpp b/cpp/tests/arithmetics.cpp
new file mode 100644
index 0000000..2e7edcf
--- /dev/null
+++ b/cpp/tests/arithmetics.cpp
@@ -0,0 +1,93 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * ast.cpp
+ *
+ * Created on: 06/04/2020
+ * Author: pgess <v.melnychenko@xreate.org>
+ */
+
+#include "xreatemanager.h"
+#include "pass/compilepass.h"
+
+#include "gtest/gtest.h"
+
+using namespace xreate;
+using namespace std;
+
+typedef bool (*FnB_NoA)();
+TEST(Arithmetics, Logic_OpAnd1)
+{
+ string code = R"Code(
+ test = function:: bool; entry() { true AND false and true }
+ )Code";
+ XreateManager* xreate = XreateManager::prepare(move(code));
+ FnB_NoA program = (FnB_NoA) xreate->run();
+
+ bool result = program();
+ ASSERT_EQ(false, result);
+}
+
+TEST(Arithmetics, Logic_OpOr1)
+{
+ string code = R"Code(
+ test = function:: bool; entry() { true AND false OR true }
+ )Code";
+ XreateManager* xreate = XreateManager::prepare(move(code));
+ FnB_NoA program = (FnB_NoA) xreate->run();
+
+ bool result = program();
+ ASSERT_EQ(true, result);
+}
+
+TEST(Arithmetics, Logic_OpNeg1)
+{
+ string code = R"Code(
+ test = function:: bool; entry() { -((true AND false)::bool) }
+ )Code";
+ XreateManager* xreate = XreateManager::prepare(move(code));
+ FnB_NoA program = (FnB_NoA) xreate->run();
+
+ bool result = program();
+ ASSERT_EQ(true, result);
+}
+
+TEST(Arithmetics, Logic_DeMorgan1)
+{
+ string code = R"Code(
+test = function:: bool; entry()
+{
+ xs = {false, true}:: [bool].
+ ys = xs :: [bool]; csize(2).
+
+ loop fold(xs->x:: bool, true ->acc):: bool
+ {
+ loop fold(ys->y:: bool, true ->acc):: bool
+ {
+ test = (-((x and y)::bool)) == (-x OR -y):: bool.
+
+ test AND acc
+ } AND acc
+ }
+}
+)Code";
+ XreateManager* xreate = XreateManager::prepare(move(code));
+ FnB_NoA program = (FnB_NoA) xreate->run();
+
+ bool result = program();
+ ASSERT_EQ(true, result);
+}
+
+TEST(Arithmetics, Logic_If1){
+ string code = R"Code(
+test = function:: bool; entry()
+{
+ if (true, false, true):: bool {true} else {false}
+}
+)Code";
+ XreateManager* xreate = XreateManager::prepare(move(code));
+ FnB_NoA program = (FnB_NoA) xreate->run();
+
+ bool result = program();
+ ASSERT_EQ(false, result);
+}
\ No newline at end of file
diff --git a/grammar/xreate.ATG b/grammar/xreate.ATG
index 42ffdbd..594bccf 100644
--- a/grammar/xreate.ATG
+++ b/grammar/xreate.ATG
@@ -1,828 +1,835 @@
//TODO add ListLiteral
//TODO ExprTyped: assign default(none) type
#include "ast.h"
#include "ExternLayer.h"
#include <string>
#include <stack>
#include <sstream>
#define wprintf(format, ...) \
char __buffer[100]; \
wcstombs(__buffer, format, 100); \
fprintf(stderr, __buffer, __VA_ARGS__)
using namespace std;
COMPILER Xreate
details::inconsistent::AST* root = nullptr; // current program unit
void SemErr(std::initializer_list<std::wstring> msgs){
std::wstringstream output;
for(const auto& msg: msgs){output << msg;}
SemErr(output.str().c_str());
}
void ensureInitalizedAST(){
if (root == nullptr) root = new details::inconsistent::AST();
}
struct {
std::stack<CodeScope*> scopesOld;
CodeScope* scope = nullptr;
} context;
void pushContextScope(CodeScope* scope){
context.scopesOld.push(context.scope);
context.scope = scope;
}
void popContextScope(){
context.scope = context.scopesOld.top();
context.scopesOld.pop();
}
int nextToken()
{
scanner->ResetPeek();
return scanner->Peek()->kind;
}
bool checkTokenAfterIdent(int key){
if (la->kind != _ident) return false;
return nextToken() == key;
}
bool checkParametersList()
{
return la->kind == _ident && nextToken() == _lparen;
}
bool checkInfix()
{
return la->kind == _ident && nextToken() == _ident;
}
bool checkIndex()
{
return la->kind == _ident && nextToken() == _lbrack;
}
bool checkListIndex()
{
return la->kind == _lcurbrack && nextToken() == _lbrack;
}
bool checkFuncDecl()
{
if (la->kind != _ident) return false;
int token2 = nextToken();
int token3 = scanner->Peek()->kind;
return token2 == _assign && token3 == _function;
}
bool checkAssignment()
{
if (la->kind != _ident) return false;
scanner->ResetPeek();
int token2 = scanner->Peek()->kind;
if (token2 == _lcurbrack) {
scanner->Peek();
int token3 = scanner->Peek()->kind;
if (token3 != _rcurbrack) return false;
int token4 = scanner->Peek()->kind;
return token4 == _assign;
}
return token2 == _assign;
}
void recognizeIdentifier(Expression& id, const std::wstring& hint){
if (!context.scope)
SemErr({L"Identifier found in undefined scope: ", hint});
if (!context.scope->recognizeIdentifier(id)){
root->postponeIdentifier(context.scope, id);
}
}
enum SwitchKind{SWITCH_NORMAL, SWITCH_META};
CHARACTERS
letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".
any = ANY - '"'.
digit = "0123456789".
cr = '\r'.
lf = '\n'.
tab = '\t'.
TOKENS
ident = (letter ['-' letter] | '_') {letter ['-' letter] | digit | '_' }.
number = digit{digit}.
string = '"' { any } '"'.
function = "function".
comma = ','.
period = '.'.
lparen = '('.
rparen = ')'.
lbrack = '['.
rbrack = ']'.
lcurbrack = '{'.
rcurbrack = '}'.
equal = "==".
assign = '='.
implic = '-' '>'.
colon = ':'.
tagcolon = "::".
lse = "<=".
lss = "<".
gte = ">=".
gtr = ">".
ne1 = "!=".
ne2= "<>".
COMMENTS FROM "/*" TO "*/" NESTED
COMMENTS FROM "//" TO lf
IGNORE cr + lf + tab
PRODUCTIONS
Xreate = (. Function* function; ensureInitalizedAST(); .)
{( //RuleDecl
InterfaceData | Imprt | GuardSection
| IF(checkFuncDecl()) FDecl<function> (. root->add(function); .)
| TDecl
| SkipModulesSection
)} (. .)
.
Ident<std::wstring& name>=
ident (. name = t->val; .).
// recognition
IdentR<Expression &e> = (. std::wstring name; .)
Ident<name> (. e = Expression(Atom<Identifier_t>(name)); .)
(. recognizeIdentifier(e, name); .).
//versioning
IdentV<Expression& e>= (. std::wstring name; .)
Ident<name> (. e = Expression(Atom<Identifier_t>(name)); .)
[ Version<e> ].
//recognition + versioning
IdentVR<Expression& e>= (. std::wstring name; .)
Ident<name> (. e = Expression(Atom<Identifier_t>(name)); .)
[ Version<e> ] (. recognizeIdentifier(e, name); .)
.
Version<Expression &e>=
lcurbrack (
ident (. SemErr({L"var version as ident is not implemented yet"}); .)
| number (. Attachments::put<versions::VariableVersion>(e, Atom<Number_t>(t->val).get()); .)
) rcurbrack .
FDecl<Function*& f> = (. std::wstring fname; std::wstring argName; TypeAnnotation typIn; TypeAnnotation typOut; Expression binding; .)
Ident<fname> assign
function (. f = new Function(fname); CodeScope* entry = f->getEntryScope(); .)
[lparen Ident<argName> tagcolon ExprAnnotations<binding> (. f->addBinding(Atom<Identifier_t>(argName), move(binding)); .)
{comma Ident<argName> tagcolon ExprAnnotations<binding> (. f->addBinding(Atom <Identifier_t>(argName), move(binding));.)
} rparen]
[ tagcolon Type<typOut> {';' FnTag<f> }]
BDecl<entry> (. const_cast<Expression&>(entry->getBody()).bindType(move(typOut));.)
.
GuardSection<>= (. std::wstring arg, guardI; Expression guardE, guardBinding; Function* f; TypeAnnotation guardT; .)
"guard" lparen
[Ident<arg>] tagcolon Ident<guardI> (. guardE = Expression(Operator::CALL, {Atom<Identifier_t>(guardI)}); bool res = root->recognizeVariantConstructor(guardE); .)
(. if(!res) SemErr(coco_string_create("Can't recognize a guard"));.)
(. if (!arg.empty()) guardE.addBindings({Atom<Identifier_t>(arg)}); .)
(. guardBinding.type = TypeAnnotation(TypeOperator::GUARD, {guardE.type}); guardBinding.type.__valueCustom = Atom<Identifier_t>(guardI).get(); .)
rparen lcurbrack {
FDecl<f> (. f->guard = guardE; if (!arg.empty()){f->addBinding(Atom<Identifier_t>(arg), Expression(guardBinding));} .)
(. root->add(f); .)
} rcurbrack
.
/**
* TYPES
*
*/
TypeTerm<TypePrimitive& typ> = (. std::wstring tid; .)
( "string" (. typ = TypePrimitive::String;.)
| "int" (. typ = TypePrimitive::Int;.)
| "float" (. typ = TypePrimitive::Float;.)
| "bool" (. typ = TypePrimitive::Bool; .)
| "i8" (. typ = TypePrimitive::I8; .)
| "i32" (. typ = TypePrimitive::I32; .)
| "i64" (. typ = TypePrimitive::I64; .)
).
Type<TypeAnnotation& typ> = (. TypeAnnotation typ2; TypePrimitive typ3; std::wstring tid; std::string field; .)
(
TList<typ>
| TRecord<typ>
| TVariant<typ>
| TPred<typ>
| TSlave<typ>
| TRef<typ>
| TypeTerm<typ3> (. typ = typ3; .)
| IF (checkIndex()) Ident<tid> lbrack
TypeIndex<field> (. typ = TypeAnnotation(TypeOperator::ACCESS, {}); typ.__valueCustom = Atom<Identifier_t>(tid).get(); typ.fields.push_back(field); .)
{comma TypeIndex<field> (. typ.fields.push_back(field); .)
} rbrack
| Ident<tid> (. typ = TypeAnnotation(TypeOperator::ALIAS, {}); typ.__valueCustom = Atom<Identifier_t>(tid).get(); .)
[lparen Type<typ2> (. typ.__operands.push_back(typ2); .)
{comma Type<typ2> (. typ.__operands.push_back(typ2); .)
} rparen]
| '*' (.typ = TypeAnnotation(); .)
) .
TypeIndex<std::string& name> =
(
number (. name = Atom<Identifier_t>(t->val).get(); .)
| string (. name = Atom<String_t>(t->val).get(); .)
)
.
TList<TypeAnnotation& typ> = (. TypeAnnotation ty; .)
lbrack Type<ty> rbrack (. typ = TypeAnnotation(TypeOperator::ARRAY, {ty}); .)
.
TRecordBody<TypeAnnotation& typ> =
(. TypeAnnotation t; std::wstring key; size_t keyCounter=0;
typ = TypeAnnotation(TypeOperator::RECORD, {});
.)
{
(
IF(checkTokenAfterIdent(_tagcolon)) Ident<key> tagcolon
| (. key = to_wstring(keyCounter++); .)
)
Type<t> [comma] (. typ.__operands.push_back(t); .)
(. typ.fields.push_back(Atom<Identifier_t>(key).get()); .)
}.
TRecord<TypeAnnotation& typ> =
lcurbrack TRecordBody<typ> rcurbrack
(. if(!typ.__operands.size()) SemErr(coco_string_create("Record type can't be empty.")); .)
.
TVariantRec<TypeAnnotation& typ> = (. TypeAnnotation typVoid; .)
lparen TRecordBody<typ> rparen
(. if(typ.__operands.size()==0) typ = typVoid; .)
.
TVariantBody<TypeAnnotation& typ> = (. TypeAnnotation t, typVoid; std::vector<TypeAnnotation> operands; std::vector<Atom<Identifier_t>> keys; std::wstring v; .)
lcurbrack
{ (. t = typVoid; .)
Ident<v> [TVariantRec<t>] (. keys.push_back(Atom<Identifier_t>(v)); operands.push_back(t); .)
[comma]
}
rcurbrack
(. typ = TypeAnnotation(TypeOperator::VARIANT, {});
typ.__operands = operands;
typ.addFields(std::move(keys));
.)
.
TVariant<TypeAnnotation& typ>=
"variant" TVariantBody<typ>
(. if(!typ.__operands.size()) SemErr(coco_string_create("Variant type can't be empty.")); .)
.
TPred<TypeAnnotation& typ>=
"predicate" TVariantBody<typ>
(. if(!typ.__operands.size()) SemErr(coco_string_create("Predicate type can't be empty.")); .)
.
TSlave<TypeAnnotation& typ>=
"slave" (. typ = TypeAnnotation(TypeOperator::SLAVE, {}); .)
lparen
string (. typ.__valueCustom = Atom<String_t>(t->val).get(); .)
rparen
.
TRef<TypeAnnotation& typ>= (. TypeAnnotation typChild; .)
"ref" lparen Type<typChild> rparen (. typ = TypeAnnotation(TypeOperator::REF, {typChild}); .)
.
TDecl = (. TypeAnnotation t; std::wstring tname, arg; std::vector<Atom<Identifier_t>> args; .)
Ident<tname> assign "type"
[lparen Ident<arg> (. args.push_back(Atom<Identifier_t>(arg)); .)
{comma Ident<arg> (. args.push_back(Atom<Identifier_t>(arg)); .)
} rparen]
Type<t>[period] (. t.addBindings(move(args)); root->add(move(t), Atom<Identifier_t>(tname)); .)
.
ContextDecl<CodeScope * scope> = (. Expression tag; .)
"context" tagcolon
MetaSimpExpr<tag> (. scope->tags.push_back(tag); .)
{';' MetaSimpExpr<tag> (. scope->tags.push_back(tag); .)
}.
VDecl<CodeScope* f> = (. Expression var, value;.)
IdentV<var> assign ExprTyped<value> (. Symbol identSymbol = f->addDefinition(move(var), move(value));
Attachments::put<ExprAlias_A>(value, identSymbol);
.)
.
BDecl<CodeScope* scope> = lcurbrack (. Expression body; pushContextScope(scope); bool flagBodyFound = false; .)
{(IF(checkAssignment()) VDecl<scope> period
// | RuleContextDecl<scope>
| ContextDecl<scope>period
| ExprTyped<body> (. scope->setBody(body); flagBodyFound = true; Attachments::put<ExprAlias_A>(body, Symbol{ScopedSymbol::RetSymbol, scope});.)
)}
rcurbrack (. if(!flagBodyFound) SemErr(coco_string_create("Code block with an empty body!"));
popContextScope();
.)
.
-IfDecl<Expression& e> = (. Expression cond; ManagedScpPtr blockTrue = root->add(new CodeScope(context.scope)); ManagedScpPtr blockFalse = root->add(new CodeScope(context.scope)); .)
-"if" lparen Expr<cond> rparen (. e = Expression(Operator::IF, {cond}); .)
+IfDecl<Expression& e> =
+ (. Expression cond(Operator::AND, {}), condPart;
+ ManagedScpPtr blockTrue = root->add(new CodeScope(context.scope));
+ ManagedScpPtr blockFalse = root->add(new CodeScope(context.scope));
+ e = Expression(Operator::IF, {});
+ .)
+"if" lparen Expr<condPart> (. cond.operands.push_back(condPart); .)
+{ comma Expr<condPart> (. cond.operands.push_back(condPart); .)
+} rparen (. e.operands.push_back(cond); .)
tagcolon ExprAnnotations<e>
BDecl<&*blockTrue> "else" BDecl<&*blockFalse> (. e.addBlock(blockTrue); e.addBlock(blockFalse); .)
.
LoopDecl<Expression& e> =
(.
Expression eIn, eAcc, eFilters; std::wstring varEl, varAcc, contextClass; Expression tagsEl;
ManagedScpPtr block = root->add(new CodeScope(context.scope));
.)
"loop"
(
"map" lparen Expr<eIn> implic Ident<varEl>
(. e = Expression(Operator::MAP, {eIn}); .)
tagcolon ExprAnnotations<tagsEl> rparen tagcolon ExprAnnotations<e>
(.
e.addBindings({Atom<Identifier_t>(varEl)});
block->addBinding(Atom<Identifier_t>(varEl), move(tagsEl));
.)
BDecl<&*block>
(. e.addBlock(block); .)
| "fold" lparen Expr<eIn> implic Ident<varEl> tagcolon ExprAnnotations<tagsEl>
['|' Expr<eFilters> ] comma Expr<eAcc> implic Ident<varAcc>rparen
(.
e = Expression(Operator::FOLD, {eIn, eAcc});
e.addBindings({Atom<Identifier_t>(varEl), Atom<Identifier_t>(varAcc)});
.)
tagcolon ExprAnnotations<e>
(.
Expression varAccBindingE; varAccBindingE.type = e.type;
block->addBinding(Atom<Identifier_t>(varEl), move(tagsEl));
block->addBinding(Atom<Identifier_t>(varAcc), move(varAccBindingE));
.)
BDecl<&*block>
(. e.addBlock(block); .)
| lparen Expr<eAcc> implic Ident<varAcc> rparen
(.
e = Expression(Operator::FOLD_INF, {eAcc});
e.addBindings({Atom<Identifier_t>(varAcc)});
.)
tagcolon ExprAnnotations<e>
(.
Expression varAccBindingE; varAccBindingE.type = e.type;
block->addBinding(Atom<Identifier_t>(varAcc), move(varAccBindingE));
.)
BDecl<&*block>
(. e.addBlock(block); .)
).
// Switches
SwitchDecl<Expression& eSwitch, SwitchKind flagSwitchKind> = (. TypeAnnotation typ; eSwitch = Expression(Operator::SWITCH, {}); Expression eCondition; Expression tag;.)
"switch"
(
SwitchVariantDecl<eSwitch>
| SwitchLateDecl<eSwitch>
| lparen ExprTyped<eCondition> rparen tagcolon ExprAnnotations<eSwitch> (. eSwitch.operands.push_back(eCondition);.)
CaseDecl<eSwitch, flagSwitchKind> {CaseDecl<eSwitch, flagSwitchKind>}
)
.
CaseDecl<Expression& outer, SwitchKind flagSwitchKind> = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); Expression condition; .)
"case"
( IF(flagSwitchKind == SWITCH_META)
lparen MetaSimpExpr<condition> rparen BDecl<&*scope> (. Expression exprCase(Operator::CASE, {}); exprCase.addTags({condition}); exprCase.addBlock(scope); outer.addArg(move(exprCase));.)
| "default" BDecl<&*scope> (. Expression exprCase(Operator::CASE_DEFAULT, {});
exprCase.addBlock(scope);
outer.operands.insert(++outer.operands.begin(), exprCase); .)
| lparen CaseParams<&*scope> rparen (. ManagedScpPtr scopeBody = root->add(new CodeScope(&*scope)); Expression exprCase(Operator::CASE, {}); .)
BDecl<&*scopeBody> (. exprCase.addBlock(scope); exprCase.addBlock(scopeBody); outer.addArg(move(exprCase)); .)
).
CaseParams<CodeScope* scope> = (. Expression condition; Expression guard(Operator::LOGIC_AND, {}); pushContextScope(scope); .)
ExprTyped<condition> (. guard.addArg(Expression(condition)); .)
{comma ExprTyped<condition> (. guard.addArg(Expression(condition)); .)
} (. scope->setBody(guard); popContextScope(); .)
.
SwitchLateDecl<Expression& expr> =
(.
std::wstring aliasCondition; Expression exprCondition, aliasAnns;
expr = Expression(Operator::SWITCH_LATE, {});
ManagedScpPtr scope = root->add(new CodeScope(context.scope));
.)
"late" lparen Expr<exprCondition> [implic Ident<aliasCondition>] [tagcolon ExprAnnotations<aliasAnns>] rparen
tagcolon ExprAnnotations<expr> BDecl<&*scope>
(.
expr.addArg(Expression(exprCondition));
expr.addBlock(scope);
std::string alias;
if(aliasCondition.empty()){
if(exprCondition.__state != Expression::IDENT){
SemErr(coco_string_create("An identifier expected in the short form"));
return;
}
//Use exprCondition as identifier
alias = exprCondition.getValueString();
} else {
//Use aliasCondition
alias = Atom<Identifier_t>(move(aliasCondition)).get();
}
expr.addBindings({Atom<Identifier_t>(string(alias))});
scope->addBinding(Atom<Identifier_t>(move(alias)), move(aliasAnns));
.)
.
SwitchVariantDecl<Expression& expr> =
(. Expression varTested; std::wstring varAlias; bool flagAliasFound = false; expr = Expression(Operator::SWITCH_VARIANT, {}); .)
"variant" lparen Expr<varTested> [implic Ident<varAlias>
(. flagAliasFound = true; .)
] [tagcolon ExprAnnotations<varTested>] rparen tagcolon ExprAnnotations<expr>
(. expr.addArg(std::move(varTested));
if (flagAliasFound) {
expr.addBindings({Atom<Identifier_t>(varAlias)});
} else {
if(varTested.__state == Expression::IDENT){
expr.addBindings({Atom<Identifier_t>(string(varTested.getValueString()))});
}
}
.)
CaseVariantDecl<expr> {CaseVariantDecl<expr>}
.
CaseVariantDecl<Expression& expr> = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); std::wstring key; scope->addBinding(Atom<Identifier_t>(string(expr.bindings.front())), Expression()); .)
"case" lparen Ident<key> rparen (. expr.addArg(root->recognizeVariantConstructor(Atom<Identifier_t>(std::move(key)))); .)
BDecl<&*scope> (. expr.addBlock(scope); .)
.
IntrinsicDecl<Expression& outer>= (. std::wstring name; .)
"intrinsic"
(
Ident< name>
(. outer = Expression(Operator::CALL_INTRINSIC, {});
outer.setValue(Atom<Identifier_t>(name));
root->recognizeIntrinsic(outer);
.)
lparen [CalleeParams<outer>] rparen
| "query" (. outer = Expression(Operator::QUERY, {}); .)
(
"late" IntrinsicQueryLateDecl<outer>
| lparen [CalleeParams<outer>] rparen
)
).
IntrinsicQueryLateDecl<Expression& expr> =
(.
std::wstring predicateAlias; Expression predicateE, predicateAnns;
expr = Expression(Operator::QUERY_LATE, {});
ManagedScpPtr scope = root->add(new CodeScope(context.scope));
.)
lparen Expr<predicateE> implic Ident<predicateAlias> tagcolon ExprAnnotations<predicateAnns> rparen
tagcolon ExprAnnotations<expr> BDecl<&*scope>
(.
expr.addArg(move(predicateE));
expr.addBindings({Atom<Identifier_t>(wstring(predicateAlias))});
scope->addBinding(Atom<Identifier_t>(move(predicateAlias)), move(predicateAnns));
expr.addBlock(scope);
.)
.
SequenceDecl<Expression& sequence> = (. sequence = Expression(); sequence.setOp(Operator::SEQUENCE); ManagedScpPtr scope = root->add(new CodeScope(context.scope)); .)
"seq" BDecl<&*scope> (. sequence.blocks.push_back(&*scope); scope = root->add(new CodeScope(&*scope)); .)
{ (. scope = root->add(new CodeScope(&*scope)); .)
BDecl<&*scope> (. sequence.blocks.push_back(&*scope); .)
}.
/*============================ INTERFACES ===============================*/
Imprt<> =
"import" "raw" lparen string (. root->__rawImports.push_back(Atom<String_t>(t->val).get()); .)
rparen period.
InterfaceData<> = "interface" lparen
( "dfa" rparen InterfaceDFA
// | "extern-c" rparen InterfaceExternC
| "cfa" rparen InterfaceCFA
).
// InterfaceExternC<> = (. ExternData data; .)
// lcurbrack {ExternHeadersDecl<data> | ExternAliasDecl<data> } rcurbrack
// (. root->addExternData(move(data)); .)
// .
//
// ExternPkgDecl<std::wstring& package> =
// "pkgconfig" lparen
// string (. package = t->val.)
// rparen
// .
//
// ExternAliasDecl<ExternData& data> = (. std::wstring alias, package; .)
// Ident<alias> assign "library" lparen ExternPkgDecl<package> rparen period
// (. data.addLibAlias(Atom<Identifier_t>(alias), Atom<String_t>(package)); .)
// .
//
// ExternHeadersDecl<ExternData& data> = (. std::list<std::string> listInc; std::wstring& package; .)
// "include"
// [lparen
// (
// Ident<alias> (. data.requireLibAlias(Atom<Identifier_t>(alias)); .)
// | ExternPkgDecl<package> (. data.requireLibPackage(Atom<String_t>(package)); .)
// )
// rparen]
// lcurbrack { string (. listInc.push_back(Atom<String_t>(t->val).get()); .)
// [comma] } rcurbrack [period] (. data.requireHeaders(listInc); .)
// .
InterfaceDFA<> = lcurbrack { InstructDecl } rcurbrack .
InstructDecl = (.Operator op; Expression tag;
Expression scheme;
std::vector<Expression>& tags = scheme.operands;
tags.push_back(Expression()); /* return value */ .)
"operator" InstructAlias<op> tagcolon lparen (.scheme.setOp(op); .)
[
MetaSimpExpr<tag> (. tags.push_back(tag); .)
{
comma MetaSimpExpr<tag> (. tags.push_back(tag); .)
}
] rparen [ implic MetaSimpExpr<tag> (. tags[0] = tag; .)
] (. root->addDFAData(move(scheme)); .)
period.
InstructAlias<Operator& op> =
(
"map" (. op = Operator::MAP; .)
| "list_range" (. op = Operator::LIST_RANGE; .)
| "list" (. op = Operator::LIST; .)
| "fold" (. op = Operator::FOLD; .)
| "index" (. op = Operator::INDEX; .)
).
InterfaceCFA<> = lcurbrack { InstructCFADecl } rcurbrack .
InstructCFADecl<> = (.Operator op; Expression tag;
Expression scheme;
std::vector<Expression>& tags = scheme.operands; .)
"operator" InstructAlias<op> tagcolon (. scheme.setOp(op); .)
[
MetaSimpExpr<tag> (. tags.push_back(tag); .)
{
comma MetaSimpExpr<tag> (. tags.push_back(tag); .)
}
] period (. root->addInterfaceData(CFA, move(scheme)); .).
/*============================ METAPROGRAMMING ===============================*/
// TagsDecl<CodeScope* f> = (. Expression tag; TagModifier mod = TagModifier::NONE; .)
// ':' { MetaSimpExpr<tag> (. /*f.addTag(std::move(tag), mod); */ .)
// }.
FnTag<Function* f> = (. Expression tag; TagModifier mod = TagModifier::NONE; .)
MetaSimpExpr<tag>
['-' TagMod<mod>] (. f->addTag(std::move(tag), mod); .).
TagMod<TagModifier& mod> =
( "assert" (. mod = TagModifier::ASSERT; .)
| "require" (. mod = TagModifier::REQUIRE; .)
).
// RuleDecl<> =
// "rule" tagcolon (. RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg; .)
// lparen Ident<arg> tagcolon Domain<typ> (. args.add(arg, typ); .)
// {comma Ident<arg> tagcolon Domain<typ> (. args.add(arg, typ); .)
// } rparen
// ["case" RGuard<guards> {comma RGuard<guards>}]
// lcurbrack RBody<args, guards> rcurbrack .
/* - TODO use RGuard for guards-*/
// RuleContextDecl<CodeScope* scope> = (.Expression eHead, eGuards, eBody; .)
// "rule" "context" tagcolon MetaSimpExpr<eHead>
// "case" lparen MetaSimpExpr<eGuards> rparen
// lcurbrack MetaSimpExpr<eBody> rcurbrack (.scope->contextRules.push_back(Expression(Operator::CONTEXT_RULE, {eHead, eGuards, eBody})); .).
// Domain<DomainAnnotation& dom> =
// (
// "function" (. dom = DomainAnnotation::FUNCTION; .)
// | "variable" (. dom = DomainAnnotation::VARIABLE; .)
// ).
// RGuard<RuleGuards& guards>= (. Expression e; .)
// MetaExpr<e> (. guards.add(std::move(e)); .).
// MetaExpr<Expression& e>= (.Operator op; Expression e2; .)
// MetaExpr2<e>
// [MetaOp<op> MetaExpr2<e2> (. e = Expression(op, {e, e2}); .)
// ].
// MetaExpr2<Expression& e>=
// (
// lparen MetaExpr<e> rparen
// | MetaSimpExpr<e>
// ).
MetaSimpExpr<Expression& e>= (. std::wstring i1, infix; Expression e2; .)
(
'-' MetaSimpExpr<e2> (. e = Expression(Operator::NEG, {e2}); .)
| IF(checkParametersList()) Ident<i1>
(. e = Expression(Operator::CALL, {Expression(Atom<Identifier_t>(i1))});
if (!root->recognizeVariantConstructor(e))
SemErr({L"Undefined predicate: ", i1});
.)
lparen [ MetaCalleeParams<e> ] rparen
| IF(checkInfix()) Ident<i1> Ident<infix> MetaSimpExpr<e2>
(. e = Expression(Operator::CALL, {Expression(Atom<Identifier_t>(infix))});
e.addArg(Expression(Atom<Identifier_t>(i1)));
e.addArg(std::move(e2));
.)
| IdentR<e>
| number (. e = Expression(Atom<Number_t>(t->val)); .)
).
MetaCalleeParams<Expression& e> = (. Expression e2; .)
MetaSimpExpr<e2> (. e.addArg(Expression(e2)); .)
{comma MetaSimpExpr<e2> (. e.addArg(Expression(e2)); .)
}.
// RBody<const RuleArguments& args, const RuleGuards& guards> =
// (. Expression e; std::wstring msg; .)
// "warning" MetaExpr<e> ["message" string (. msg = t->val; .)
// ] (. root->add(new RuleWarning(RuleArguments(args), RuleGuards(guards), std::move(e), Atom<String_t>(msg))); .)
// .
// MetaOp< Operator& op> =
// implic (. op = Operator::IMPL; .)
// .
/*============================ Expressions ===============================*/
ExprAnnotations<Expression& e> = (. TypeAnnotation typ; std::list<Expression> tags; Expression tag; e.tags.clear();.)
Type<typ> (. e.bindType(move(typ)); .)
{';' MetaSimpExpr<tag> (. tags.push_back(tag); .)
} (. e.addTags(tags); .)
.
ExprTyped<Expression&e> = Expr<e> [tagcolon ExprAnnotations<e>].
Expr< Expression& e> (. Expression e2; .)
= ExprLogicAnd<e>
- [ ('or' | 'OR') Expr<e2> (. e = Expression(Operator::OR, {e, e2}); .)
+ [ ("or" | "OR") Expr<e2> (. e = Expression(Operator::OR, {e, e2}); .)
]
.
ExprLogicAnd< Expression& e> (. Expression e2; .)
= ExprRel<e>
- [ ('and' | 'AND') ExprLogicAnd <e2> (. e = Expression(Operator::AND, {e, e2}); .)
+ [ ("and" | "AND") ExprLogicAnd <e2> (. e = Expression(Operator::AND, {e, e2}); .)
]
.
ExprRel< Expression& e> (. Operator op; Expression e2; .)
= ExprArithmAdd<e>
[ RelOp<op> ExprRel<e2> (. e = Expression(op, {e, e2}); .)
]
.
ExprArithmAdd< Expression& e>= (. Operator op; Expression e2; .)
ExprArithmMul< e>
[
AddOp<op>ExprArithmAdd< e2> (. e = Expression(op, {e, e2});.)
].
ExprArithmMul< Expression& e> (. Operator op; Expression e2; .)
= ExprUpdate<e>
[ MulOp< op>
ExprArithmMul< e2> (. e = Expression(op, {e, e2}); .)
].
ExprUpdate<Expression& e>= (. Expression e2; .)
ExprPostfix< e>
[
colon
( IF(checkListIndex()) ListIndexLiteral<e2>
| ListLiteral<e2>) (. e = Expression(Operator::UPDATE, {e, e2}); .)
].
ExprPostfix<Expression& e>
= Term<e>
[ (. e = Expression(Operator::INDEX, {e}); .)
{lbrack CalleeParams<e> rbrack }
].
Term< Expression& e> (. std::wstring name; e = Expression(); .)
=
(IF (checkParametersList()) Ident< name>
(. e = Expression(Operator::CALL, {Atom<Identifier_t>(name)}); root->recognizeVariantConstructor(e); .)
lparen [CalleeParams<e>] rparen
| IdentVR<e>
| ListLiteral<e>
| ListRangeLiteral<e>
| LoopDecl<e>
| IfDecl<e>
| SwitchDecl<e, SWITCH_NORMAL>
| IntrinsicDecl<e>
| SequenceDecl<e>
| number (. e = Expression(Atom<Number_t>(t->val)); .)
| string (. e = Expression(Atom<String_t>(t->val)); .)
| "true" (. e = Expression(Atom<Number_t>(1)); e.bindType(TypePrimitive::Bool); .)
| "false" (. e = Expression(Atom<Number_t>(0)); e.bindType(TypePrimitive::Bool); .)
| "undef" (. e = Expression(Operator::UNDEF, {}); .)
| '-' Term<e> (. e = Expression(Operator::NEG, {e}); .)
| lparen ExprTyped<e> rparen
).
ListLiteral<Expression& e> = (. std::wstring key;
Expression val;
std::list<Atom<Identifier_t>> keys;
e = Expression(Operator::LIST, {});
.)
lcurbrack {
( IF(checkTokenAfterIdent(_assign)) Ident<key> assign
| (. key = L""; .)
) Expr<val> (. keys.push_back(Atom<Identifier_t>(key));
e.operands.push_back(val);
.)
[comma] } rcurbrack (. e.addBindings(keys.begin(), keys.end()); .)
.
ListIndexLiteral<Expression& e> = (. e = Expression(Operator::LIST_INDEX, {});Expression valE;.)
lcurbrack
{ (. Expression idxE(Operator::LIST, {});.)
lbrack CalleeParams<idxE> rbrack
assign Expr<valE>[comma] (. e.operands.push_back(idxE); e.operands.push_back(valE); .)
}
rcurbrack
.
ListRangeLiteral<Expression& e> = (. Expression eFrom, eTo; .)
lbrack Expr<eFrom> ".." Expr<eTo> rbrack (. e = Expression(Operator::LIST_RANGE, {eFrom, eTo}); .)
.
CalleeParams<Expression& e> = (. Expression e2; .)
ExprTyped<e2> (. e.addArg(Expression(e2)); .)
{comma ExprTyped<e2> (. e.addArg(Expression(e2)); .)
}.
AddOp< Operator& op>
= (. op = Operator::ADD; .)
( '+'
| '-' (. op = Operator::SUB; .)
).
MulOp< Operator& op>
= (. op = Operator::MUL; .)
( '*'
| '/' (. op = Operator::DIV; .)
).
RelOp< Operator& op>
= (. op = Operator::EQU; .)
( equal
| (ne1 | ne2) (. op = Operator::NE; .)
| lse (. op = Operator::LSE; .)
| lss (. op = Operator::LSS; .)
| gte (. op = Operator::GTE; .)
| gtr (. op = Operator::GTR; .)
).
SkipModulesSection = "module" {ANY} (lcurbrack {ANY} rcurbrack | '.').
END Xreate.
Event Timeline
Log In to Comment