/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ #ifndef __MINIZINC_AST_HH__ #define __MINIZINC_AST_HH__ #include #include #include #include #include #include #include #include #include #include #include namespace MiniZinc { class IntLit; class FloatLit; class SetLit; class BoolLit; class StringLit; class Id; class AnonVar; class ArrayLit; class ArrayAccess; class Comprehension; class ITE; class BinOp; class UnOp; class Call; class VarDecl; class Let; class TypeInst; class Item; class FunctionI; class ExpressionSet; class ExpressionSetIter; /// %Location of an expression used during parsing class ParserLocation { protected: /// Source code file name ASTString _filename; /// Line where expression starts unsigned int _first_line; /// Line where expression ends unsigned int _last_line; /// Column where expression starts unsigned int _first_column; /// Column where expression ends unsigned int _last_column; public: /// Construct empty location ParserLocation(void) : _first_line(1), _last_line(1), _first_column(0), _last_column(0) {} /// Construct location ParserLocation(const ASTString& filename, unsigned int first_line, unsigned int first_column, unsigned int last_line, unsigned int last_column) : _filename(filename), _first_line(first_line), _last_line(last_line), _first_column(first_column), _last_column(last_column) {} ASTString filename(void) const { return _filename; } void filename(const ASTString& f) { _filename = f; } unsigned int first_line(void) const { return _first_line; } void first_line(unsigned int l) { _first_line = l; } unsigned int last_line(void) const { return _last_line; } void last_line(unsigned int l) { _last_line = l; } unsigned int first_column(void) const { return _first_column; } void first_column(unsigned int c) { _first_column = c; } unsigned int last_column(void) const { return _last_column; } void last_column(unsigned int c) { _last_column = c; } std::string toString(void) const { std::ostringstream oss; oss << _filename << ":" << _first_line << "." << _first_column; if (_first_line != _last_line) { oss << "-" << _last_line << "." << _last_column; } else if (_first_column != _last_column) { oss << "-" << _last_column; } return oss.str(); } }; /// %Location of an expression in the source code class Location { protected: /// Internal representation of a Location /// Layout depends on sizeof pointer and arguments /// 32 bit pointers: /// Layout 1: filename (32 bit), first line (8 bit), last line-first line (7 bit), first column /// (6 bit), last column (7 bit) Layout 2: filename (32 bit), 4 IntLit for the lines/columns /// 64 bit pointers: /// Layout 1: filename (64 bit), first line (20 bit), last line-first line (20 bit), first /// column (10 bit), last column (10 bit) Layout 2: filename (64 bit), 4 IntLit for the /// lines/columns class LocVec : public ASTVec { protected: LocVec(const ASTString& filename, unsigned int first_line, unsigned int first_column, unsigned int last_line, unsigned int last_column); LocVec(const ASTString& filename, IntVal combined); public: static LocVec* a(const ASTString& filename, unsigned int first_line, unsigned int first_column, unsigned int last_line, unsigned int last_column); void mark(void) { _gc_mark = 1; if (_data[0]) static_cast(_data[0])->mark(); } ASTString filename(void) const; unsigned int first_line(void) const; unsigned int last_line(void) const; unsigned int first_column(void) const; unsigned int last_column(void) const; }; union LI { LocVec* lv; ptrdiff_t t; } _loc_info; LocVec* lv(void) const { LI li = _loc_info; li.t &= ~static_cast(1); return li.lv; } public: /// Construct empty location Location(void) { _loc_info.lv = NULL; } /// Construct location Location(const ASTString& filename, unsigned int first_line, unsigned int first_column, unsigned int last_line, unsigned int last_column) { if (last_line < first_line) throw InternalError("invalid location"); _loc_info.lv = LocVec::a(filename, first_line, first_column, last_line, last_column); } Location(const ParserLocation& loc) { _loc_info.lv = LocVec::a(loc.filename(), loc.first_line(), loc.first_column(), loc.last_line(), loc.last_column()); } /// Return string representation std::string toString(void) const; /// Return filename ASTString filename(void) const { return lv() ? lv()->filename() : ASTString(); } /// Return first line number unsigned int first_line(void) const { return lv() ? lv()->first_line() : 0; } /// Return last line number unsigned int last_line(void) const { return lv() ? lv()->last_line() : 0; } /// Return first column number unsigned int first_column(void) const { return lv() ? lv()->first_column() : 0; } /// Return last column number unsigned int last_column(void) const { return lv() ? lv()->last_column() : 0; } /// Return whether location is introduced by the compiler bool is_introduced(void) const { return _loc_info.lv == NULL || ((_loc_info.t & 1) != 0); } /// Mark as alive for garbage collection void mark(void) const; /// Return location with introduced flag set Location introduce(void) const; /// Location used for un-allocated expressions static Location nonalloc; ParserLocation parserLocation(void) const { return ParserLocation(filename(), first_line(), first_column(), last_line(), last_column()); } }; /// Output operator for locations template std::basic_ostream& operator<<(std::basic_ostream& os, const Location& loc) { std::basic_ostringstream s; s.copyfmt(os); s.width(0); if (loc.filename() == "") { s << "unknown file"; } else { s << loc.filename(); } s << ":" << loc.first_line() << "." << loc.first_column(); if (loc.first_line() != loc.last_line()) { s << "-" << loc.last_line() << "." << loc.last_column(); } else if (loc.first_column() != loc.last_column()) { s << "-" << loc.last_column(); } return os << s.str(); } /** * \brief Annotations */ class Annotation { private: ExpressionSet* _s; /// Delete Annotation(const Annotation&); /// Delete Annotation& operator=(const Annotation&); public: Annotation(void) : _s(NULL) {} ~Annotation(void); bool contains(Expression* e) const; bool containsCall(const ASTString& id) const; bool isEmpty(void) const; ExpressionSetIter begin(void) const; ExpressionSetIter end(void) const; void add(Expression* e); void add(std::vector e); void remove(Expression* e); void removeCall(const ASTString& id); void clear(void); void merge(const Annotation& ann); Call* getCall(const ASTString& id) const; static Annotation empty; }; /// returns the Annotation specified by the string; returns NULL if not exists Expression* getAnnotation(const Annotation& ann, std::string str); /// returns the Annotation specified by the string; returns NULL if not exists Expression* getAnnotation(const Annotation& ann, const ASTString& str); /** * \brief Base class for expressions */ class Expression : public ASTNode { protected: /// The %MiniZinc type of the expression Type _type; /// The annotations Annotation _ann; /// The location of the expression Location _loc; /// The hash value of the expression size_t _hash; public: /// Identifier of the concrete expression type enum ExpressionId { E_INTLIT = ASTNode::NID_END + 1, E_FLOATLIT, E_SETLIT, E_BOOLLIT, E_STRINGLIT, E_ID, E_ANON, E_ARRAYLIT, E_ARRAYACCESS, E_COMP, E_ITE, E_BINOP, E_UNOP, E_CALL, E_VARDECL, E_LET, E_TI, E_TIID, EID_END = E_TIID }; bool isUnboxedVal(void) const { if (sizeof(double) <= sizeof(FloatLit*)) { // bit 1 or bit 0 is set return (reinterpret_cast(this) & static_cast(3)) != 0; } else { // bit 0 is set return (reinterpret_cast(this) & static_cast(1)) != 0; } } bool isUnboxedInt(void) const { if (sizeof(double) <= sizeof(FloatLit*)) { // bit 1 is set, bit 0 is not set return (reinterpret_cast(this) & static_cast(3)) == 2; } else { // bit 0 is set return (reinterpret_cast(this) & static_cast(1)) == 1; } } bool isUnboxedFloatVal(void) const { // bit 0 is set (and doubles fit inside pointers) return (sizeof(double) <= sizeof(FloatLit*)) && (reinterpret_cast(this) & static_cast(1)) == 1; } ExpressionId eid(void) const { return isUnboxedInt() ? E_INTLIT : isUnboxedFloatVal() ? E_FLOATLIT : static_cast(_id); } const Location& loc(void) const { return isUnboxedVal() ? Location::nonalloc : _loc; } void loc(const Location& l) { if (!isUnboxedVal()) _loc = l; } const Type& type(void) const { return isUnboxedInt() ? Type::unboxedint : isUnboxedFloatVal() ? Type::unboxedfloat : _type; } void type(const Type& t); size_t hash(void) const { return isUnboxedInt() ? unboxedIntToIntVal().hash() : isUnboxedFloatVal() ? unboxedFloatToFloatVal().hash() : _hash; } protected: /// Combination function for hash values void cmb_hash(size_t h) { _hash ^= h + 0x9e3779b9 + (_hash << 6) + (_hash >> 2); } /// Combination function for hash values size_t cmb_hash(size_t seed, size_t h) { seed ^= h + 0x9e3779b9 + (seed << 6) + (seed >> 2); return seed; } /// Compute base hash value void init_hash(void) { _hash = cmb_hash(0, _id); } /// Check if \a e0 and \a e1 are equal static bool equal_internal(const Expression* e0, const Expression* e1); /// Constructor Expression(const Location& loc, const ExpressionId& eid, const Type& t) : ASTNode(eid), _type(t), _loc(loc) {} public: IntVal unboxedIntToIntVal(void) const { assert(isUnboxedInt()); if (sizeof(double) <= sizeof(FloatVal*)) { unsigned long long int i = reinterpret_cast(this) & ~static_cast(7); bool pos = ((reinterpret_cast(this) & static_cast(4)) == 0); if (pos) { return i >> 3; } else { return -(static_cast(i >> 3)); } } else { unsigned long long int i = reinterpret_cast(this) & ~static_cast(3); bool pos = ((reinterpret_cast(this) & static_cast(2)) == 0); if (pos) { return i >> 2; } else { return -(static_cast(i >> 2)); } } } static IntLit* intToUnboxedInt(long long int i) { static const unsigned int pointerBits = sizeof(IntLit*) * 8; if (sizeof(double) <= sizeof(FloatVal*)) { static const long long int maxUnboxedVal = (static_cast(1) << (pointerBits - 3)) - static_cast(1); if (i < -maxUnboxedVal || i > maxUnboxedVal) return NULL; long long int j = i < 0 ? -i : i; ptrdiff_t ubi_p = (static_cast(j) << 3) | static_cast(2); if (i < 0) ubi_p = ubi_p | static_cast(4); return reinterpret_cast(ubi_p); } else { static const long long int maxUnboxedVal = (static_cast(1) << (pointerBits - 2)) - static_cast(1); if (i < -maxUnboxedVal || i > maxUnboxedVal) return NULL; long long int j = i < 0 ? -i : i; ptrdiff_t ubi_p = (static_cast(j) << 2) | static_cast(1); if (i < 0) ubi_p = ubi_p | static_cast(2); return reinterpret_cast(ubi_p); } } FloatVal unboxedFloatToFloatVal(void) const { assert(isUnboxedFloatVal()); union { double d; uint64_t bits; const Expression* p; } _u; _u.p = this; _u.bits = _u.bits >> 1; uint64_t exponent = (_u.bits & (static_cast(0x3FF) << 52)) >> 52; if (exponent != 0) { exponent += 512; // reconstruct original bias of 1023 } uint64_t sign = (_u.bits & (static_cast(1) << 62) ? 1 : 0); _u.bits = (sign << 63) | (exponent << 52) | (_u.bits & static_cast(0xFFFFFFFFFFFFF)); return _u.d; } static FloatLit* doubleToUnboxedFloatVal(double d) { if (sizeof(double) > sizeof(FloatLit*)) return NULL; union { double d; uint64_t bits; FloatLit* p; } _u; _u.d = d; uint64_t exponent = (_u.bits & (static_cast(0x7FF) << 52)) >> 52; if (exponent != 0) { if (exponent < 513 || exponent > 1534) return NULL; // exponent doesn't fit in 10 bits exponent -= 512; // make exponent fit in 10 bits, with bias 511 } bool sign = (_u.bits & (static_cast(1) << 63)) != 0; _u.bits = _u.bits & ~(static_cast(0x7FF) << 52); // mask out top 11 bits (previously exponent) _u.bits = (_u.bits << 1) | 1u; // shift by one bit and add tag for double _u.bits = _u.bits | (static_cast(sign) << 63) | (static_cast(exponent) << 53); return _u.p; } bool isTagged(void) const { // only bit 2 is set if (isUnboxedVal()) return false; if (sizeof(double) <= sizeof(FloatVal*)) return (reinterpret_cast(this) & static_cast(7)) == 4; else return (reinterpret_cast(this) & static_cast(3)) == 2; } Expression* tag(void) const { assert(!isUnboxedVal()); if (sizeof(double) <= sizeof(FloatVal*)) return reinterpret_cast(reinterpret_cast(this) | static_cast(4)); else return reinterpret_cast(reinterpret_cast(this) | static_cast(2)); } Expression* untag(void) { if (isUnboxedVal()) return this; if (sizeof(double) <= sizeof(FloatVal*)) return reinterpret_cast(reinterpret_cast(this) & ~static_cast(4)); else return reinterpret_cast(reinterpret_cast(this) & ~static_cast(2)); } /// Test if expression is of type \a T template bool isa(void) const { #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wtautological-undefined-compare" #endif if (nullptr == this) throw InternalError("isa: nullptr"); #ifdef __clang__ #pragma clang diagnostic pop #endif return isUnboxedInt() ? T::eid == E_INTLIT : isUnboxedFloatVal() ? T::eid == E_FLOATLIT : _id == T::eid; } /// Cast expression to type \a T* template T* cast(void) { assert(isa()); return static_cast(this); } /// Cast expression to type \a const T* template const T* cast(void) const { assert(isa()); return static_cast(this); } /// Cast expression to type \a T* or NULL if types do not match template T* dyn_cast(void) { return isa() ? static_cast(this) : NULL; } /// Cast expression to type \a const T* or NULL if types do not match template const T* dyn_cast(void) const { return isa() ? static_cast(this) : NULL; } /// Cast expression to type \a T* template static T* cast(Expression* e) { return e == NULL ? NULL : e->cast(); } /// Cast expression to type \a const T* template static const T* cast(const Expression* e) { return e == NULL ? NULL : e->cast(); } /// Cast expression to type \a T* or NULL if types do not match template static T* dyn_cast(Expression* e) { return e == NULL ? NULL : e->dyn_cast(); } /// Cast expression to type \a const T* or NULL if types do not match template static const T* dyn_cast(const Expression* e) { return e == NULL ? NULL : e->dyn_cast(); } /// Add annotation \a ann to the expression void addAnnotation(Expression* ann); /// Add annotation \a ann to the expression void addAnnotations(std::vector ann); const Annotation& ann(void) const { return isUnboxedVal() ? Annotation::empty : _ann; } Annotation& ann(void) { return isUnboxedVal() ? Annotation::empty : _ann; } /// Return hash value of \a e static size_t hash(const Expression* e) { return e == NULL ? 0 : e->hash(); } /// Check if \a e0 and \a e1 are equal static bool equal(const Expression* e0, const Expression* e1); /// Mark \a e as alive for garbage collection static void mark(Expression* e); }; /// \brief Integer literal expression class IntLit : public Expression { protected: /// The value of this expression IntVal _v; /// Constructor IntLit(const Location& loc, IntVal v); public: /// The identifier of this expression type static const ExpressionId eid = E_INTLIT; /// Access value IntVal v(void) const { return isUnboxedInt() ? unboxedIntToIntVal() : _v; } /// Recompute hash value void rehash(void); /// Allocate literal static IntLit* a(IntVal v); /// Allocate literal for enumerated type (only used internally for generators) static IntLit* aEnum(IntVal v, unsigned int enumId); }; /// \brief Float literal expression class FloatLit : public Expression { protected: /// The value of this expression FloatVal _v; /// Constructor FloatLit(const Location& loc, FloatVal v); public: /// The identifier of this expression type static const ExpressionId eid = E_FLOATLIT; /// Access value FloatVal v(void) const { return isUnboxedFloatVal() ? unboxedFloatToFloatVal() : _v; } /// Recompute hash value void rehash(void); /// Allocate literal static FloatLit* a(FloatVal v); }; /// \brief Set literal expression class SetLit : public Expression { protected: /// The value of this expression ASTExprVec _v; union { /// A range-list based representation for an integer set, or NULL IntSetVal* isv; /// A range-list based representation for an float set, or NULL FloatSetVal* fsv; } _u; public: /// The identifier of this expression type static const ExpressionId eid = E_SETLIT; /// Construct set \$f\{v1,\dots,vn\}\$f SetLit(const Location& loc, const std::vector& v); /// Construct set \$f\{v1,\dots,vn\}\$f SetLit(const Location& loc, ASTExprVec v); /// Construct set SetLit(const Location& loc, IntSetVal* isv); /// Construct set SetLit(const Location& loc, FloatSetVal* fsv); /// Access value ASTExprVec v(void) const { return _v; } /// Set value void v(const ASTExprVec& val) { _v = val; } /// Access integer set value if present IntSetVal* isv(void) const { return type().bt() == Type::BT_INT ? _u.isv : NULL; } /// Set integer set value void isv(IntSetVal* val) { _u.isv = val; } /// Access float set value if present FloatSetVal* fsv(void) const { return type().bt() == Type::BT_FLOAT ? _u.fsv : NULL; } /// Set integer set value void fsv(FloatSetVal* val) { _u.fsv = val; } /// Recompute hash value void rehash(void); }; /// \brief Boolean literal expression class BoolLit : public Expression { protected: /// The value of this expression bool _v; public: /// The identifier of this expression type static const ExpressionId eid = E_BOOLLIT; /// Constructor BoolLit(const Location& loc, bool v); /// Access value bool v(void) const { return _v; } /// Recompute hash value void rehash(void); }; /// \brief String literal expression class StringLit : public Expression { protected: /// The value of this expression ASTString _v; public: /// The identifier of this expression type static const ExpressionId eid = E_STRINGLIT; /// Constructor StringLit(const Location& loc, const std::string& v); /// Constructor StringLit(const Location& loc, const ASTString& v); /// Access value ASTString v(void) const { return _v; } /// Set value void v(const ASTString& val) { _v = val; } /// Recompute hash value void rehash(void); }; /// \brief Identifier expression class Id : public Expression { protected: /// The string identifier void* _v_or_idn; /// The declaration corresponding to this identifier (may be NULL) Expression* _decl; public: /// The identifier of this expression type static const ExpressionId eid = E_ID; /// Constructor (\a decl may be NULL) Id(const Location& loc, const std::string& v, VarDecl* decl); /// Constructor (\a decl may be NULL) Id(const Location& loc, const ASTString& v, VarDecl* decl); /// Constructor (\a decl may be NULL) Id(const Location& loc, long long int idn, VarDecl* decl); /// Access identifier ASTString v(void) const; /// Set identifier void v(const ASTString& val) { _v_or_idn = val.aststr(); } /// Access identifier number long long int idn(void) const; /// Set identifier number void idn(long long int n) { _v_or_idn = reinterpret_cast((static_cast(n) << 1) | static_cast(1)); rehash(); } /// Return identifier or X_INTRODUCED plus identifier number ASTString str(void) const; /// Access declaration VarDecl* decl(void) const { Expression* d = _decl; while (d && d->isa()) d = d->cast()->_decl; return Expression::cast(d); } /// Set declaration void decl(VarDecl* d); /// Redirect to another Id \a id void redirect(Id* id) { assert(_decl == NULL || _decl->isa()); _decl = id; } /// Recompute hash value void rehash(void); }; /// \brief Type-inst identifier expression class TIId : public Expression { protected: /// The string identifier ASTString _v; public: /// The identifier of this expression type static const ExpressionId eid = E_TIID; /// Constructor TIId(const Location& loc, const std::string& v); /// Access identifier ASTString v(void) const { return _v; } /// Set identifier void v(const ASTString& val) { _v = val; } /// Check whether it is an enum identifier (starting with two $ signs) bool isEnum(void) const { return _v.c_str()[0] == '$'; } /// Recompute hash value void rehash(void); }; /// \brief Anonymous variable expression class AnonVar : public Expression { public: /// The identifier of this expression type static const ExpressionId eid = E_ANON; /// Constructor AnonVar(const Location& loc); /// Recompute hash value void rehash(void); }; /// \brief Array literal expression class ArrayLit : public Expression { friend class Expression; protected: /// The array union { /// An expression vector (if _flag_2==false) ASTExprVecO* _v; /// Another array literal (if _flag_2==true) ArrayLit* _al; } _u; /// The declared array dimensions // If _flag_2 is true, then this is an array view. In that case, // the _dims array holds the sliced dimensions ASTIntVec _dims; /// Set compressed vector (initial repetitions are removed) void compress(const std::vector& v, const std::vector& dims); public: /// Index conversion from slice to original int origIdx(int i) const; /// Get element \a i of a sliced array Expression* slice_get(int i) const; /// Set element \a i of a sliced array void slice_set(int i, Expression* e); public: /// The identifier of this expression type static const ExpressionId eid = E_ARRAYLIT; /// Constructor ArrayLit(const Location& loc, const std::vector& v, const std::vector >& dims); /// Constructor (existing content) ArrayLit(const Location& loc, ArrayLit& v, const std::vector >& dims); /// Constructor (one-dimensional, existing content) ArrayLit(const Location& loc, ArrayLit& v); /// Constructor (one-dimensional) ArrayLit(const Location& loc, const std::vector& v); /// Constructor (two-dimensional) ArrayLit(const Location& loc, const std::vector >& v); /// Constructor for slices ArrayLit(const Location& loc, ArrayLit* v, const std::vector >& dims, const std::vector >& slice); /// Constructor (one-dimensional) ArrayLit(const Location& loc, const std::vector& v); /// Recompute hash value void rehash(void); // The following methods are only used for copying /// Access value ASTExprVec getVec(void) const { assert(!_flag_2); return _u._v; } /// Set value void setVec(const ASTExprVec& val) { assert(!_flag_2); _u._v = val.vec(); } /// Get underlying array (if this is an array slice) or NULL ArrayLit* getSliceLiteral(void) const { return _flag_2 ? _u._al : NULL; } /// Get underlying _dims vector ASTIntVec dimsInternal(void) const { return _dims; } /// Return number of dimensions int dims(void) const; /// Return minimum index of dimension \a i int min(int i) const; /// Return maximum index of dimension \a i int max(int i) const; /// Return the length of the array int length(void) const; /// Turn into 1d array (only used at the end of flattening) void make1d(void); /// Check if this array was produced by flattening bool flat(void) const { return _flag_1; } /// Set whether this array was produced by flattening void flat(bool b) { _flag_1 = b; } /// Return size of underlying array unsigned int size(void) const { return (_flag_2 || _u._v->flag()) ? length() : _u._v->size(); } /// Access element \a i Expression* operator[](int i) const { return (_flag_2 || _u._v->flag()) ? slice_get(i) : (*_u._v)[i]; } /// Set element \a i void set(int i, Expression* e) { if (_flag_2 || _u._v->flag()) { slice_set(i, e); } else { (*_u._v)[i] = e; } } }; /// \brief Array access expression class ArrayAccess : public Expression { protected: /// The array to access Expression* _v; /// The indexes (for all array dimensions) ASTExprVec _idx; public: /// The identifier of this expression type static const ExpressionId eid = E_ARRAYACCESS; /// Constructor ArrayAccess(const Location& loc, Expression* v, const std::vector& idx); /// Constructor ArrayAccess(const Location& loc, Expression* v, ASTExprVec idx); /// Access value Expression* v(void) const { return _v; } /// Set value void v(Expression* val) { _v = val; } /// Access index sets ASTExprVec idx(void) const { return _idx; } /// Set index sets void idx(const ASTExprVec& idx) { _idx = idx; } /// Recompute hash value void rehash(void); }; /** * \brief Generators for comprehensions * * A generator consists of a list of variable declarations, one for * each generated variable, and the expression to generate. E.g., * the Zinc expression [ x[i,j,k] | i,j in 1..10, k in 1..5] contains * two generators. The first one has variable declarations for i and j * and the expression 1..10, and the second one has a variable declaration * for k and the expression 1..5. * */ class Generator { friend class Comprehension; protected: /// Variable declarations std::vector _v; /// in-expression Expression* _in; /// where-expression Expression* _where; public: /// Allocate Generator(const std::vector& v, Expression* in, Expression* where); /// Allocate Generator(const std::vector& v, Expression* in, Expression* where); /// Allocate Generator(const std::vector& v, Expression* in, Expression* where); /// Allocate Generator(const std::vector& v, Expression* in, Expression* where); /// Allocate single where clause (without generator) at position \a pos Generator(int pos, Expression* where); }; /// \brief A list of generators with one where-expression struct Generators { /// %Generators std::vector _g; /// Constructor Generators(void) {} }; /// \brief An expression representing an array- or set-comprehension class Comprehension : public Expression { friend class Expression; protected: /// The expression to generate Expression* _e; /// A list of generator expressions ASTExprVec _g; /// A list of indices where generators start ASTIntVec _g_idx; public: /// The identifier of this expression type static const ExpressionId eid = E_COMP; /// Constructor Comprehension(const Location& loc, Expression* e, Generators& g, bool set); /// Recompute hash value void rehash(void); /// Whether comprehension is a set bool set(void) const; /// Return number of generators int n_generators(void) const; /// Return "in" expression for generator \a i Expression* in(int i); /// Return "in" expression for generator \a i const Expression* in(int i) const; /// Return number of declarations for generator \a i int n_decls(int i) const; /// Return declaration \a i for generator \a gen VarDecl* decl(int gen, int i); /// Return declaration \a i for generator \a gen const VarDecl* decl(int gen, int i) const; /// Return where clause for generator \a i Expression* where(int i); /// Return where clause for generator \a i const Expression* where(int i) const; /// Return generator body Expression* e(void) const { return _e; } /// Set generator body void e(Expression* e0) { _e = e0; } /// Re-construct (used for copying) void init(Expression* e, Generators& g); }; /// \brief If-then-else expression class ITE : public Expression { friend class Expression; protected: /// List of if-then-pairs ASTExprVec _e_if_then; /// Else-expression Expression* _e_else; public: /// The identifier of this expression type static const ExpressionId eid = E_ITE; /// Constructor ITE(const Location& loc, const std::vector& e_if_then, Expression* e_else); int size(void) const { return _e_if_then.size() / 2; } Expression* e_if(int i) { return _e_if_then[2 * i]; } Expression* e_then(int i) { return _e_if_then[2 * i + 1]; } Expression* e_else(void) { return _e_else; } const Expression* e_if(int i) const { return _e_if_then[2 * i]; } const Expression* e_then(int i) const { return _e_if_then[2 * i + 1]; } const Expression* e_else(void) const { return _e_else; } void e_then(int i, Expression* e) { _e_if_then[2 * i + 1] = e; } void e_else(Expression* e) { _e_else = e; } /// Recompute hash value void rehash(void); /// Re-construct (used for copying) void init(const std::vector& e_if_then, Expression* e_else); }; /// Type of binary operators enum BinOpType { BOT_PLUS, BOT_MINUS, BOT_MULT, BOT_DIV, BOT_IDIV, BOT_MOD, BOT_POW, BOT_LE, BOT_LQ, BOT_GR, BOT_GQ, BOT_EQ, BOT_NQ, BOT_IN, BOT_SUBSET, BOT_SUPERSET, BOT_UNION, BOT_DIFF, BOT_SYMDIFF, BOT_INTERSECT, BOT_PLUSPLUS, BOT_EQUIV, BOT_IMPL, BOT_RIMPL, BOT_OR, BOT_AND, BOT_XOR, BOT_DOTDOT }; /// \brief Binary-operator expression class BinOp : public Expression { protected: /// Left hand side expression Expression* _e0; /// Right hand side expression Expression* _e1; /// The predicate or function declaration (or NULL) FunctionI* _decl; public: /// The identifier of this expression type static const ExpressionId eid = E_BINOP; /// Constructor BinOp(const Location& loc, Expression* e0, BinOpType op, Expression* e1); /// Access left hand side Expression* lhs(void) const { return _e0; } /// Set left hand side void lhs(Expression* e) { _e0 = e; } /// Access right hand side Expression* rhs(void) const { return _e1; } /// Set right hand side void rhs(Expression* e) { _e1 = e; } /// Access argument \a i Expression* arg(int i) { assert(i == 0 || i == 1); return i == 0 ? _e0 : _e1; } /// Return number of arguments unsigned int n_args(void) const { return 2; } /// Access declaration FunctionI* decl(void) const { return _decl; } /// Set declaration void decl(FunctionI* f) { _decl = f; } /// Return string representation of the operator ASTString opToString(void) const; /// Recompute hash value void rehash(void); /// Return operator type BinOpType op(void) const; }; /// Type of unary operators enum UnOpType { UOT_NOT, UOT_PLUS, UOT_MINUS }; /// \brief Unary-operator expressions class UnOp : public Expression { protected: /// %Expression Expression* _e0; /// The predicate or function declaration (or NULL) FunctionI* _decl; public: /// The identifier of this expression type static const ExpressionId eid = E_UNOP; /// Constructor UnOp(const Location& loc, UnOpType op, Expression* e); /// Access expression Expression* e(void) const { return _e0; } /// Set expression void e(Expression* e0) { _e0 = e0; } /// Access argument \a i Expression* arg(int i) { assert(i == 0); return _e0; } /// Return number of arguments unsigned int n_args(void) const { return 1; } /// Access declaration FunctionI* decl(void) const { return _decl; } /// Set declaration void decl(FunctionI* f) { _decl = f; } ASTString opToString(void) const; /// Recompute hash value void rehash(void); /// Return operator type UnOpType op(void) const; }; /// \brief A predicate or function call expression class Call : public Expression { friend class Expression; protected: union { /// Identifier of called predicate or function ASTStringO* _id; /// The predicate or function declaration (or NULL) FunctionI* _decl; } _u_id; union { /// Single-argument call (tagged pointer) Expression* _oneArg; /// Arguments to the call ASTExprVecO* _args; } _u; /// Check if _u_id contains an id or a decl bool hasId(void) const; public: /// The identifier of this expression type static const ExpressionId eid = E_CALL; /// Constructor Call(const Location& loc, const std::string& id, const std::vector& args); /// Constructor Call(const Location& loc, const ASTString& id, const std::vector& args); /// Access identifier ASTString id(void) const; /// Set identifier (overwrites decl) void id(const ASTString& i); /// Number of arguments unsigned int n_args(void) const { return _u._oneArg->isUnboxedVal() || _u._oneArg->isTagged() ? 1 : _u._args->size(); } /// Access argument \a i Expression* arg(int i) const { assert(i < n_args()); if (_u._oneArg->isUnboxedVal() || _u._oneArg->isTagged()) { assert(i == 0); return _u._oneArg->isUnboxedVal() ? _u._oneArg : _u._oneArg->untag(); } else { return (*_u._args)[i]; } } /// Set argument \a i void arg(int i, Expression* e) { assert(i < n_args()); if (_u._oneArg->isUnboxedVal() || _u._oneArg->isTagged()) { assert(i == 0); _u._oneArg = e->isUnboxedVal() ? e : e->tag(); } else { (*_u._args)[i] = e; } } /// Set arguments void args(const ASTExprVec& a) { if (a.size() == 1) { _u._oneArg = a[0]->isUnboxedVal() ? a[0] : a[0]->tag(); } else { _u._args = a.vec(); assert(!_u._oneArg->isTagged()); } } /// Access declaration FunctionI* decl(void) const; /// Set declaration (overwrites id) void decl(FunctionI* f); /// Recompute hash value void rehash(void); }; /// \brief A variable declaration expression class VarDecl : public Expression { protected: /// Type-inst of the declared variable TypeInst* _ti; /// Identifier Id* _id; /// Initialisation expression (can be NULL) Expression* _e; /// Flattened version of the VarDecl WeakRef _flat; /// Integer payload int _payload; public: /// The identifier of this expression type static const ExpressionId eid = E_VARDECL; /// Constructor VarDecl(const Location& loc, TypeInst* ti, const std::string& id, Expression* e = NULL); /// Constructor VarDecl(const Location& loc, TypeInst* ti, const ASTString& id, Expression* e = NULL); // Constructor VarDecl(const Location& loc, TypeInst* ti, long long int idn, Expression* e = NULL); /// Constructor VarDecl(const Location& loc, TypeInst* ti, Id* id, Expression* e = NULL); /// Access TypeInst TypeInst* ti(void) const { return _ti; } /// Set TypeInst void ti(TypeInst* t) { _ti = t; } /// Access identifier Id* id(void) const { return _id; } /// Access initialisation expression Expression* e(void) const; /// Set initialisation expression void e(Expression* rhs); /// Access flattened version VarDecl* flat(void) { return _flat() ? _flat()->cast() : NULL; } /// Set flattened version void flat(VarDecl* vd); /// Recompute hash value void rehash(void); /// Whether variable is toplevel bool toplevel(void) const; /// Whether variable is toplevel void toplevel(bool t); /// Whether variable is introduced bool introduced(void) const; /// Whether variable is introduced void introduced(bool t); /// Whether variable has been evaluated bool evaluated(void) const; /// Whether variable has been evaluated void evaluated(bool t); /// Access payload int payload(void) const { return _payload; } /// Set payload void payload(int i) { _payload = i; } /// Put current value on trail void trail(void); }; class EnvI; class CopyMap; /// \brief %Let expression class Let : public Expression { friend Expression* copy(EnvI& env, CopyMap& m, Expression* e, bool followIds, bool copyFundecls, bool isFlatModel); friend class Expression; protected: /// List of local declarations ASTExprVec _let; /// Copy of original local declarations ASTExprVec _let_orig; /// Body of the let Expression* _in; public: /// The identifier of this expression type static const ExpressionId eid = E_LET; /// Constructor Let(const Location& loc, const std::vector& let, Expression* in); /// Recompute hash value void rehash(void); /// Access local declarations ASTExprVec let(void) const { return _let; } /// Access local declarations ASTExprVec let_orig(void) const { return _let_orig; } /// Access body Expression* in(void) const { return _in; } /// Remember current let bindings void pushbindings(void); /// Restore previous let bindings void popbindings(void); }; /// \brief Type-inst expression class TypeInst : public Expression { protected: /// Ranges of an array expression ASTExprVec _ranges; /// Declared domain (or NULL) Expression* _domain; public: /// The identifier of this expression type static const ExpressionId eid = E_TI; /// Constructor TypeInst(const Location& loc, const Type& t, ASTExprVec ranges, Expression* domain = NULL); /// Constructor TypeInst(const Location& loc, const Type& t, Expression* domain = NULL); /// Access ranges ASTExprVec ranges(void) const { return _ranges; } /// Access domain Expression* domain(void) const { return _domain; } //// Set domain void domain(Expression* d) { _domain = d; } /// Set ranges to \a ranges void setRanges(const std::vector& ranges); bool isarray(void) const { return _ranges.size() > 0; } bool hasTiVariable(void) const; /// Recompute hash value void rehash(void); /// Check if domain is computed from right hand side of variable bool computedDomain(void) const { return _flag_1; } /// Set if domain is computed from right hand side of variable void setComputedDomain(bool b) { _flag_1 = b; } /// Check if this TypeInst represents an enum bool isEnum(void) const { return _flag_2; } /// Set if this TypeInst represents an enum void setIsEnum(bool b) { _flag_2 = b; } }; /** * \brief Base-class for items */ class Item : public ASTNode { protected: /// Location of the item Location _loc; public: /// Identifier of the concrete item type enum ItemId { II_INC = Expression::EID_END + 1, II_VD, II_ASN, II_CON, II_SOL, II_OUT, II_FUN, II_END = II_FUN }; ItemId iid(void) const { return static_cast(_id); } const Location& loc(void) const { return _loc; } protected: /// Constructor Item(const Location& loc, const ItemId& iid) : ASTNode(iid), _loc(loc) { _flag_1 = false; } public: /// Test if item is of type \a T template bool isa(void) const { return _id == T::iid; } /// Cast item to type \a T* template T* cast(void) { assert(isa()); return static_cast(this); } /// Cast expression to type \a const T* template const T* cast(void) const { assert(isa()); return static_cast(this); } /// Cast item to type \a T* or NULL if types do not match template T* dyn_cast(void) { return isa() ? static_cast(this) : NULL; } /// Cast item to type \a const T* or NULL if types do not match template const T* dyn_cast(void) const { return isa() ? static_cast(this) : NULL; } /// Cast item to type \a T* template static T* cast(Item* i) { return i == NULL ? NULL : i->cast(); } /// Cast item to type \a const T* template static const T* cast(const Item* i) { return i == NULL ? NULL : i->cast(); } /// Cast item to type \a T* or NULL if types do not match template static T* dyn_cast(Item* i) { return i == NULL ? NULL : i->dyn_cast(); } /// Cast item to type \a const T* or NULL if types do not match template static const T* dyn_cast(const Item* i) { return i == NULL ? NULL : i->dyn_cast(); } /// Check if item should be removed bool removed(void) const { return _flag_1; } /// Set flag to remove item void remove(void) { _flag_1 = true; } /// Unset remove item flag (only possible if not already removed by compact()) void unremove(void) { _flag_1 = false; } }; class Model; /// \brief Include item class IncludeI : public Item { protected: /// Filename to include ASTString _f; /// Model for that file Model* _m; public: /// The identifier of this item type static const ItemId iid = II_INC; /// Constructor IncludeI(const Location& loc, const ASTString& f); /// Access filename ASTString f(void) const { return _f; } /// Set filename void f(const ASTString& nf) { _f = nf; } /// Access model Model* m(void) const { return _m; } /// Set the model void m(Model* m0, bool own = true) { assert(_m == NULL || m0 == NULL); _m = m0; _flag_2 = own; } bool own(void) const { return _flag_2; } }; /// \brief Variable declaration item class VarDeclI : public Item { protected: /// The declaration expression VarDecl* _e; public: /// The identifier of this item type static const ItemId iid = II_VD; /// Constructor VarDeclI(const Location& loc, VarDecl* e); /// Access expression VarDecl* e(void) const { return _e; } /// Set expression void e(VarDecl* vd) { _e = vd; } /// Flag used during compilation bool flag(void) const { return _flag_2; } /// Set flag used during compilation void flag(bool b) { _flag_2 = b; } }; /// \brief Assign item class AssignI : public Item { protected: /// Identifier of variable to assign to ASTString _id; /// Expression to assign to the variable Expression* _e; /// Declaration of the variable to assign to VarDecl* _decl; public: /// The identifier of this item type static const ItemId iid = II_ASN; /// Constructor AssignI(const Location& loc, const std::string& id, Expression* e); /// Access identifier ASTString id(void) const { return _id; } /// Access expression Expression* e(void) const { return _e; } /// Set expression void e(Expression* e0) { _e = e0; } /// Access declaration VarDecl* decl(void) const { return _decl; } /// Set declaration void decl(VarDecl* d) { _decl = d; } }; /// \brief Constraint item class ConstraintI : public Item { protected: /// Constraint expression Expression* _e; public: /// The identifier of this item type static const ItemId iid = II_CON; /// Constructor ConstraintI(const Location& loc, Expression* e); /// Access expression Expression* e(void) const { return _e; } /// Set expression void e(Expression* e0) { _e = e0; } /// Flag used during compilation bool flag(void) const { return _flag_2; } /// Set flag used during compilation void flag(bool b) { _flag_2 = b; } }; /// \brief Solve item class SolveI : public Item { protected: /// Solve item annotation Annotation _ann; /// Expression for minimisation/maximisation (or NULL) Expression* _e; /// Constructor SolveI(const Location& loc, Expression* e); public: /// The identifier of this item type static const ItemId iid = II_SOL; /// Type of solving enum SolveType { ST_SAT, ST_MIN, ST_MAX }; /// Allocate solve satisfy item static SolveI* sat(const Location& loc); /// Allocate solve minimize item static SolveI* min(const Location& loc, Expression* e); /// Allocate solve maximize item static SolveI* max(const Location& loc, Expression* e); /// Access solve annotation const Annotation& ann(void) const { return _ann; } /// Access solve annotation Annotation& ann(void) { return _ann; } /// Access expression for optimisation Expression* e(void) const { return _e; } /// Set expression for optimisation void e(Expression* e0) { _e = e0; } /// Return type of solving SolveType st(void) const; /// Set type of solving void st(SolveType s); }; /// \brief Output item class OutputI : public Item { protected: /// Expression to output Expression* _e; public: /// The identifier of this item type static const ItemId iid = II_OUT; /// Constructor OutputI(const Location& loc, Expression* e); /// Access expression Expression* e(void) const { return _e; } /// Update expression void e(Expression* e) { _e = e; } }; class EnvI; /// \brief Function declaration item class FunctionI : public Item { protected: /// Identifier of this function ASTString _id; /// Type-inst of the return value TypeInst* _ti; /// List of parameter declarations ASTExprVec _params; /// Annotation Annotation _ann; /// Function body (or NULL) Expression* _e; /// Whether function is defined in the standard library bool _from_stdlib; public: /// The identifier of this item type static const ItemId iid = II_FUN; /// Type of builtin expression-valued functions typedef Expression* (*builtin_e)(EnvI&, Call*); /// Type of builtin int-valued functions typedef IntVal (*builtin_i)(EnvI&, Call*); /// Type of builtin bool-valued functions typedef bool (*builtin_b)(EnvI&, Call*); /// Type of builtin float-valued functions typedef FloatVal (*builtin_f)(EnvI&, Call*); /// Type of builtin set-valued functions typedef IntSetVal* (*builtin_s)(EnvI&, Call*); /// Type of builtin string-valued functions typedef std::string (*builtin_str)(EnvI&, Call*); /// Builtin functions (or NULL) struct { builtin_e e; builtin_i i; builtin_f f; builtin_b b; builtin_s s; builtin_str str; } _builtins; /// Constructor FunctionI(const Location& loc, const std::string& id, TypeInst* ti, const std::vector& params, Expression* e = NULL); /// Constructor FunctionI(const Location& loc, const ASTString& id, TypeInst* ti, const ASTExprVec& params, Expression* e = NULL); /// Access identifier ASTString id(void) const { return _id; } /// Access TypeInst TypeInst* ti(void) const { return _ti; } /// Access parameters ASTExprVec params(void) const { return _params; } /// Access annotation const Annotation& ann(void) const { return _ann; } /// Access annotation Annotation& ann(void) { return _ann; } /// Access body Expression* e(void) const { return _e; } /// Set body void e(Expression* b) { _e = b; } /** \brief Compute return type given argument types \a ta */ Type rtype(EnvI& env, const std::vector& ta, bool strictEnums); /** \brief Compute return type given argument types \a ta */ Type rtype(EnvI& env, const std::vector& ta, bool strictEnums); /** \brief Compute expected type of argument \a n given argument types \a ta */ Type argtype(EnvI& env, const std::vector& ta, int n); /// Return whether function is defined in the standard library bool from_stdlib(void) const { return _from_stdlib; }; /// Mark for GC void mark(void) { _gc_mark = 1; loc().mark(); } }; /** * \brief Visitor for expressions * * This class implements no-ops for all expression types. * Override the methods to implement custom behaviour. */ class EVisitor { public: /// Visit integer literal void vIntLit(const IntLit&) {} /// Visit floating point literal void vFloatLit(const FloatLit&) {} /// Visit Boolean literal void vBoolLit(const BoolLit&) {} /// Visit set literal void vSetLit(const SetLit&) {} /// Visit string literal void vStringLit(const StringLit&) {} /// Visit identifier void vId(const Id&) {} /// Visit anonymous variable void vAnonVar(const AnonVar&) {} /// Visit array literal void vArrayLit(const ArrayLit&) {} /// Visit array access void vArrayAccess(const ArrayAccess&) {} /// Visit array comprehension void vComprehension(const Comprehension&) {} /// Visit array comprehension (only generator \a gen_i) void vComprehensionGenerator(const Comprehension&, int gen_i) { (void)gen_i; } /// Visit if-then-else void vITE(const ITE&) {} /// Visit binary operator void vBinOp(const BinOp&) {} /// Visit unary operator void vUnOp(const UnOp&) {} /// Visit call void vCall(const Call&) {} /// Visit let void vLet(const Let&) {} /// Visit variable declaration void vVarDecl(const VarDecl&) {} /// Visit type inst void vTypeInst(const TypeInst&) {} /// Visit TIId void vTIId(const TIId&) {} /// Determine whether to enter node bool enter(Expression* e) { return true; } /// Exit node after processing has finished void exit(Expression* e) {} }; /// Statically allocated constants class Constants { private: /// Garbage collection root set for constants Model* m; public: /// Literal true BoolLit* lit_true; /// Variable bound to true VarDecl* var_true; /// Literal false BoolLit* lit_false; /// Variable bound to false VarDecl* var_false; /// Special variable to signal compiler to ignore result VarDecl* var_ignore; /// Infinite set SetLit* infinity; /// Function item used to keep track of redefined variables FunctionI* var_redef; /// Literal absent value Expression* absent; /// Identifiers for builtins struct { ASTString forall; ASTString forall_reif; ASTString exists; ASTString clause; ASTString bool2int; ASTString int2float; ASTString bool2float; ASTString assert; ASTString trace; ASTString sum; ASTString lin_exp; ASTString element; ASTString show; ASTString fix; ASTString output; struct { ASTString lin_eq; ASTString lin_le; ASTString lin_ne; ASTString plus; ASTString minus; ASTString times; ASTString div; ASTString mod; ASTString lt; ASTString le; ASTString gt; ASTString ge; ASTString eq; ASTString ne; } int_; struct { ASTString lin_eq; ASTString lin_le; ASTString lin_ne; ASTString plus; ASTString minus; ASTString times; ASTString div; ASTString mod; ASTString lt; ASTString le; ASTString gt; ASTString ge; ASTString eq; ASTString ne; } int_reif; struct { ASTString lin_eq; ASTString lin_le; ASTString lin_lt; ASTString lin_ne; ASTString plus; ASTString minus; ASTString times; ASTString div; ASTString mod; ASTString lt; ASTString le; ASTString gt; ASTString ge; ASTString eq; ASTString ne; ASTString in; ASTString dom; } float_; struct { ASTString lin_eq; ASTString lin_le; ASTString lin_lt; ASTString lin_ne; ASTString plus; ASTString minus; ASTString times; ASTString div; ASTString mod; ASTString lt; ASTString le; ASTString gt; ASTString ge; ASTString eq; ASTString ne; ASTString in; } float_reif; ASTString bool_eq; ASTString bool_eq_reif; ASTString array_bool_or; ASTString array_bool_and; ASTString bool_clause; ASTString bool_clause_reif; ASTString bool_xor; ASTString set_eq; ASTString set_in; ASTString set_card; ASTString pow; ASTString introduced_var; ASTString anonEnumFromStrings; } ids; /// Identifiers for Boolean contexts struct { Id* root; Id* pos; Id* neg; Id* mix; } ctx; /// Common annotations struct { Id* output_var; ASTString output_array; Id* add_to_output; Id* output_only; Id* mzn_check_var; ASTString mzn_check_enum_var; Id* is_defined_var; ASTString defines_var; Id* is_reverse_map; Id* promise_total; Id* maybe_partial; Id* _export; ASTString doc_comment; ASTString mzn_path; ASTString is_introduced; Id* user_cut; // MIP Id* lazy_constraint; // MIP Id* mzn_break_here; Id* rhs_from_assignment; Id* domain_change_constraint; ASTString global_register; } ann; /// Command line options struct { /// basic MiniZinc command line options ASTString cmdlineData_str; ASTString cmdlineData_short_str; ASTString datafile_str; ASTString datafile_short_str; ASTString globalsDir_str; ASTString globalsDir_alt_str; ASTString globalsDir_short_str; ASTString help_str; ASTString help_short_str; ASTString ignoreStdlib_str; ASTString include_str; ASTString inputFromStdin_str; ASTString instanceCheckOnly_str; ASTString no_optimize_str; ASTString no_optimize_alt_str; ASTString no_outputOzn_str; ASTString no_outputOzn_short_str; ASTString no_typecheck_str; ASTString newfzn_str; ASTString outputBase_str; ASTString outputFznToStdout_str; ASTString outputFznToStdout_alt_str; ASTString outputOznToFile_str; ASTString outputOznToStdout_str; ASTString outputFznToFile_str; ASTString outputFznToFile_alt_str; ASTString outputFznToFile_short_str; ASTString rangeDomainsOnly_str; ASTString statistics_str; ASTString statistics_short_str; ASTString stdlib_str; ASTString verbose_str; ASTString verbose_short_str; ASTString version_str; ASTString werror_str; struct { ASTString all_sols_str; ASTString fzn_solver_str; } solver; } cli; /// options strings to find setting in Options map struct { ASTString cmdlineData; ASTString datafile; ASTString datafiles; ASTString fznToStdout; ASTString fznToFile; ASTString globalsDir; ASTString ignoreStdlib; ASTString includeDir; ASTString includePaths; ASTString instanceCheckOnly; ASTString inputFromStdin; ASTString model; ASTString newfzn; ASTString noOznOutput; ASTString optimize; ASTString outputBase; ASTString oznToFile; ASTString oznToStdout; ASTString rangeDomainsOnly; ASTString statistics; ASTString stdlib; ASTString typecheck; ASTString verbose; ASTString werror; struct { ASTString allSols; ASTString numSols; ASTString threads; ASTString fzn_solver; ASTString fzn_flags; ASTString fzn_flag; ASTString fzn_time_limit_ms; ASTString fzn_sigint; } solver; } opts; /// categories of the command line interface options struct { ASTString general; ASTString io; ASTString solver; ASTString translation; } cli_cat; /// Keep track of allocated integer literals std::unordered_map integerMap; /// Keep track of allocated float literals std::unordered_map floatMap; /// Constructor Constants(void); /// Return shared BoolLit BoolLit* boollit(bool b) { return b ? lit_true : lit_false; } static const int max_array_size = std::numeric_limits::max() / 2; }; /// Return static instance Constants& constants(void); } // namespace MiniZinc #include #endif