diff --git a/config/default.json b/config/default.json index f551dc0..f3144c4 100644 --- a/config/default.json +++ b/config/default.json @@ -1,36 +1,37 @@ { "template": "problems", "templates": { "bugs":"Containers.DONE_ArrayUpdate1", "default": "*-Colevels.*:Interpretation.*", "documentation":"Modules.Doc_*:Modules_API.Doc_*:Interpretation.Doc_*:AST.Doc_*:Loop.Doc_*:LateReasoning.Doc_*:Latex.Doc_*:Polymorphs.Doc_*:Transcend.Doc_*:ASTCorrespondence.Doc_*:Virtualization.Doc_*:Exploitation.Doc_*:Communication.Doc_*:Introduction.*", "ast": "AST.*", "effects": "Effects.*", "basic": "Attachments.*", "dimensions": "Dimensions.CompileDeepAnn1", "compilation": "Compilation.*", "communication": "Communication.*", "cfa": "CFA.*", "containers": "Containers.DONE_*", "dfa": "DFA.*", "diagnostic": "Diagnostic.*", "dsl": "Interpretation.*:Association.*", "exploitation": "Exploitation.*", "ExpressionSerializer": "ExpressionSerializer.*", "externc": "InterfaceExternC.*", "loops": "Loop.*", "latereasoning": "LateReasoning.*", "latex": "Latex.*", "modules": "Modules.*", "polymorphs": "PDT.BuildDTTable1", "problems": "Problems.MinMax1", + "arithmetics": "Arithmetics.*", "intrinsic-query": "Types.SlaveTypes*:Association.TypedQuery*", "types": "Types.*", "universal": "Universal.*", "virtualization": "Virtualization.*", "vendorsAPI/clang": "ClangAPI.*", "vendorsAPI/xml2": "libxml2.*" } } diff --git a/cpp/src/ast.h b/cpp/src/ast.h index 391b46d..4334ca8 100644 --- a/cpp/src/ast.h +++ b/cpp/src/ast.h @@ -1,750 +1,750 @@ /* 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 * File: ast.h */ /** * \file ast.h * \brief A syntax tree representation and related code * * \sa xreate::AST */ #ifndef AST_H #define AST_H #include "attachments.h" #include "utils.h" #include #include #include #include #include #include #include #include #include namespace xreate { struct ScopedSymbol; struct Symbol; } namespace std { template<> struct hash { std::size_t operator()(xreate::ScopedSymbol const& s) const; }; template<> struct equal_to { bool operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const; }; template<> struct hash { size_t operator()(xreate::Symbol const& s) const; }; template<> struct equal_to { bool operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const; }; } namespace xreate { struct String_t { }; struct Identifier_t { }; struct Number_t { }; struct Type_t { }; template class Atom { }; //DEBT store line:col for all atoms/identifiers template<> class Atom { public: Atom(const std::wstring& value); Atom(std::string && name); const std::string& get() const; private: std::string __value; }; template<> class Atom { public: Atom(wchar_t* value); Atom(int value); double get()const; private: double __value; }; template<> class Atom { public: Atom(const std::wstring& value); Atom(std::string && name); const std::string& get() const; private: std::string __value; }; enum class TypePrimitive { Invalid, Bool, I8, I32, I64, Int, Float, String }; enum class TypeOperator { NONE, VOID, REF, ALIAS, VARIANT, ARRAY, RECORD, ACCESS, SLAVE, GUARD }; struct struct_tag { }; const struct_tag tag_struct = struct_tag(); /** * \brief A type representation to support type system * * The class represents type in a denormalized form, i.e. with no arguments and aliases substitution * \sa AST::expandType() */ class TypeAnnotation { public: TypeAnnotation(); TypeAnnotation(TypePrimitive typ); TypeAnnotation(TypeOperator op, std::initializer_list operands); TypeAnnotation(TypeOperator op, std::vector&& operands); void addBindings(std::vector>&& params); void addFields(std::vector>&& listFields); bool operator<(const TypeAnnotation& t) const; // TypeAnnotation (struct_tag, std::initializer_list); bool isValid() const; TypeOperator __operator = TypeOperator::NONE; std::vector __operands; TypePrimitive __value; std::string __valueCustom; std::vector fields; std::vector bindings; private: }; enum class Operator { - INVALID, UNDEF, AND, OR, ADD, SUB, MUL, DIV, + INVALID, UNDEF, AND, OR, ADD, SUB, MUL, DIV, MOD, EQU, NE, NEG, LSS, LSE, GTR, GTE, LIST, LIST_INDEX, LIST_RANGE, CALL, CALL_INTRINSIC, QUERY, QUERY_LATE, IMPL/* implication */, MAP, FOLD, FOLD_INF, INDEX, IF, SWITCH, SWITCH_VARIANT, SWITCH_LATE, CASE, CASE_DEFAULT, LOGIC_AND, CONTEXT_RULE, VARIANT, SEQUENCE, UPDATE }; class Function; class AST; class CodeScope; class MetaRuleAbstract; typedef ManagedPtr ManagedFnPtr; typedef ManagedPtr ManagedScpPtr; typedef ManagedPtr ManagedRulePtr; const ManagedScpPtr NO_SCOPE = ManagedScpPtr(UINT_MAX, 0); /** * \brief AST node to represent a single instruction or an annotation * \attention In case of any changes update \ref xreate::ExpressionHints auxiliary helper as well * * %Expression is a generic building block of syntax tree which is able to hold node data * along with child nodes as operands. * * \note For types the %expression-like data structure \ref TypeAnnotation is used rather than Expression itself. * \sa xreate::AST, xreate::TypeAnnotation */ struct Expression { friend class CodeScope; friend class TranscendLayer; friend class CFAPass; friend class ExpressionHints; Expression(const Operator &oprt, std::initializer_list params); Expression(const Atom& ident); Expression(const Atom& number); Expression(const Atom& a); Expression(); void setOp(Operator oprt); void addArg(Expression&& arg); void addBindings(std::initializer_list> params); void bindType(TypeAnnotation t); template void addBindings(InputIt paramsBegin, InputIt paramsEnd); void addTags(const std::list tags) const; void addBlock(ManagedScpPtr scope); const std::vector& getOperands() const; double getValueDouble() const; void setValueDouble(double value); const std::string& getValueString() const; void setValue(const Atom&& v); bool isValid() const; bool isDefined() const; bool operator==(const Expression& other) const; /** * \brief is it string, number, compound operation and so on */ enum { INVALID, COMPOUND, IDENT, NUMBER, STRING, BINDING } __state = INVALID; /** * \brief Valid for compound State. Holds type of compound operator */ Operator op; /** * \brief Unique id to identify expression within syntax tree */ unsigned int id; /** * \brief Exact meaning depends on particular instruction * \details As an example, named lists/structs hold field names in bindings */ std::vector bindings; /** * \brief Holds child instructions as arguments */ std::vector operands; /** * \brief Holds type of instruction's result */ TypeAnnotation type; /** * \brief Holds additional annotations */ mutable std::map tags; /** * \brief Child code blocks * \details For example, If statement holds TRUE-branch as first and FALSE-branch as second block here */ std::list blocks; private: std::string __valueS; double __valueD; static unsigned int nextVacantId; }; bool operator<(const Expression&, const Expression&); template void Expression::addBindings(InputIt paramsBegin, InputIt paramsEnd) { size_t index = bindings.size(); std::transform(paramsBegin, paramsEnd, std::inserter(bindings, bindings.end()), [&index, this] (const Atom atom) { std::string key = atom.get(); return key; }); } typedef std::list ExpressionList; enum class TagModifier { NONE, ASSERT, REQUIRE }; enum class DomainAnnotation { FUNCTION, VARIABLE }; class RuleArguments : public std::vector> { public: void add(const Atom& name, DomainAnnotation typ); }; class RuleGuards : public std::vector { public: void add(Expression&& e); }; class TranscendLayer; class LLVMLayer; class MetaRuleAbstract { public: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards); virtual ~MetaRuleAbstract(); virtual void compile(TranscendLayer& layer) = 0; protected: RuleArguments __args; RuleGuards __guards; }; class RuleWarning : public MetaRuleAbstract { friend class TranscendLayer; public: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message); virtual void compile(TranscendLayer& layer); ~RuleWarning(); private: std::string __message; Expression __condition; }; typedef unsigned int VNameId; namespace versions { typedef int VariableVersion; const VariableVersion VERSION_NONE = -2; const VariableVersion VERSION_INIT = 0; } template<> struct AttachmentsDict { typedef versions::VariableVersion Data; static const unsigned int key = 6; }; struct ScopedSymbol { VNameId id; versions::VariableVersion version; static const ScopedSymbol RetSymbol; }; struct Symbol { ScopedSymbol identifier; const CodeScope * scope; }; struct ASTSite { unsigned int id; Expression getDefinition() const; //static Ast registerSite(const Expression& e); }; struct IdentifierSymbol{}; struct ExprAlias_A{}; struct ExprId_A{}; template<> struct AttachmentsDict { typedef Symbol Data; static const unsigned int key = 7; }; template<> struct AttachmentsDict { typedef Symbol Data; static const unsigned int key = 9; }; template<> struct AttachmentsDict{ typedef Expression Data; static const unsigned int key = 12; }; typedef std::pair Tag; bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2); bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2); bool operator<(const Symbol& s1, const Symbol& s2); bool operator==(const Symbol& s1, const Symbol& s2); bool operator< (const ASTSite& s1, const ASTSite& s2); /** * \brief AST node to represent a single code block/a scope of visibility * * Holds a single expression as a `body` along with set of variable assignments(declarations) used in body's expression. * \sa xreate::AST */ class CodeScope { friend class Function; friend class PassManager; public: CodeScope(CodeScope* parent = 0); ~CodeScope(); /** \brief Set expression as a body */ void setBody(const Expression& body); /** \brief Returns current code scope body */ const Expression& getBody() const; /** \brief Adds variable definition to be used in body as well as in other declarations */ Symbol addDefinition(Expression&& var, Expression&& body); /** \brief Returns symbols' definition */ static const Expression& getDefinition(const Symbol& symbol, bool flagAllowUndefined = false); const Expression& getDefinition(const ScopedSymbol& symbol, bool flagAllowUndefined = false) const; /** \brief Adds variable defined elsewhere */ void addBinding(Expression&& var, Expression&& argument, const VNameId hintBindingId = 0); std::vector __bindings; std::map __identifiers; CodeScope* __parent; //TODO move __definitions to SymbolsAttachments data //NOTE: definition of return type has index 0 std::unordered_map __declarations; std::vector tags; std::vector contextRules; private: ScopedSymbol registerIdentifier(const Expression& identifier, const VNameId hintBindingId = 0); public: bool recognizeIdentifier(const Expression& identifier) const; ScopedSymbol getSymbol(const std::string& alias); }; /** * \brief AST node to represent a single function * * Holds an `__entry` entry code scope along with `guard` to denote the different specializations. * \sa xreate::AST */ class Function { friend class Expression; friend class CodeScope; friend class AST; public: Function(const Atom& name); /** * \brief Adds function arguments */ void addBinding(Atom && name, Expression&& argument, const VNameId hintBindingId=0); /** * \brief Adds additional function annotations */ void addTag(Expression&& tag, const TagModifier mod); const std::string& getName() const; const std::map& getTags() const; CodeScope* getEntryScope() const; CodeScope* __entry; std::string __name; Expression guard; private: std::map __tags; }; class ExternData; typedef Expanded ExpandedType; struct TypeInferred{}; template<> struct AttachmentsDict { typedef ExpandedType Data; static const unsigned int key = 11; }; enum ASTInterface { CFA, DFA, Extern, Adhoc }; struct FunctionSpecialization { std::string guard; size_t id; }; struct FunctionSpecializationQuery { std::unordered_set context; }; template<> struct AttachmentsId{ static unsigned int getId(const Expression& expression){ return expression.id; } }; template<> struct AttachmentsId{ static unsigned int getId(const Symbol& s){ return s.scope->__declarations.at(s.identifier).id; } }; template<> struct AttachmentsId{ static unsigned int getId(const ManagedFnPtr& f){ const Symbol symbolFunction{ScopedSymbol::RetSymbol, f->getEntryScope()}; return AttachmentsId::getId(symbolFunction); } }; template<> struct AttachmentsId{ static unsigned int getId(const CodeScope* scope){ const Symbol symbolScope{ScopedSymbol::RetSymbol, scope}; return AttachmentsId::getId(symbolScope); } }; template<> struct AttachmentsId{ static unsigned int getId(const unsigned int id){ return id; } }; class TypeResolver; enum class IntrinsicFn { ARR_INIT, REC_FIELDS }; namespace details { namespace inconsistent { /** * \brief AST in an inconsistent form during construction * * Represents AST under construction(**inconsistent state**). * \attention Clients should use rather xreate::AST unless client's code explicitly works with Syntax Tree during construction. * * Typically an instance is created by xreate::XreateManager only and filled out by the parser * \sa xreate::XreateManager::prepare(std::string&&) */ class AST { friend class xreate::TypeResolver; public: AST(); /** * \brief Adds new function to AST * \param f Function to register */ void add(Function* f); /** * \brief Adds new declarative rule to AST * \param r Declarative Rule */ void add(MetaRuleAbstract* r); /** \brief Registers new code block */ ManagedScpPtr add(CodeScope* scope); /** * \brief Add new type to AST * @param t Type definition * @param alias Typer name */ void add(TypeAnnotation t, Atom alias); /** \brief Current module's name */ std::string getModuleName(); /** * \brief Looks for function with given name * \param name Function name to find * \note Requires that only one function exists under given name * \return Found function */ ManagedPtr findFunction(const std::string& name); /** \brief Returns all function in AST */ std::list getAllFunctions() const; /** * \brief Returns all specializations of a function with a given name * \param fnName function to find * \return list of found function specializations */ std::list getFnSpecializations(const std::string& fnName) const; /** * \return First element in Functions/Scopes/Rules list depending on template parameter * \tparam Target either Function or CodeScope or MetaRuleAbstract */ template ManagedPtr begin(); /** * \brief Performs all necessary steps after AST is built * * Performs all finalization steps and moves AST into consistent state represented by xreate::AST * \sa xreate::AST * \return AST in consistent state */ xreate::AST* finalize(); typedef std::multimap FUNCTIONS_REGISTRY; //std::list __externdata; std::list __dfadata; //TODO move to more appropriate place std::list __rawImports; //TODO move to more appropriate place std::multimap __interfacesData; //TODO CFA data here. private: std::vector __rules; std::vector __functions; std::vector __scopes; FUNCTIONS_REGISTRY __dictFunctions; protected: std::map __registryTypes; public: /** * \brief Stores DFA scheme for later use by DFA Pass * * Treats expression as a DFA scheme and feeds to the DFA Pass later * \param data DFA Scheme * \sa xreate::DFAPass */ void addDFAData(Expression&& data); /** \brief Stores data for later use by xreate::ExternLayer */ void addExternData(ExternData&& entry); /** * \brief Generalized function to store particular data for later use by particular pass * \param interface Particular Interface * \param data Particular data */ void addInterfaceData(const ASTInterface& interface, Expression&& data); /**\name Symbols Recognition */ ///@{ public: //TODO revisit enums/variants, move to codescope /** * \brief Tries to find out whether expression is Variant constructor */ bool recognizeVariantConstructor(Expression& function); Atom recognizeVariantConstructor(Atom ident); /** * \brief Postpones unrecognized identifier for future second round of recognition * \param scope Code block identifier is encountered * \param id Identifier */ void postponeIdentifier(CodeScope* scope, const Expression& id); /** \brief Second round of identifiers recognition done right after AST is fully constructed */ void recognizePostponedIdentifiers(); void recognizeIntrinsic(Expression& fn) const; private: std::map> __registryVariants; static std::map __registryIntrinsics; std::set> __bucketUnrecognizedIdentifiers; static void initIntrinsics(); public: ///@} }; template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); } } // namespace details::incomplete /** * \brief AST in a consistent state * * AST has two mutually exclusive possible states: * - an inconsistent state while AST is under construction. Represented by xreate::details::inconsistent::AST * - a consistent state when AST is built and finalize() is invoked. * * This class represents a consistent state and should be used by clients unless client's code explicitly works with AST under construction. * Consistent AST enables access to additional functions(such as type management). * \sa xreate::details::inconsistent::AST */ class AST : public details::inconsistent::AST { public: AST() : details::inconsistent::AST() {} /** * \brief Computes fully expanded form of type by substituting all arguments and aliases * \param t Type to expand * \return Expdanded or normal form of type * \sa TypeAnnotation */ ExpandedType expandType(const TypeAnnotation &t) const; /** * Searches type by given name * \param name Typename to search * \return Expanded or normal form of desired type * \note if type name is not found returns new undefined type with this name */ ExpandedType findType(const std::string& name); /** * Invokes Type Inference Analysis to find out expanded(normal) form expressions's type * \sa typeinference.h * \param e * \param expectedT expected type * \return Type of expression */ ExpandedType getType(const Expression& e, const TypeAnnotation& expectedT = TypeAnnotation()); }; } #endif // AST_H diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp index 18bca00..35c2355 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,846 +1,850 @@ /* 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::SUB: case Operator::MUL: case Operator::MOD: case Operator::DIV: case Operator::EQU: case Operator::LSS: case Operator::GTR: case Operator::NE: case Operator::LSE: case Operator::GTE: assert(expr.__state == Expression::COMPOUND); assert(expr.operands.size() == 2); leftRaw = process(expr.operands.at(0)); rightRaw = process(expr.operands.at(1)); break; default:; } switch (expr.op) { case Operator::AND: { assert(expr.operands.size()); llvm::Value* resultRaw = process(expr.operands[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::MOD:{ + return l.irBuilder.CreateSRem(leftRaw, rightRaw, hintAlias); + } + case Operator::EQU: { if (leftRaw->getType()->isIntegerTy()) return l.irBuilder.CreateICmpEQ(leftRaw, rightRaw, DEFAULT("tmp_equ")); if (leftRaw->getType()->isFloatingPointTy()) return l.irBuilder.CreateFCmpOEQ(leftRaw, rightRaw, DEFAULT("tmp_equ")); 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, hintAlias); } else { 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 index 2e7edcf..a4e58ef 100644 --- a/cpp/tests/arithmetics.cpp +++ b/cpp/tests/arithmetics.cpp @@ -1,93 +1,107 @@ /* 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 "supplemental/basics.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); +} + +TEST(Arithmetics, OperatorMod1){ + string code = R"Code( + test = function(x:: int, y::int):: int; entry() + { + x % y + } + )Code"; + + XreateManager* xreate = XreateManager::prepare(move(code)); + Fn2Args program = (Fn2Args) xreate->run(); + + ASSERT_EQ(1, program(4, 3)); } \ No newline at end of file diff --git a/cpp/tests/problems.cpp b/cpp/tests/problems.cpp index df96bbd..1ea7797 100644 --- a/cpp/tests/problems.cpp +++ b/cpp/tests/problems.cpp @@ -1,112 +1,134 @@ // // Created by pgess on 26/03/2020. // #include "xreatemanager.h" #include "pass/compilepass.h" #include "llvmlayer.h" #include "supplemental/basics.h" #include "gtest/gtest.h" using namespace xreate; TEST(Problems, MinMax1){ struct Pair {intmax_t x; intmax_t y;}; typedef Pair (*FnPair)(); FILE* code = fopen("scripts/containers/minmax.xreate", "r"); assert(code != nullptr); auto man = details::tier1::XreateManager::prepare(code); LLVMLayer* llvm = man->llvm; man->analyse(); std::unique_ptr compiler(new compilation::CompilePassCustomDecorators<>(man)); compiler->prepare(); llvm::Function* fnMinMax1Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax1"))->compile(); llvm::Function* fnMinMax2Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax2"))->compile(); llvm::Function* fnMinMax3Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax3"))->compile(); llvm::Function* fnMinMax4Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax4"))->compile(); llvm::Function* fnMinMax5Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax5"))->compile(); llvm::Function* fnMinMax6Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax6"))->compile(); llvm::Function* fnMinMax7Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax7"))->compile(); llvm::Function* fnMinMax8Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax8"))->compile(); llvm::Function* fnMinMax9Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax9"))->compile(); llvm::Function* fnMinMax10Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax10"))->compile(); llvm::Function* fnMinMax11Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax11"))->compile(); + llvm::Function* fnMinMax12Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax12"))->compile(); + llvm::Function* fnMinMax13Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax13"))->compile(); + llvm::Function* fnMinMax14Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax14"))->compile(); llvm->print(); llvm->initJit(); { FnPair fnMinxMax1 = (FnPair) llvm->getFunctionPointer(fnMinMax1Raw); Pair resultMinMax1 = fnMinxMax1(); ASSERT_EQ(3, resultMinMax1.x); ASSERT_EQ(37, resultMinMax1.y); } { FnNoArgs fnMinMax2 = (FnNoArgs) llvm->getFunctionPointer(fnMinMax2Raw); intmax_t resultMinMax2 = fnMinMax2(); ASSERT_EQ(10, resultMinMax2); } { FnNoArgs fnMinMax3 = (FnNoArgs) llvm->getFunctionPointer(fnMinMax3Raw); intmax_t resultMinMax3 = fnMinMax3(); ASSERT_EQ(146, resultMinMax3); } { FnNoArgs fnMinMax4 = (FnNoArgs) llvm->getFunctionPointer(fnMinMax4Raw); intmax_t resultMinMax4 = fnMinMax4(); ASSERT_EQ(6, resultMinMax4); } { FnPair fnMinMax5 = (FnPair) llvm->getFunctionPointer(fnMinMax5Raw); Pair resultMinMax5 = fnMinMax5(); ASSERT_EQ(4, resultMinMax5.x); ASSERT_EQ(11, resultMinMax5.y); } { FnPair fnMinMax6 = (FnPair) llvm->getFunctionPointer(fnMinMax6Raw); Pair resultMinMax6 = fnMinMax6(); ASSERT_EQ(2, resultMinMax6.x); ASSERT_EQ(8, resultMinMax6.y); } { FnPair fnMinMax7 = (FnPair) llvm->getFunctionPointer(fnMinMax7Raw); Pair resultMinMax7 = fnMinMax7(); ASSERT_EQ(1, resultMinMax7.x); ASSERT_EQ(3, resultMinMax7.y); } { FnPair fnMinMax8 = (FnPair) llvm->getFunctionPointer(fnMinMax8Raw); Pair resultMinMax8 = fnMinMax8(); ASSERT_EQ(2, resultMinMax8.x); ASSERT_EQ(3, resultMinMax8.y); } { FnPair fnMinMax9 = (FnPair) llvm->getFunctionPointer(fnMinMax9Raw); Pair resultMinMax9 = fnMinMax9(); ASSERT_EQ(1, resultMinMax9.x); ASSERT_EQ(8, resultMinMax9.y); } { FnNoArgs fnMinMax10 = (FnNoArgs ) llvm->getFunctionPointer(fnMinMax10Raw); intmax_t resultMinMax10 = fnMinMax10(); ASSERT_EQ(1, resultMinMax10); } { FnNoArgs fnMinMax11 = (FnNoArgs ) llvm->getFunctionPointer(fnMinMax11Raw); intmax_t resultMinMax11 = fnMinMax11(); ASSERT_EQ(8, resultMinMax11); } + + { + FnNoArgs fnMinMax12 = (FnNoArgs ) llvm->getFunctionPointer(fnMinMax12Raw); + intmax_t resultMinMax12 = fnMinMax12(); + ASSERT_EQ(2, resultMinMax12); + } + + { + FnNoArgs fnMinMax13 = (FnNoArgs ) llvm->getFunctionPointer(fnMinMax13Raw); + intmax_t resultMinMax13 = fnMinMax13(); + ASSERT_EQ(3, resultMinMax13); + } + + { + FnPair fnMinMax14 = (FnPair) llvm->getFunctionPointer(fnMinMax14Raw); + Pair resultMinMax14 = fnMinMax14(); + ASSERT_EQ(2, resultMinMax14.x); + ASSERT_EQ(3, resultMinMax14.y); + } } \ No newline at end of file diff --git a/grammar/xreate.ATG b/grammar/xreate.ATG index 594bccf..8670b4e 100644 --- a/grammar/xreate.ATG +++ b/grammar/xreate.ATG @@ -1,835 +1,836 @@ //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(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}); .) ] . ExprLogicAnd< Expression& e> (. Expression e2; .) = ExprRel [ ("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; .) + | '%' (. op = Operator::MOD; .) ). RelOp< Operator& op> = (. op = Operator::EQU; .) ( equal | (ne1 | ne2) (. op = Operator::NE; .) | lse (. op = Operator::LSE; .) | lss (. op = Operator::LSS; .) | gte (. op = Operator::GTE; .) | gtr (. op = Operator::GTR; .) ). SkipModulesSection = "module" {ANY} (lcurbrack {ANY} rcurbrack | '.'). END Xreate. diff --git a/scripts/containers/minmax.xreate b/scripts/containers/minmax.xreate index 9b9b8c6..8532993 100644 --- a/scripts/containers/minmax.xreate +++ b/scripts/containers/minmax.xreate @@ -1,241 +1,282 @@ El = type {idx:: int, val:: int}. PairT = type(X) {X, X}. Pair = type PairT(int). PairEl = type PairT(El). min = function(x:: int, y:: int):: int { if (x < y):: int { x } else { y } } max = function(x:: int, y:: int):: int { if (x > y):: int { x } else { y } } minEl = function(e1:: El, e2:: El):: El { if (e1["val"] < e2["val"]):: El {e1} else {e2} } maxEl = function(e1:: El, e2:: El):: El { if (e1["val"] > e2["val"]):: El {e1} else {e2} } minElIdx = function(x:: El, y:: El):: El { if (x["idx"] < y["idx"]):: El {x} else {y} } maxElIdx = function(x:: El, y:: El):: El { if (x["idx"] > y["idx"]):: El {x} else {y} } minLstEl = function(x:: El, y:: El):: El { if (x["val"] <= y["val"]):: El {x} else {y} } maxLstEl = function(x:: El, y:: El):: El { if (x["val"] >= y["val"]):: El {x} else {y} } fn-minmax1 = function:: {min:: int, max:: int} { arr = {25, 37, 12, 6, 5, 19, 3, 20}:: [int]. loop fold(arr->el:: int, {1000, 0}->state):: {min:: int, max:: int} { { min(el, state["min"]), max(el, state["max"]) }:: {min:: int, max:: int} } } fn-minmax2 = function:: int { arr = { {1, 72}, {3, 8}, {2, 5}, {3, 4}, {11, 1}, {6, 5}, {9, 2} } :: [{int, int}]. loop fold(arr->rect:: {int, int}, 1000->squareMin):: int { square = rect[0] * rect[1]:: int. min(square, squareMin) } } fn-minmax3 = function:: int { arr = { {1, 72}, {3, 8}, {2, 5}, {3, 4}, {11, 1}, {6, 5}, {9, 2} } :: [{int, int}]. loop fold(arr->rect:: {int, int}, 0->perMax):: int { per = 2 * (rect[0] + rect[1]):: int. max(per, perMax) } } fn-minmax4 = function:: int { arr = {25, 37, 12, 6, 5, 19, 3, 20}:: [int]. minInit = {0, 25}:: El. result = loop fold(arr->el:: int, {0, minInit}->state):: {idx:: int, minEl:: El} { elCur = {state["idx"], el}:: El. idxNext = state["idx"] + 1:: int. {idxNext, minEl(elCur, state["minEl"])}:: {idx:: int, minEl:: El} }. result["minEl", "idx"] } fn-minmax5 = function:: El { input = { {1, 72}, {3, 8}, {2, 5}, {3, 4}, {11, 1}, {6, 5}, {9, 2} } :: [{int, int}]. resultInit = {0, 0}:: El. result = loop fold(input->el:: Pair, {0, resultInit}->acc):: {idx:: int, max:: El} { density = el[0] / el[1] :: int. idxNext = acc["idx"] + 1:: int. elCur = {acc["idx"], density}:: El. {idxNext, maxEl(elCur, acc["max"])}:: {idx:: int, max:: El} }. result["max"] } fn-minmax6 = function:: Pair { arr = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]. init = {0, {{1000, 1000}, {0, 0}}}:: {int, PairEl}. result = loop fold(arr->val:: int, init->acc):: {int, PairEl} { el = {acc[0], val}:: El. idx = acc[0]+1 :: int. min = minEl(el, acc[1, 0]) :: El. max = maxLstEl(el, acc[1, 1]):: El. {idx, ({min, max}:: PairEl)}:: {int, PairEl} }. {result[1][0]["idx"], result[1][1]["idx"]} } fn-minmax7 = function:: Pair { arr = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]. init = {0, {{0, 0}, {1000, 1000}}}:: {int, PairEl}. result = loop fold(arr->val:: int, init->acc):: {int, PairEl} { el = {acc[0], val}:: El. idx = acc[0]+1 :: int. max = maxEl(el, acc[1, 0]) :: El. min = minLstEl(el, acc[1, 1]):: El. {idx, ({max, min}:: PairEl)}:: {int, PairEl} }. {result[1][0]["idx"], result[1][1]["idx"]} } fn-minmax8 = function:: Pair { input = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]. init = {0, {{1000, 1000}, {1000, 1000}}}:: {int, PairEl}. result = loop fold(input->val:: int, init->acc):: {int, PairEl} { el = {acc[0], val}:: El. idx = acc[0]+1 :: int. minF = minEl(el, acc[1, 0]) :: El. minL = minLstEl(el, acc[1, 1]):: El. {idx, {minF, minL}}:: {int, PairEl} }. {result[1, 0, "idx"], result[1, 1, "idx"]} } fn-minmax9 = function:: Pair { input = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]. init = {0, {{0, 0}, {0, 0}}}:: {int, PairEl}. result = loop fold(input->val:: int, init->acc):: {int, PairEl} { el = {acc[0], val}:: El. idx = acc[0]+1 :: int. maxF = maxEl(el, acc[1, 0]) :: El. maxL = maxLstEl(el, acc[1, 1]):: El. {idx, {maxF, maxL}}:: {int, PairEl} }. {result[1, 0, "idx"], result[1, 1, "idx"]} } fn-minmax10 = function:: int { input = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]. init = {0, {{1000, 1000}, {0, 0}}}:: {int, PairEl}. result = loop fold(input->val:: int, init->acc):: {int, PairEl} { el = {acc[0], val}:: El. idx = acc[0]+1 :: int. minF = minEl(el, acc[1, 0]) :: El. maxF = maxEl(el, acc[1, 1]):: El. {idx, {minF, maxF}}:: {int, PairEl} }. (minElIdx(result[1, 0], result[1, 1])::El)["idx"] } fn-minmax11 = function:: int { input = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]. ctxInit = {0, {{1000, 1000}, {0, 0}}}:: {int, PairEl}. result = loop fold(input-> val:: int, ctxInit->ctx):: {int, PairEl} { elCur = {ctx[0], val}:: El. elMinL = minLstEl(elCur, ctx[1, 0]):: El. elMaxL = maxLstEl(elCur, ctx[1, 1]):: El. {ctx[0]+1, {elMinL, elMaxL}}:: {int, PairEl} }. (maxElIdx(result[1, 0], result[1, 1])::El)["idx"] } fn-minmax12 = function:: int { input = {-8, 16, 3, -5, 2, -11, -905, -54}:: [int]. - loop fold(input->val:: int, 0->minPos):: int + result = loop fold(input->val:: int, {1000, false} -> state):: {minPstv:: int, flagPstvFound:: bool} { - if (val > 0 { min(val, minPos) } else { minPos } - } + if (val > 0):: int { {min(val, state["minPstv"]), true}:: {minPstv:: int, flagPstvFound:: bool} } else { state } + }. + + if (result["flagPstvFound"])::int {result["minPstv"]} else { 0 } +} + +OptionalVal = type {flag:: bool, val:: int}. + +fn-minmax13 = function::int +{ + input = {-8, 16, 3, -5, 2, -11, -905, -54}:: [int]. + + result = loop fold(input->x:: int, {false, -1000} -> state):: OptionalVal + { + if (x % 2 == 1):: OptionalVal {{true, max(x, state["val"])}:: OptionalVal } else { state } + }. + + result["val"] +} + +OptionalEl = type {el:: El, exists:: bool}. + +fn-minmax14 = function:: El +{ + input = { -8, 16, 3, -5, 2, -11, -905, -54 }:: [int]. + threshold = 2:: int. + + result = loop fold (input -> x:: int, {0, {el = { 0, 1000 }, exists = false }} -> result):: {int , OptionalEl} + { + xEl = {result[0], x}:: El. + + if(x > threshold):: {int , OptionalEl} + { + { result[0] + 1, + { el = minEl(xEl, result[1, "el"]), exists = true } + }:: {int , OptionalEl} } + else + { + result : {[0]= result[0] + 1} + } + }. + + if (result[1, "exists"]):: El { result[1, "el"] } else { {0, 0}:: El } }