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 * * 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 #include 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 BasicBruteFunction::prepareSignature() { LLVMLayer* llvm = IBruteFunction::pass->man->llvm; AST* ast = IBruteFunction::pass->man->root; CodeScope* entry = IBruteFunction::function->__entry; std::vector 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&& args, const std::string& hintDecl) { llvm::Function* calleeInfo = dyn_cast(__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&& 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&& 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(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& 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(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 callee(findFunction(expr)); const std::string& nameCallee = expr.getValueString(); //prepare arguments std::vector 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 fieldsFormal = helper.getRecordFields(exprT); containers::RecordIR irRecords(ctx); llvm::StructType *recordTRaw = llvm::cast(l.toLLVMType(exprT)); llvm::Value *resultRaw = irRecords.init(recordTRaw); return irRecords.update(resultRaw, exprT, expr); } case ARRAY: { std::unique_ptr 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 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 indexes; std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()), [this] (const Expression & op) { return process(op); } ); std::unique_ptr containersIR( containers::IContainersIR::create(aggrE, expectedT, ctx) ); containers::ArrayIR* arraysIR = static_cast(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::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(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({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(expr.operands.at(fieldId), typField); llvm::Value* fieldRaw = process(expr.operands.at(fieldId)); assert(fieldRaw); variantRaw = l.irBuilder.CreateInsertValue(variantRaw, fieldRaw, llvm::ArrayRef({fieldId})); } llvm::Type* typStorageRaw = llvm::cast(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({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 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(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&& types = prepareSignature(); llvm::Type* expectedResultType = prepareResult(); llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false); raw = llvm::cast(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 unit(pass->buildCodeScopeUnit(scope, this)); if (scope->__parent != nullptr) { auto parentUnit = Decorators::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 ::buildFunctionUnit(const ManagedFnPtr& function) { return new BruteFunctionDefault(function, this); } template<> compilation::IBruteScope* CompilePassCustomDecorators ::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(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` 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 + */ + +#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 #include #include #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 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 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 (. root->add(function); .) | TDecl | SkipModulesSection )} (. .) . Ident= ident (. name = t->val; .). // recognition IdentR = (. std::wstring name; .) Ident (. e = Expression(Atom(name)); .) (. recognizeIdentifier(e, name); .). //versioning IdentV= (. std::wstring name; .) Ident (. e = Expression(Atom(name)); .) [ Version ]. //recognition + versioning IdentVR= (. std::wstring name; .) Ident (. e = Expression(Atom(name)); .) [ Version ] (. recognizeIdentifier(e, name); .) . Version= lcurbrack ( ident (. SemErr({L"var version as ident is not implemented yet"}); .) | number (. Attachments::put(e, Atom(t->val).get()); .) ) rcurbrack . FDecl = (. std::wstring fname; std::wstring argName; TypeAnnotation typIn; TypeAnnotation typOut; Expression binding; .) Ident assign function (. f = new Function(fname); CodeScope* entry = f->getEntryScope(); .) [lparen Ident tagcolon ExprAnnotations (. f->addBinding(Atom(argName), move(binding)); .) {comma Ident tagcolon ExprAnnotations (. f->addBinding(Atom (argName), move(binding));.) } rparen] [ tagcolon Type {';' FnTag }] BDecl (. const_cast(entry->getBody()).bindType(move(typOut));.) . GuardSection<>= (. std::wstring arg, guardI; Expression guardE, guardBinding; Function* f; TypeAnnotation guardT; .) "guard" lparen [Ident] tagcolon Ident (. guardE = Expression(Operator::CALL, {Atom(guardI)}); bool res = root->recognizeVariantConstructor(guardE); .) (. if(!res) SemErr(coco_string_create("Can't recognize a guard"));.) (. if (!arg.empty()) guardE.addBindings({Atom(arg)}); .) (. guardBinding.type = TypeAnnotation(TypeOperator::GUARD, {guardE.type}); guardBinding.type.__valueCustom = Atom(guardI).get(); .) rparen lcurbrack { FDecl (. f->guard = guardE; if (!arg.empty()){f->addBinding(Atom(arg), Expression(guardBinding));} .) (. root->add(f); .) } rcurbrack . /** * TYPES * */ TypeTerm = (. 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 typ2; TypePrimitive typ3; std::wstring tid; std::string field; .) ( TList | TRecord | TVariant | TPred | TSlave | TRef | TypeTerm (. typ = typ3; .) | IF (checkIndex()) Ident lbrack TypeIndex (. typ = TypeAnnotation(TypeOperator::ACCESS, {}); typ.__valueCustom = Atom(tid).get(); typ.fields.push_back(field); .) {comma TypeIndex (. typ.fields.push_back(field); .) } rbrack | Ident (. typ = TypeAnnotation(TypeOperator::ALIAS, {}); typ.__valueCustom = Atom(tid).get(); .) [lparen Type (. typ.__operands.push_back(typ2); .) {comma Type (. typ.__operands.push_back(typ2); .) } rparen] | '*' (.typ = TypeAnnotation(); .) ) . TypeIndex = ( number (. name = Atom(t->val).get(); .) | string (. name = Atom(t->val).get(); .) ) . TList = (. TypeAnnotation ty; .) lbrack Type rbrack (. typ = TypeAnnotation(TypeOperator::ARRAY, {ty}); .) . TRecordBody = (. TypeAnnotation t; std::wstring key; size_t keyCounter=0; typ = TypeAnnotation(TypeOperator::RECORD, {}); .) { ( IF(checkTokenAfterIdent(_tagcolon)) Ident tagcolon | (. key = to_wstring(keyCounter++); .) ) Type [comma] (. typ.__operands.push_back(t); .) (. typ.fields.push_back(Atom(key).get()); .) }. TRecord = lcurbrack TRecordBody rcurbrack (. if(!typ.__operands.size()) SemErr(coco_string_create("Record type can't be empty.")); .) . TVariantRec = (. TypeAnnotation typVoid; .) lparen TRecordBody rparen (. if(typ.__operands.size()==0) typ = typVoid; .) . TVariantBody = (. TypeAnnotation t, typVoid; std::vector operands; std::vector> keys; std::wstring v; .) lcurbrack { (. t = typVoid; .) Ident [TVariantRec] (. keys.push_back(Atom(v)); operands.push_back(t); .) [comma] } rcurbrack (. typ = TypeAnnotation(TypeOperator::VARIANT, {}); typ.__operands = operands; typ.addFields(std::move(keys)); .) . TVariant= "variant" TVariantBody (. if(!typ.__operands.size()) SemErr(coco_string_create("Variant type can't be empty.")); .) . TPred= "predicate" TVariantBody (. if(!typ.__operands.size()) SemErr(coco_string_create("Predicate type can't be empty.")); .) . TSlave= "slave" (. typ = TypeAnnotation(TypeOperator::SLAVE, {}); .) lparen string (. typ.__valueCustom = Atom(t->val).get(); .) rparen . TRef= (. TypeAnnotation typChild; .) "ref" lparen Type rparen (. typ = TypeAnnotation(TypeOperator::REF, {typChild}); .) . TDecl = (. TypeAnnotation t; std::wstring tname, arg; std::vector> args; .) Ident assign "type" [lparen Ident (. args.push_back(Atom(arg)); .) {comma Ident (. args.push_back(Atom(arg)); .) } rparen] Type[period] (. t.addBindings(move(args)); root->add(move(t), Atom(tname)); .) . ContextDecl = (. Expression tag; .) "context" tagcolon MetaSimpExpr (. scope->tags.push_back(tag); .) {';' MetaSimpExpr (. scope->tags.push_back(tag); .) }. VDecl = (. Expression var, value;.) IdentV assign ExprTyped (. Symbol identSymbol = f->addDefinition(move(var), move(value)); Attachments::put(value, identSymbol); .) . BDecl = lcurbrack (. Expression body; pushContextScope(scope); bool flagBodyFound = false; .) {(IF(checkAssignment()) VDecl period // | RuleContextDecl | ContextDeclperiod | ExprTyped (. scope->setBody(body); flagBodyFound = true; Attachments::put(body, Symbol{ScopedSymbol::RetSymbol, scope});.) )} rcurbrack (. if(!flagBodyFound) SemErr(coco_string_create("Code block with an empty body!")); popContextScope(); .) . -IfDecl = (. Expression cond; ManagedScpPtr blockTrue = root->add(new CodeScope(context.scope)); ManagedScpPtr blockFalse = root->add(new CodeScope(context.scope)); .) -"if" lparen Expr rparen (. e = Expression(Operator::IF, {cond}); .) +IfDecl = + (. 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 (. cond.operands.push_back(condPart); .) +{ comma Expr (. cond.operands.push_back(condPart); .) +} rparen (. e.operands.push_back(cond); .) tagcolon ExprAnnotations BDecl<&*blockTrue> "else" BDecl<&*blockFalse> (. e.addBlock(blockTrue); e.addBlock(blockFalse); .) . LoopDecl = (. Expression eIn, eAcc, eFilters; std::wstring varEl, varAcc, contextClass; Expression tagsEl; ManagedScpPtr block = root->add(new CodeScope(context.scope)); .) "loop" ( "map" lparen Expr implic Ident (. e = Expression(Operator::MAP, {eIn}); .) tagcolon ExprAnnotations rparen tagcolon ExprAnnotations (. e.addBindings({Atom(varEl)}); block->addBinding(Atom(varEl), move(tagsEl)); .) BDecl<&*block> (. e.addBlock(block); .) | "fold" lparen Expr implic Ident tagcolon ExprAnnotations ['|' Expr ] comma Expr implic Identrparen (. e = Expression(Operator::FOLD, {eIn, eAcc}); e.addBindings({Atom(varEl), Atom(varAcc)}); .) tagcolon ExprAnnotations (. Expression varAccBindingE; varAccBindingE.type = e.type; block->addBinding(Atom(varEl), move(tagsEl)); block->addBinding(Atom(varAcc), move(varAccBindingE)); .) BDecl<&*block> (. e.addBlock(block); .) | lparen Expr implic Ident rparen (. e = Expression(Operator::FOLD_INF, {eAcc}); e.addBindings({Atom(varAcc)}); .) tagcolon ExprAnnotations (. Expression varAccBindingE; varAccBindingE.type = e.type; block->addBinding(Atom(varAcc), move(varAccBindingE)); .) BDecl<&*block> (. e.addBlock(block); .) ). // Switches SwitchDecl = (. TypeAnnotation typ; eSwitch = Expression(Operator::SWITCH, {}); Expression eCondition; Expression tag;.) "switch" ( SwitchVariantDecl | SwitchLateDecl | lparen ExprTyped rparen tagcolon ExprAnnotations (. eSwitch.operands.push_back(eCondition);.) CaseDecl {CaseDecl} ) . CaseDecl = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); Expression condition; .) "case" ( IF(flagSwitchKind == SWITCH_META) lparen MetaSimpExpr 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 = (. Expression condition; Expression guard(Operator::LOGIC_AND, {}); pushContextScope(scope); .) ExprTyped (. guard.addArg(Expression(condition)); .) {comma ExprTyped (. guard.addArg(Expression(condition)); .) } (. scope->setBody(guard); popContextScope(); .) . SwitchLateDecl = (. std::wstring aliasCondition; Expression exprCondition, aliasAnns; expr = Expression(Operator::SWITCH_LATE, {}); ManagedScpPtr scope = root->add(new CodeScope(context.scope)); .) "late" lparen Expr [implic Ident] [tagcolon ExprAnnotations] rparen tagcolon ExprAnnotations 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(move(aliasCondition)).get(); } expr.addBindings({Atom(string(alias))}); scope->addBinding(Atom(move(alias)), move(aliasAnns)); .) . SwitchVariantDecl = (. Expression varTested; std::wstring varAlias; bool flagAliasFound = false; expr = Expression(Operator::SWITCH_VARIANT, {}); .) "variant" lparen Expr [implic Ident (. flagAliasFound = true; .) ] [tagcolon ExprAnnotations] rparen tagcolon ExprAnnotations (. expr.addArg(std::move(varTested)); if (flagAliasFound) { expr.addBindings({Atom(varAlias)}); } else { if(varTested.__state == Expression::IDENT){ expr.addBindings({Atom(string(varTested.getValueString()))}); } } .) CaseVariantDecl {CaseVariantDecl} . CaseVariantDecl = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); std::wstring key; scope->addBinding(Atom(string(expr.bindings.front())), Expression()); .) "case" lparen Ident rparen (. expr.addArg(root->recognizeVariantConstructor(Atom(std::move(key)))); .) BDecl<&*scope> (. expr.addBlock(scope); .) . IntrinsicDecl= (. std::wstring name; .) "intrinsic" ( Ident< name> (. outer = Expression(Operator::CALL_INTRINSIC, {}); outer.setValue(Atom(name)); root->recognizeIntrinsic(outer); .) lparen [CalleeParams] rparen | "query" (. outer = Expression(Operator::QUERY, {}); .) ( "late" IntrinsicQueryLateDecl | lparen [CalleeParams] rparen ) ). IntrinsicQueryLateDecl = (. std::wstring predicateAlias; Expression predicateE, predicateAnns; expr = Expression(Operator::QUERY_LATE, {}); ManagedScpPtr scope = root->add(new CodeScope(context.scope)); .) lparen Expr implic Ident tagcolon ExprAnnotations rparen tagcolon ExprAnnotations BDecl<&*scope> (. expr.addArg(move(predicateE)); expr.addBindings({Atom(wstring(predicateAlias))}); scope->addBinding(Atom(move(predicateAlias)), move(predicateAnns)); expr.addBlock(scope); .) . SequenceDecl = (. 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(t->val).get()); .) rparen period. InterfaceData<> = "interface" lparen ( "dfa" rparen InterfaceDFA // | "extern-c" rparen InterfaceExternC | "cfa" rparen InterfaceCFA ). // InterfaceExternC<> = (. ExternData data; .) // lcurbrack {ExternHeadersDecl | ExternAliasDecl } rcurbrack // (. root->addExternData(move(data)); .) // . // // ExternPkgDecl = // "pkgconfig" lparen // string (. package = t->val.) // rparen // . // // ExternAliasDecl = (. std::wstring alias, package; .) // Ident assign "library" lparen ExternPkgDecl rparen period // (. data.addLibAlias(Atom(alias), Atom(package)); .) // . // // ExternHeadersDecl = (. std::list listInc; std::wstring& package; .) // "include" // [lparen // ( // Ident (. data.requireLibAlias(Atom(alias)); .) // | ExternPkgDecl (. data.requireLibPackage(Atom(package)); .) // ) // rparen] // lcurbrack { string (. listInc.push_back(Atom(t->val).get()); .) // [comma] } rcurbrack [period] (. data.requireHeaders(listInc); .) // . InterfaceDFA<> = lcurbrack { InstructDecl } rcurbrack . InstructDecl = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; tags.push_back(Expression()); /* return value */ .) "operator" InstructAlias tagcolon lparen (.scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { comma MetaSimpExpr (. tags.push_back(tag); .) } ] rparen [ implic MetaSimpExpr (. tags[0] = tag; .) ] (. root->addDFAData(move(scheme)); .) period. InstructAlias = ( "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& tags = scheme.operands; .) "operator" InstructAlias tagcolon (. scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { comma MetaSimpExpr (. tags.push_back(tag); .) } ] period (. root->addInterfaceData(CFA, move(scheme)); .). /*============================ METAPROGRAMMING ===============================*/ // TagsDecl = (. Expression tag; TagModifier mod = TagModifier::NONE; .) // ':' { MetaSimpExpr (. /*f.addTag(std::move(tag), mod); */ .) // }. FnTag = (. Expression tag; TagModifier mod = TagModifier::NONE; .) MetaSimpExpr ['-' TagMod] (. f->addTag(std::move(tag), mod); .). TagMod = ( "assert" (. mod = TagModifier::ASSERT; .) | "require" (. mod = TagModifier::REQUIRE; .) ). // RuleDecl<> = // "rule" tagcolon (. RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg; .) // lparen Ident tagcolon Domain (. args.add(arg, typ); .) // {comma Ident tagcolon Domain (. args.add(arg, typ); .) // } rparen // ["case" RGuard {comma RGuard}] // lcurbrack RBody rcurbrack . /* - TODO use RGuard for guards-*/ // RuleContextDecl = (.Expression eHead, eGuards, eBody; .) // "rule" "context" tagcolon MetaSimpExpr // "case" lparen MetaSimpExpr rparen // lcurbrack MetaSimpExpr rcurbrack (.scope->contextRules.push_back(Expression(Operator::CONTEXT_RULE, {eHead, eGuards, eBody})); .). // Domain = // ( // "function" (. dom = DomainAnnotation::FUNCTION; .) // | "variable" (. dom = DomainAnnotation::VARIABLE; .) // ). // RGuard= (. Expression e; .) // MetaExpr (. guards.add(std::move(e)); .). // MetaExpr= (.Operator op; Expression e2; .) // MetaExpr2 // [MetaOp MetaExpr2 (. e = Expression(op, {e, e2}); .) // ]. // MetaExpr2= // ( // lparen MetaExpr rparen // | MetaSimpExpr // ). MetaSimpExpr= (. std::wstring i1, infix; Expression e2; .) ( '-' MetaSimpExpr (. e = Expression(Operator::NEG, {e2}); .) | IF(checkParametersList()) Ident (. e = Expression(Operator::CALL, {Expression(Atom(i1))}); if (!root->recognizeVariantConstructor(e)) SemErr({L"Undefined predicate: ", i1}); .) lparen [ MetaCalleeParams ] rparen | IF(checkInfix()) Ident Ident MetaSimpExpr (. e = Expression(Operator::CALL, {Expression(Atom(infix))}); e.addArg(Expression(Atom(i1))); e.addArg(std::move(e2)); .) | IdentR | number (. e = Expression(Atom(t->val)); .) ). MetaCalleeParams = (. Expression e2; .) MetaSimpExpr (. e.addArg(Expression(e2)); .) {comma MetaSimpExpr (. e.addArg(Expression(e2)); .) }. // RBody = // (. Expression e; std::wstring msg; .) // "warning" MetaExpr ["message" string (. msg = t->val; .) // ] (. root->add(new RuleWarning(RuleArguments(args), RuleGuards(guards), std::move(e), Atom(msg))); .) // . // MetaOp< Operator& op> = // implic (. op = Operator::IMPL; .) // . /*============================ Expressions ===============================*/ ExprAnnotations = (. TypeAnnotation typ; std::list tags; Expression tag; e.tags.clear();.) Type (. e.bindType(move(typ)); .) {';' MetaSimpExpr (. tags.push_back(tag); .) } (. e.addTags(tags); .) . ExprTyped = Expr [tagcolon ExprAnnotations]. Expr< Expression& e> (. Expression e2; .) = ExprLogicAnd - [ ('or' | 'OR') Expr (. e = Expression(Operator::OR, {e, e2}); .) + [ ("or" | "OR") Expr (. e = Expression(Operator::OR, {e, e2}); .) ] . ExprLogicAnd< Expression& e> (. Expression e2; .) = ExprRel - [ ('and' | 'AND') ExprLogicAnd (. e = Expression(Operator::AND, {e, e2}); .) + [ ("and" | "AND") ExprLogicAnd (. e = Expression(Operator::AND, {e, e2}); .) ] . ExprRel< Expression& e> (. Operator op; Expression e2; .) = ExprArithmAdd [ RelOp ExprRel (. e = Expression(op, {e, e2}); .) ] . ExprArithmAdd< Expression& e>= (. Operator op; Expression e2; .) ExprArithmMul< e> [ AddOpExprArithmAdd< e2> (. e = Expression(op, {e, e2});.) ]. ExprArithmMul< Expression& e> (. Operator op; Expression e2; .) = ExprUpdate [ MulOp< op> ExprArithmMul< e2> (. e = Expression(op, {e, e2}); .) ]. ExprUpdate= (. Expression e2; .) ExprPostfix< e> [ colon ( IF(checkListIndex()) ListIndexLiteral | ListLiteral) (. e = Expression(Operator::UPDATE, {e, e2}); .) ]. ExprPostfix = Term [ (. e = Expression(Operator::INDEX, {e}); .) {lbrack CalleeParams rbrack } ]. Term< Expression& e> (. std::wstring name; e = Expression(); .) = (IF (checkParametersList()) Ident< name> (. e = Expression(Operator::CALL, {Atom(name)}); root->recognizeVariantConstructor(e); .) lparen [CalleeParams] rparen | IdentVR | ListLiteral | ListRangeLiteral | LoopDecl | IfDecl | SwitchDecl | IntrinsicDecl | SequenceDecl | number (. e = Expression(Atom(t->val)); .) | string (. e = Expression(Atom(t->val)); .) | "true" (. e = Expression(Atom(1)); e.bindType(TypePrimitive::Bool); .) | "false" (. e = Expression(Atom(0)); e.bindType(TypePrimitive::Bool); .) | "undef" (. e = Expression(Operator::UNDEF, {}); .) | '-' Term (. e = Expression(Operator::NEG, {e}); .) | lparen ExprTyped rparen ). ListLiteral = (. std::wstring key; Expression val; std::list> keys; e = Expression(Operator::LIST, {}); .) lcurbrack { ( IF(checkTokenAfterIdent(_assign)) Ident assign | (. key = L""; .) ) Expr (. keys.push_back(Atom(key)); e.operands.push_back(val); .) [comma] } rcurbrack (. e.addBindings(keys.begin(), keys.end()); .) . ListIndexLiteral = (. e = Expression(Operator::LIST_INDEX, {});Expression valE;.) lcurbrack { (. Expression idxE(Operator::LIST, {});.) lbrack CalleeParams rbrack assign Expr[comma] (. e.operands.push_back(idxE); e.operands.push_back(valE); .) } rcurbrack . ListRangeLiteral = (. Expression eFrom, eTo; .) lbrack Expr ".." Expr rbrack (. e = Expression(Operator::LIST_RANGE, {eFrom, eTo}); .) . CalleeParams = (. Expression e2; .) ExprTyped (. e.addArg(Expression(e2)); .) {comma ExprTyped (. 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.