From 0460e1f025801ee19ec28c497f4b52f8f143d8a4 Mon Sep 17 00:00:00 2001 From: Guido Tack Date: Fri, 11 Dec 2015 17:00:27 +1100 Subject: [PATCH 01/15] Add preliminary support for enumerated types --- include/minizinc/ast.hh | 4 +++ include/minizinc/ast.hpp | 2 ++ include/minizinc/typecheck.hh | 4 +++ lib/copy.cpp | 1 + lib/flatten.cpp | 18 ++++++++++ lib/parser.yxx | 30 ++++++++++++++++- lib/typecheck.cpp | 63 +++++++++++++++++++++++++++++++++-- 7 files changed, 119 insertions(+), 3 deletions(-) diff --git a/include/minizinc/ast.hh b/include/minizinc/ast.hh index 8127529c1..440318290 100644 --- a/include/minizinc/ast.hh +++ b/include/minizinc/ast.hh @@ -871,6 +871,10 @@ namespace MiniZinc { 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; } }; /** diff --git a/include/minizinc/ast.hpp b/include/minizinc/ast.hpp index 1442dc8fc..8b36a85b4 100644 --- a/include/minizinc/ast.hpp +++ b/include/minizinc/ast.hpp @@ -464,6 +464,7 @@ namespace MiniZinc { Expression* domain) : Expression(loc,E_TI,type), _ranges(ranges), _domain(domain) { _flag_1 = false; + _flag_2 = false; rehash(); } @@ -473,6 +474,7 @@ namespace MiniZinc { Expression* domain) : Expression(loc,E_TI,type), _domain(domain) { _flag_1 = false; + _flag_2 = false; rehash(); } diff --git a/include/minizinc/typecheck.hh b/include/minizinc/typecheck.hh index 1d39756d3..4446938a9 100644 --- a/include/minizinc/typecheck.hh +++ b/include/minizinc/typecheck.hh @@ -31,6 +31,10 @@ namespace MiniZinc { DeclMap idmap; /// Map from declarations to positions PosMap pos; + /// The model + Model* model; + + TopoSorter(Model* model0) : model(model0) {} /// Add a variable declaration void add(EnvI& env, VarDecl* vd, bool unique); diff --git a/lib/copy.cpp b/lib/copy.cpp index 810a85d2f..b246bb0e1 100644 --- a/lib/copy.cpp +++ b/lib/copy.cpp @@ -414,6 +414,7 @@ namespace MiniZinc { } TypeInst* c = new TypeInst(copy_location(m,e),t->type(), ASTExprVec(r),copy(env,m,t->domain(),followIds,copyFundecls,isFlatModel)); + c->setIsEnum(t->isEnum()); m.insert(e,c); ret = c; } diff --git a/lib/flatten.cpp b/lib/flatten.cpp index 777189274..459a26459 100644 --- a/lib/flatten.cpp +++ b/lib/flatten.cpp @@ -5028,6 +5028,24 @@ namespace MiniZinc { EnvI& env; Decls(EnvI& env0) : env(env0) {} void vCall(Call& c) { + if (c.id()=="format" || c.id()=="show") { + if (Id* ident = c.args()[c.args().size()-1]->dyn_cast()) { + if (Id* ti_id = Expression::dyn_cast(ident->decl()->ti()->domain())) { + if (ti_id->decl()->ti()->isEnum()) { + GCLock lock; + + + + std::vector args(1); + args[0] = c.args()[c.args().size()-1]; + std::string enumName = "_toString_"+ti_id->str().str(); + Call* convertEnum = new Call(Location().introduce(),enumName,args); + convertEnum->type(Type::parstring()); + c.args()[c.args().size()-1] = convertEnum; + } + } + } + } c.decl(env.orig->matchFn(env,&c)); } } _decls(env); diff --git a/lib/parser.yxx b/lib/parser.yxx index 8e6a177a6..fb831d9dd 100644 --- a/lib/parser.yxx +++ b/lib/parser.yxx @@ -640,7 +640,7 @@ namespace MiniZinc { %type set_expr string_expr string_quote_rest %type simple_array_literal simple_array_literal_2d simple_array_comp if_then_else_expr call_expr quoted_op_call let_expr operation_item_tail set_literal set_comp -%type expr_list expr_list_head elseif_list let_vardecl_item_list +%type expr_list expr_list_head elseif_list let_vardecl_item_list enum_id_list %type simple_array_literal_2d_list array_access_tail %type simple_array_literal_3d_list @@ -789,6 +789,34 @@ vardecl_item : $$ = new VarDeclI(@$,$1); delete $2; } + | MZN_ENUM MZN_IDENTIFIER + { + TypeInst* ti = new TypeInst(@$,Type::parsetint()); + ti->setIsEnum(true); + VarDecl* vd = new VarDecl(@$,ti,$2); + free($2); + $$ = new VarDeclI(@$,vd); + } + | MZN_ENUM MZN_IDENTIFIER MZN_EQ '{' enum_id_list '}' + { + TypeInst* ti = new TypeInst(@$,Type::parsetint()); + ti->setIsEnum(true); + SetLit* sl = new SetLit(@$, *$5); + VarDecl* vd = new VarDecl(@$,ti,$2,sl); + free($2); + delete $5; + $$ = new VarDeclI(@$,vd); + } + +enum_id_list : + // empty + { $$ = new std::vector(); } + | MZN_IDENTIFIER + { $$ = new std::vector(); + $$->push_back(new Id(@$,$1,NULL)); free($1); + } + | enum_id_list ',' MZN_IDENTIFIER + { $$ = $1; if ($$) $$->push_back(new Id(@$,$3,NULL)); free($3); } assign_item : MZN_IDENTIFIER MZN_EQ expr diff --git a/lib/typecheck.cpp b/lib/typecheck.cpp index b11db3f02..789d678b5 100644 --- a/lib/typecheck.cpp +++ b/lib/typecheck.cpp @@ -18,6 +18,8 @@ #include #include +#include + namespace MiniZinc { struct VarDeclCmp { @@ -51,8 +53,48 @@ namespace MiniZinc { } }; + void createEnumMapper(EnvI& env, Model* m, Id* ident, SetLit* sl) { + GCLock lock; + std::vector ranges(1); + ranges[0] = new TypeInst(Location().introduce(),Type::parint()); + TypeInst* ti = new TypeInst(Location().introduce(),Type::parstring(1)); + ti->setRanges(ranges); + std::string name = "_enum_to_string_"+ident->str().str(); + std::vector al_args(sl->v().size()); + for (unsigned int i=0; iv().size(); i++) { + al_args[i] = new StringLit(Location().introduce(),sl->v()[i]->cast()->str()); + } + ArrayLit* al = new ArrayLit(Location().introduce(),al_args); + VarDecl* vd = new VarDecl(Location().introduce(),ti,name,al); + m->addItem(new VarDeclI(Location().introduce(),vd)); + + TypeInst* ti_aa = new TypeInst(Location().introduce(),Type::parint()); + VarDecl* vd_aa = new VarDecl(Location().introduce(),ti_aa,"x"); + vd_aa->toplevel(false); + std::vector aa_args(1); + aa_args[0] = vd_aa->id(); + ArrayAccess* aa = new ArrayAccess(Location().introduce(),vd->id(),aa_args); + TypeInst* ti_fi = new TypeInst(Location().introduce(),Type::parstring()); + std::vector fi_params(1); + fi_params[0] = vd_aa; + FunctionI* fi = new FunctionI(Location().introduce(),"_toString_"+ident->str().str(),ti_fi,fi_params,aa); + m->addItem(fi); + } + void TopoSorter::add(EnvI& env, VarDecl* vd, bool unique) { + if (vd->ti()->isEnum() && vd->e()) { + SetLit* sl = vd->e()->cast(); + GCLock lock; + for (unsigned int i=0; iv().size(); i++) { + TypeInst* ti_id = new TypeInst(sl->v()[i]->loc(),Type::parint()); + VarDecl* vd_id = new VarDecl(ti_id->loc(),ti_id,sl->v()[i]->cast()->str(),IntLit::a(i+1)); + model->addItem(new VarDeclI(vd_id->loc(),vd_id)); + } + SetLit* nsl = new SetLit(vd->loc(), IntSetVal::a(1,sl->v().size())); + createEnumMapper(env, model, vd->id(), sl); + vd->e(nsl); + } DeclMap::iterator vdi = idmap.find(vd->id()); if (vdi == idmap.end()) { Decls nd; nd.push_back(vd); @@ -820,7 +862,7 @@ namespace MiniZinc { }; void typecheck(Env& env, Model* m, std::vector& typeErrors, bool ignoreUndefinedParameters) { - TopoSorter ts; + TopoSorter ts(m); std::vector functionItems; std::vector assignItems; @@ -854,8 +896,25 @@ namespace MiniZinc { VarDecl* vd = ts.get(env.envi(),ai->id(),ai->loc()); if (vd->e()) throw TypeError(env.envi(),ai->loc(),"multiple assignment to the same variable"); + + if (vd->ti()->isEnum()) { + if (SetLit* sl = ai->e()->dyn_cast()) { + GCLock lock; + for (unsigned int i=0; iv().size(); i++) { + TypeInst* ti_id = new TypeInst(sl->v()[i]->loc(),Type::parint()); + VarDecl* vd_id = new VarDecl(ti_id->loc(),ti_id,sl->v()[i]->cast()->str(),IntLit::a(i+1)); + m->addItem(new VarDeclI(vd_id->loc(),vd_id)); + ts.add(env.envi(),vd_id,true); + } + SetLit* nsl = new SetLit(vd->loc(), IntSetVal::a(1,sl->v().size())); + vd->e(nsl); + } else { + throw TypeError(env.envi(),ai->loc(),"invalid assignment to enum"); + } + } else { + vd->e(ai->e()); + } ai->remove(); - vd->e(ai->e()); } class TSV1 : public ItemVisitor { From 9b76951610bdc300dfdc666f7af7042d9f9e66a0 Mon Sep 17 00:00:00 2001 From: Guido Tack Date: Tue, 1 Mar 2016 15:27:25 +1100 Subject: [PATCH 02/15] Added enums into the type system. They are not checked yet but the enum types are (somewhat) propagated, so that output works in many cases. --- CMakeLists.txt | 1 + include/minizinc/flatten_internal.hh | 11 ++ include/minizinc/type.hh | 124 ++++++------ include/minizinc/typecheck.hh | 2 + lib/MIPdomains.cpp | 2 +- lib/ast.cpp | 8 +- lib/cli.cpp | 2 +- lib/flatten.cpp | 111 ++++++----- lib/htmlprinter.cpp | 2 +- lib/model.cpp | 12 +- lib/options.cpp | 8 +- lib/parser.yxx | 11 ++ lib/type.cpp | 83 ++++++++ lib/typecheck.cpp | 275 ++++++++++++++++++++------- share/minizinc/std/builtins.mzn | 1 + 15 files changed, 467 insertions(+), 186 deletions(-) create mode 100644 lib/type.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ae32090c..123a0b606 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -250,6 +250,7 @@ lib/prettyprinter.cpp #lib/solver.cpp lib/solver_instance.cpp lib/solver_instance_base.cpp +lib/type.cpp lib/typecheck.cpp lib/flatten.cpp lib/MIPdomains.cpp diff --git a/include/minizinc/flatten_internal.hh b/include/minizinc/flatten_internal.hh index abaaecb8a..ce30f7409 100644 --- a/include/minizinc/flatten_internal.hh +++ b/include/minizinc/flatten_internal.hh @@ -91,6 +91,12 @@ namespace MiniZinc { bool _failed; unsigned int ids; ASTStringMap::t reifyMap; + typedef UNORDERED_NAMESPACE::unordered_map EnumMap; + EnumMap enumMap; + std::vector enumVarDecls; + typedef UNORDERED_NAMESPACE::unordered_map ArrayEnumMap; + ArrayEnumMap arrayEnumMap; + std::vector > arrayEnumDecls; public: EnvI(Model* orig0); ~EnvI(void); @@ -101,6 +107,11 @@ namespace MiniZinc { Map::iterator map_end(void); void dump(void); + unsigned int registerEnum(VarDeclI* vdi); + VarDeclI* getEnum(unsigned int i) const; + unsigned int registerArrayEnum(const std::vector& arrayEnum); + const std::vector& getArrayEnum(unsigned int i) const; + void flat_addItem(Item* i); void flat_removeItem(int i); void flat_removeItem(Item* i); diff --git a/include/minizinc/type.hh b/include/minizinc/type.hh index abeaeb4dd..0e7157b01 100644 --- a/include/minizinc/type.hh +++ b/include/minizinc/type.hh @@ -14,9 +14,12 @@ #include #include +#include namespace MiniZinc { + class EnvI; + /// Type of a MiniZinc expression class Type { public: @@ -37,12 +40,19 @@ namespace MiniZinc { unsigned int _st : 1; unsigned int _ot : 1; unsigned int _cv : 1; + /** \brief Enumerated type identifier + * This is an index into a table in the Env. It is currently limited to + * 4095 different enumerated type identifiers. + * For a non-array type, this maps directly to the identity of the enum. + * For an array type, it maps to a tuple of enum identities. + */ + unsigned int _enumId : 12; /// Number of array dimensions - int _dim : 19; + int _dim : 7; public: /// Default constructor Type(void) : _ti(TI_PAR), _bt(BT_UNKNOWN), _st(ST_PLAIN), - _ot(OT_PRESENT), _cv(CV_NO), _dim(0) {} + _ot(OT_PRESENT), _cv(CV_NO), _enumId(0), _dim(0) {} /// Access type-inst TypeInst ti(void) const { return static_cast(_ti); } @@ -73,70 +83,85 @@ namespace MiniZinc { /// Set var-in-par type void cv(bool b) { _cv = b ? CV_YES : CV_NO; } + /// Access enum identifier + unsigned int enumId(void) const { return _enumId; } + /// Set enum identifier + void enumId(unsigned int eid) { _enumId = eid; } + /// Access dimensions int dim(void) const { return _dim; } /// Set dimensions - void dim(int d) { _dim = d; } + void dim(int d) { _dim = d; assert(_dim==d); } protected: /// Constructor Type(const TypeInst& ti, const BaseType& bt, const SetType& st, - int dim) - : _ti(ti), _bt(bt), _st(st), _ot(OT_PRESENT), _cv(ti==TI_VAR ? CV_YES : CV_NO), _dim(dim) {} + unsigned int enumId, int dim) + : _ti(ti), _bt(bt), _st(st), _ot(OT_PRESENT), _cv(ti==TI_VAR ? CV_YES : CV_NO) + , _enumId(enumId), _dim(dim) {} public: static Type parint(int dim=0) { - return Type(TI_PAR,BT_INT,ST_PLAIN,dim); + return Type(TI_PAR,BT_INT,ST_PLAIN,0,dim); + } + static Type parenum(unsigned int enumId, int dim=0) { + return Type(TI_PAR,BT_INT,ST_PLAIN,enumId,dim); } static Type parbool(int dim=0) { - return Type(TI_PAR,BT_BOOL,ST_PLAIN,dim); + return Type(TI_PAR,BT_BOOL,ST_PLAIN,0,dim); } static Type parfloat(int dim=0) { - return Type(TI_PAR,BT_FLOAT,ST_PLAIN,dim); + return Type(TI_PAR,BT_FLOAT,ST_PLAIN,0,dim); } static Type parstring(int dim=0) { - return Type(TI_PAR,BT_STRING,ST_PLAIN,dim); + return Type(TI_PAR,BT_STRING,ST_PLAIN,0,dim); } static Type ann(int dim=0) { - return Type(TI_PAR,BT_ANN,ST_PLAIN,dim); + return Type(TI_PAR,BT_ANN,ST_PLAIN,0,dim); } static Type parsetint(int dim=0) { - return Type(TI_PAR,BT_INT,ST_SET,dim); + return Type(TI_PAR,BT_INT,ST_SET,0,dim); + } + static Type parsetenum(unsigned int enumId, int dim=0) { + return Type(TI_PAR,BT_INT,ST_SET,enumId,dim); } static Type parsetbool(int dim=0) { - return Type(TI_PAR,BT_BOOL,ST_SET,dim); + return Type(TI_PAR,BT_BOOL,ST_SET,0,dim); } static Type parsetfloat(int dim=0) { - return Type(TI_PAR,BT_FLOAT,ST_SET,dim); + return Type(TI_PAR,BT_FLOAT,ST_SET,0,dim); } static Type parsetstring(int dim=0) { - return Type(TI_PAR,BT_STRING,ST_SET,dim); + return Type(TI_PAR,BT_STRING,ST_SET,0,dim); } static Type varint(int dim=0) { - return Type(TI_VAR,BT_INT,ST_PLAIN,dim); + return Type(TI_VAR,BT_INT,ST_PLAIN,0,dim); + } + static Type varenumint(unsigned int enumId, int dim=0) { + return Type(TI_VAR,BT_INT,ST_PLAIN,enumId,dim); } static Type varbool(int dim=0) { - return Type(TI_VAR,BT_BOOL,ST_PLAIN,dim); + return Type(TI_VAR,BT_BOOL,ST_PLAIN,0,dim); } static Type varfloat(int dim=0) { - return Type(TI_VAR,BT_FLOAT,ST_PLAIN,dim); + return Type(TI_VAR,BT_FLOAT,ST_PLAIN,0,dim); } static Type varsetint(int dim=0) { - return Type(TI_VAR,BT_INT,ST_SET,dim); + return Type(TI_VAR,BT_INT,ST_SET,0,dim); } static Type varbot(int dim=0) { - return Type(TI_VAR,BT_BOT,ST_PLAIN,dim); + return Type(TI_VAR,BT_BOT,ST_PLAIN,0,dim); } static Type bot(int dim=0) { - return Type(TI_PAR,BT_BOT,ST_PLAIN,dim); + return Type(TI_PAR,BT_BOT,ST_PLAIN,0,dim); } static Type top(int dim=0) { - return Type(TI_PAR,BT_TOP,ST_PLAIN,dim); + return Type(TI_PAR,BT_TOP,ST_PLAIN,0,dim); } static Type vartop(int dim=0) { - return Type(TI_VAR,BT_TOP,ST_PLAIN,dim); + return Type(TI_VAR,BT_TOP,ST_PLAIN,0,dim); } static Type optvartop(int dim=0) { - Type t(TI_VAR,BT_TOP,ST_PLAIN,dim); + Type t(TI_VAR,BT_TOP,ST_PLAIN,0,dim); t._ot = OT_OPTIONAL; return t; } @@ -192,6 +217,7 @@ namespace MiniZinc { + (static_cast(_bt)<<24) + (static_cast(_ti)<<21) + (static_cast(_ot)<<20) + + (static_cast(_enumId)<<8) + (_dim == -1 ? 1 : (_dim == 0 ? 0 : _dim+1)); } static Type fromInt(int i) { @@ -200,46 +226,24 @@ namespace MiniZinc { t._bt = static_cast((i >> 24) & 0xF); t._ti = static_cast((i >> 21) & 0x7); t._ot = static_cast((i >> 20) & 0x1); - int dim = (i & 0xFFFFF); + t._enumId = static_cast((i >> 8) & 0xFFF); + int dim = (i & 0x7F); t._dim = (dim == 0 ? 0 : (dim==1 ? -1 : dim-1)); return t; } - std::string toString(void) const { - std::ostringstream oss; - if (_dim>0) { - oss<<"array[int"; - for (int i=1; i<_dim; i++) - oss << ",int"; - oss<<"] of "; - } - if (_dim<0) - oss<<"array[$_] of "; - switch (_ti) { - case TI_PAR: break; - case TI_VAR: oss<<"var "; break; - } - if (_ot==OT_OPTIONAL) oss<<"opt "; - if (_st==ST_SET) oss<<"set of "; - switch (_bt) { - case BT_INT: oss<<"int"; break; - case BT_BOOL: oss<<"bool"; break; - case BT_FLOAT: oss<<"float"; break; - case BT_STRING: oss<<"string"; break; - case BT_ANN: oss<<"ann"; break; - case BT_BOT: oss<<"bot"; break; - case BT_TOP: oss<<"top"; break; - case BT_UNKNOWN: oss<<"??? "; break; - } - return oss.str(); - } + std::string toString(EnvI& env) const; + std::string nonEnumToString(void) const; public: /// Check if \a bt0 is a subtype of \a bt1 - static bool bt_subtype(const BaseType& bt0, const BaseType& bt1) { - if (bt0==bt1) + static bool bt_subtype(const Type& t0, const Type& t1) { + // TODO: this should be + // if (t0.bt() == t1.bt() && (t0.enumId() == t1.enumId() || t1.enumId()==0)) + // But currently subtyping on enums does not work yet + if (t0.bt() == t1.bt()) return true; - switch (bt0) { - case BT_BOOL: return (bt1==BT_INT || bt1==BT_FLOAT); - case BT_INT: return bt1==BT_FLOAT; + switch (t0.bt()) { + case BT_BOOL: return (t1.bt()==BT_INT || t1.bt()==BT_FLOAT); + case BT_INT: return t1.bt()==BT_FLOAT; default: return false; } } @@ -247,17 +251,17 @@ namespace MiniZinc { /// Check if this type is a subtype of \a t bool isSubtypeOf(const Type& t) const { if (_dim==0 && t._dim!=0 && _st==ST_SET && t._st==ST_PLAIN && - ( bt()==BT_BOT || bt_subtype(bt(), t.bt()) || t.bt()==BT_TOP) && _ti==TI_PAR && + ( bt()==BT_BOT || bt_subtype(*this, t) || t.bt()==BT_TOP) && _ti==TI_PAR && (_ot==OT_PRESENT || _ot==t._ot) ) return true; // either same dimension or t has variable dimension if (_dim!=t._dim && (_dim==0 || t._dim!=-1)) return false; // same type, this is present or both optional - if (_ti==t._ti && bt_subtype(bt(),t.bt()) && _st==t._st) + if (_ti==t._ti && bt_subtype(*this,t) && _st==t._st) return _ot==OT_PRESENT || _ot==t._ot; // this is par other than that same type as t - if (_ti==TI_PAR && bt_subtype(bt(),t.bt()) && _st==t._st) + if (_ti==TI_PAR && bt_subtype(*this,t) && _st==t._st) return _ot==OT_PRESENT || _ot==t._ot; if ( _ti==TI_PAR && t._bt==BT_BOT) return true; diff --git a/include/minizinc/typecheck.hh b/include/minizinc/typecheck.hh index 4446938a9..e42b712d8 100644 --- a/include/minizinc/typecheck.hh +++ b/include/minizinc/typecheck.hh @@ -38,6 +38,8 @@ namespace MiniZinc { /// Add a variable declaration void add(EnvI& env, VarDecl* vd, bool unique); + /// Add a variable declaration item + void add(EnvI& env, VarDeclI* vd, bool unique); /// Remove a variable declaration void remove(EnvI& env, VarDecl* vd); /// Get variable declaration from identifier \a id diff --git a/lib/MIPdomains.cpp b/lib/MIPdomains.cpp index 5129a1582..0d810e7e2 100644 --- a/lib/MIPdomains.cpp +++ b/lib/MIPdomains.cpp @@ -964,7 +964,7 @@ namespace MiniZinc { } else { MZN_MIPD__assert_for_feas( 0, "Variable " << vd->id()->str() - << " of type " << vd->type().toString() + << " of type " << vd->type().toString(mipd.__env->envi()) << " has a domain." ); } // /// Deleting var domain: diff --git a/lib/ast.cpp b/lib/ast.cpp index 8b81de915..38d2fda90 100644 --- a/lib/ast.cpp +++ b/lib/ast.cpp @@ -695,8 +695,8 @@ namespace MiniZinc { } else { throw TypeError(env, getLoc(ta[i],fi),"type-inst variable $"+ tiid.str()+" instantiated with different types ("+ - tiit.toString()+" vs "+ - it->second.toString()+")"); + tiit.toString(env)+" vs "+ + it->second.toString(env)+")"); } } } @@ -720,8 +720,8 @@ namespace MiniZinc { } else if (it->second!=tiit) { throw TypeError(env, getLoc(ta[i],fi),"type-inst variable $"+ tiid.str()+" instantiated with different types ("+ - tiit.toString()+" vs "+ - it->second.toString()+")"); + tiit.toString(env)+" vs "+ + it->second.toString(env)+")"); } } } diff --git a/lib/cli.cpp b/lib/cli.cpp index 691897e84..5c2d336d8 100644 --- a/lib/cli.cpp +++ b/lib/cli.cpp @@ -26,7 +26,7 @@ namespace MiniZinc { } } std::stringstream ss; - ss << "For option: " << name << " expected Par String vector, received " << e->type().toString() << std::endl; + ss << "For option: " << name << " expected Par String vector, received " << e->type().nonEnumToString() << std::endl; throw InternalError(ss.str()); } diff --git a/lib/flatten.cpp b/lib/flatten.cpp index efeec6030..9d2fca1e7 100644 --- a/lib/flatten.cpp +++ b/lib/flatten.cpp @@ -342,6 +342,45 @@ namespace MiniZinc { return _failed; } + + unsigned int EnvI::registerEnum(VarDeclI* vdi) { + EnumMap::iterator it = enumMap.find(vdi); + unsigned int ret; + if (it == enumMap.end()) { + ret = enumVarDecls.size(); + enumVarDecls.push_back(vdi); + enumMap.insert(std::make_pair(vdi, ret)); + } else { + ret = it->second; + } + return ret+1; + } + VarDeclI* EnvI::getEnum(unsigned int i) const { + assert(i > 0 && i <= enumVarDecls.size()); + return enumVarDecls[i-1]; + } + unsigned int EnvI::registerArrayEnum(const std::vector& arrayEnum) { + std::ostringstream oss; + for (unsigned int i=0; isecond; + } + return ret+1; + } + const std::vector& EnvI::getArrayEnum(unsigned int i) const { + assert(i > 0 && i <= arrayEnumDecls.size()); + return arrayEnumDecls[i-1]; + } + + void EnvI::collectVarDecls(bool b) { collect_vardecls = b; } @@ -5097,7 +5136,7 @@ namespace MiniZinc { if (decl==NULL) { FunctionI* origdecl = env.orig->matchFn(env, c.id(), tv); if (origdecl == NULL) { - throw FlatteningError(env,c.loc(),"function is used in output, par version needed"); + throw FlatteningError(env,c.loc(),"function "+c.id().str()+" is used in output, par version needed"); } if (origdecl->e() && cannotUseRHSForOutput(env, origdecl->e())) { @@ -5172,21 +5211,15 @@ namespace MiniZinc { Decls(EnvI& env0) : env(env0) {} void vCall(Call& c) { if (c.id()=="format" || c.id()=="show") { - if (Id* ident = c.args()[c.args().size()-1]->dyn_cast()) { - if (Id* ti_id = Expression::dyn_cast(ident->decl()->ti()->domain())) { - if (ti_id->decl()->ti()->isEnum()) { - GCLock lock; - - - - std::vector args(1); - args[0] = c.args()[c.args().size()-1]; - std::string enumName = "_toString_"+ti_id->str().str(); - Call* convertEnum = new Call(Location().introduce(),enumName,args); - convertEnum->type(Type::parstring()); - c.args()[c.args().size()-1] = convertEnum; - } - } + if (c.args()[c.args().size()-1]->type().enumId() > 0) { + Id* ti_id = env.getEnum(c.args()[c.args().size()-1]->type().enumId())->e()->id(); + GCLock lock; + std::vector args(1); + args[0] = c.args()[c.args().size()-1]; + std::string enumName = "_toString_"+ti_id->str().str(); + Call* convertEnum = new Call(Location().introduce(),enumName,args); + convertEnum->type(Type::parstring()); + c.args()[c.args().size()-1] = convertEnum; } } c.decl(env.orig->matchFn(env,&c)); @@ -5243,7 +5276,7 @@ namespace MiniZinc { if (decl==NULL) { FunctionI* origdecl = env.orig->matchFn(env, rhs->id(), tv); if (origdecl == NULL) { - throw FlatteningError(env,rhs->loc(),"function is used in output, par version needed"); + throw FlatteningError(env,rhs->loc(),"function "+rhs->id().str()+" is used in output, par version needed"); } if (!origdecl->from_stdlib()) { decl = copy(env,env.cmap,origdecl)->cast(); @@ -5312,15 +5345,13 @@ namespace MiniZinc { } } }; - for (unsigned int i=e.orig->size(); i--;) { - if (OutputI* oi = (*e.orig)[i]->dyn_cast()) { - GCLock lock; - OutputI* noi = copy(e,oi)->cast(); - CopyOutput co(e); - topDown(co, noi->e()); - e.flat_addItem(noi); - break; - } + + if (OutputI* oi = e.orig->outputItem()) { + GCLock lock; + OutputI* noi = copy(e,oi)->cast(); + CopyOutput co(e); + topDown(co, noi->e()); + e.flat_addItem(noi); } } @@ -5362,7 +5393,7 @@ namespace MiniZinc { if (decl==NULL) { FunctionI* origdecl = e.orig->matchFn(e, rhs->id(), tv); if (origdecl == NULL) { - throw FlatteningError(e,rhs->loc(),"function is used in output, par version needed"); + throw FlatteningError(e,rhs->loc(),"function "+rhs->id().str()+" is used in output, par version needed"); } if (!origdecl->from_stdlib()) { decl = copy(e,e.cmap,origdecl)->cast(); @@ -5466,20 +5497,11 @@ namespace MiniZinc { OutputI* outputItem = NULL; GCLock lock; - class OV1 : public ItemVisitor { - public: - EnvI& env; - VarOccurrences& vo; - OutputI*& outputItem; - OV1(EnvI& env0, VarOccurrences& vo0, OutputI*& outputItem0) - : env(env0), vo(vo0), outputItem(outputItem0) {} - void vOutputI(OutputI* oi) { - outputItem = copy(env,env.cmap, oi)->cast(); - makePar(env,outputItem->e()); - env.output->addItem(outputItem); - } - } _ov1(e,e.output_vo,outputItem); - iterItems(_ov1,e.orig); + if (e.orig->outputItem()) { + outputItem = copy(e,e.cmap, e.orig->outputItem())->cast(); + makePar(e,outputItem->e()); + e.output->addItem(outputItem); + } if (outputItem==NULL) { // Create output item for all variables defined at toplevel in the MiniZinc source @@ -5544,7 +5566,7 @@ namespace MiniZinc { if (decl==NULL) { FunctionI* origdecl = env.orig->matchFn(env, c.id(), tv); if (origdecl == NULL || !origdecl->rtype(env, tv).ispar()) { - throw FlatteningError(env,c.loc(),"function is used in output, par version needed"); + throw FlatteningError(env,c.loc(),"function "+c.id().str()+" is used in output, par version needed"); } if (!origdecl->from_stdlib()) { decl = copy(env,env.cmap,origdecl)->cast(); @@ -5576,6 +5598,7 @@ namespace MiniZinc { if (Expression* vd_e = env.cmap.find(vdi->e())) { VarDecl* vd = vd_e->cast(); VarDeclI* vdi_copy = copy(env,env.cmap,vdi)->cast(); + Type t = vdi_copy->e()->ti()->type(); t.ti(Type::TI_PAR); vdi_copy->e()->ti()->domain(NULL); @@ -5610,7 +5633,7 @@ namespace MiniZinc { if (decl==NULL) { FunctionI* origdecl = env.orig->matchFn(env, rhs->id(), tv); if (origdecl == NULL) { - throw FlatteningError(env,rhs->loc(),"function is used in output, par version needed"); + throw FlatteningError(env,rhs->loc(),"function "+rhs->id().str()+" is used in output, par version needed"); } if (!origdecl->from_stdlib()) { decl = copy(env,env.cmap,origdecl)->cast(); @@ -6261,7 +6284,7 @@ namespace MiniZinc { if (decl==NULL) { FunctionI* origdecl = env.orig->matchFn(env, rhs->id(), tv); if (origdecl == NULL) { - throw FlatteningError(env,rhs->loc(),"function is used in output, par version needed"); + throw FlatteningError(env,rhs->loc(),"function "+rhs->id().str()+" is used in output, par version needed"); } if (!isBuiltin(origdecl)) { decl = copy(env,env.cmap,origdecl)->cast(); diff --git a/lib/htmlprinter.cpp b/lib/htmlprinter.cpp index 7f9d16c5a..678d50868 100644 --- a/lib/htmlprinter.cpp +++ b/lib/htmlprinter.cpp @@ -444,7 +444,7 @@ namespace MiniZinc { os << ""; GCLock lock; HtmlDocOutput::DocItem di(vdi->e()->type().ispar() ? HtmlDocOutput::DocItem::T_PAR: HtmlDocOutput::DocItem::T_VAR, - vdi->e()->type().toString()+" "+vdi->e()->id()->str().str(), os.str()); + vdi->e()->type().toString(env)+" "+vdi->e()->id()->str().str(), os.str()); HtmlDocOutput::addToGroup(_maingroup, group, di); } } diff --git a/lib/model.cpp b/lib/model.cpp index 3b931bb57..32a6f2ef0 100644 --- a/lib/model.cpp +++ b/lib/model.cpp @@ -124,8 +124,8 @@ namespace MiniZinc { for (unsigned int j=0; jparams()[j]->type())) { #ifdef MZN_DEBUG_FUNCTION_REGISTRY - std::cerr << t[j].toString() << " does not match " - << fi->params()[j]->type().toString() << "\n"; + std::cerr << t[j].toString(env) << " does not match " + << fi->params()[j]->type().toString(env) << "\n"; #endif match=false; break; @@ -205,8 +205,8 @@ namespace MiniZinc { for (unsigned int j=0; jtype().isSubtypeOf(fi->params()[j]->type())) { #ifdef MZN_DEBUG_FUNCTION_REGISTRY - std::cerr << args[j]->type().toString() << " does not match " - << fi->params()[j]->type().toString() << "\n"; + std::cerr << args[j]->type().toString(env) << " does not match " + << fi->params()[j]->type().toString(env) << "\n"; #endif match=false; break; @@ -260,8 +260,8 @@ namespace MiniZinc { for (unsigned int j=0; jargs().size(); j++) { if (!c->args()[j]->type().isSubtypeOf(fi->params()[j]->type())) { #ifdef MZN_DEBUG_FUNCTION_REGISTRY - std::cerr << c->args()[j]->type().toString() << " does not match " - << fi->params()[j]->type().toString() << "\n"; + std::cerr << c->args()[j]->type().toString(env) << " does not match " + << fi->params()[j]->type().toString(env) << "\n"; std::cerr << "Wrong argument is " << *c->args()[j]; #endif match=false; diff --git a/lib/options.cpp b/lib/options.cpp index 20b2cfe51..98a4220bb 100644 --- a/lib/options.cpp +++ b/lib/options.cpp @@ -30,7 +30,7 @@ namespace MiniZinc { _options[name] = ka; } else { std::stringstream ss; - ss << "For option: " << name << " expected Par Int, received " << e->type().toString() << std::endl; + ss << "For option: " << name << " expected Par Int, received " << e->type().nonEnumToString() << std::endl; throw InternalError(ss.str()); } } @@ -40,7 +40,7 @@ namespace MiniZinc { _options[name] = ka; } else { std::stringstream ss; - ss << "For option: " << name << " expected Par Float, received " << e->type().toString() << std::endl; + ss << "For option: " << name << " expected Par Float, received " << e->type().nonEnumToString() << std::endl; throw InternalError(ss.str()); } } @@ -50,7 +50,7 @@ namespace MiniZinc { _options[name] = ka; } else { std::stringstream ss; - ss << "For option: " << name << " expected Par Bool, received " << e->type().toString() << std::endl; + ss << "For option: " << name << " expected Par Bool, received " << e->type().nonEnumToString() << std::endl; throw InternalError(ss.str()); } } @@ -60,7 +60,7 @@ namespace MiniZinc { _options[name] = ka; } else { std::stringstream ss; - ss << "For option: " << name << " expected Par String, received " << e->type().toString() << std::endl; + ss << "For option: " << name << " expected Par String, received " << e->type().nonEnumToString() << std::endl; throw InternalError(ss.str()); } } diff --git a/lib/parser.yxx b/lib/parser.yxx index 3f0f99893..2d1680e3c 100644 --- a/lib/parser.yxx +++ b/lib/parser.yxx @@ -807,6 +807,17 @@ vardecl_item : delete $5; $$ = new VarDeclI(@$,vd); } + | MZN_ENUM MZN_IDENTIFIER MZN_EQ MZN_IDENTIFIER '(' expr ')' + { + TypeInst* ti = new TypeInst(@$,Type::parsetint()); + ti->setIsEnum(true); + vector args; + args.push_back($6); + Call* sl = new Call(@$, ASTString($4), args); + VarDecl* vd = new VarDecl(@$,ti,$2,sl); + free($2); + $$ = new VarDeclI(@$,vd); + } enum_id_list : // empty diff --git a/lib/type.cpp b/lib/type.cpp new file mode 100644 index 000000000..b7b4cd920 --- /dev/null +++ b/lib/type.cpp @@ -0,0 +1,83 @@ +/* -*- 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/. */ + +#include +#include + +namespace MiniZinc { + + std::string Type::toString(EnvI& env) const { + std::ostringstream oss; + if (_dim>0) { + oss<<"array[int"; + for (int i=1; i<_dim; i++) + oss << ",int"; + oss<<"] of "; + } + if (_dim<0) + oss<<"array[$_] of "; + switch (_ti) { + case TI_PAR: break; + case TI_VAR: oss<<"var "; break; + } + if (_ot==OT_OPTIONAL) oss<<"opt "; + if (_st==ST_SET) oss<<"set of "; + switch (_bt) { + case BT_INT: + { + if (_enumId==0) { + oss<<"int"; + } else { + oss << *env.getEnum(_enumId)->e()->id(); + } + } + break; + case BT_BOOL: oss<<"bool"; break; + case BT_FLOAT: oss<<"float"; break; + case BT_STRING: oss<<"string"; break; + case BT_ANN: oss<<"ann"; break; + case BT_BOT: oss<<"bot"; break; + case BT_TOP: oss<<"top"; break; + case BT_UNKNOWN: oss<<"??? "; break; + } + return oss.str(); + } + + std::string Type::nonEnumToString(void) const { + std::ostringstream oss; + if (_dim>0) { + oss<<"array[int"; + for (int i=1; i<_dim; i++) + oss << ",int"; + oss<<"] of "; + } + if (_dim<0) + oss<<"array[$_] of "; + switch (_ti) { + case TI_PAR: break; + case TI_VAR: oss<<"var "; break; + } + if (_ot==OT_OPTIONAL) oss<<"opt "; + if (_st==ST_SET) oss<<"set of "; + switch (_bt) { + case BT_INT: oss<<"int"; break; + case BT_BOOL: oss<<"bool"; break; + case BT_FLOAT: oss<<"float"; break; + case BT_STRING: oss<<"string"; break; + case BT_ANN: oss<<"ann"; break; + case BT_BOT: oss<<"bot"; break; + case BT_TOP: oss<<"top"; break; + case BT_UNKNOWN: oss<<"??? "; break; + } + return oss.str(); + } + +} diff --git a/lib/typecheck.cpp b/lib/typecheck.cpp index 274e4229f..abb2a5e47 100644 --- a/lib/typecheck.cpp +++ b/lib/typecheck.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -53,47 +54,174 @@ namespace MiniZinc { } }; - void createEnumMapper(EnvI& env, Model* m, Id* ident, SetLit* sl) { + void createEnumMapper(EnvI& env, Model* m, unsigned int enumId, Id* ident, SetLit* sl) { GCLock lock; - std::vector ranges(1); - ranges[0] = new TypeInst(Location().introduce(),Type::parint()); - TypeInst* ti = new TypeInst(Location().introduce(),Type::parstring(1)); - ti->setRanges(ranges); - std::string name = "_enum_to_string_"+ident->str().str(); - std::vector al_args(sl->v().size()); - for (unsigned int i=0; iv().size(); i++) { - al_args[i] = new StringLit(Location().introduce(),sl->v()[i]->cast()->str()); + if (sl) { + std::vector ranges(1); + ranges[0] = new TypeInst(Location().introduce(),Type::parint()); + TypeInst* ti = new TypeInst(Location().introduce(),Type::parstring(1)); + ti->setRanges(ranges); + std::string name = "_enum_to_string_"+ident->str().str(); + std::vector al_args(sl->v().size()); + for (unsigned int i=0; iv().size(); i++) { + al_args[i] = new StringLit(Location().introduce(),sl->v()[i]->cast()->str()); + } + ArrayLit* al = new ArrayLit(Location().introduce(),al_args); + VarDecl* vd = new VarDecl(Location().introduce(),ti,name,al); + m->addItem(new VarDeclI(Location().introduce(),vd)); + + TypeInst* ti_aa = new TypeInst(Location().introduce(),Type::parint()); + VarDecl* vd_aa = new VarDecl(Location().introduce(),ti_aa,"x"); + vd_aa->toplevel(false); + std::vector aa_args(1); + aa_args[0] = vd_aa->id(); + ArrayAccess* aa = new ArrayAccess(Location().introduce(),vd->id(),aa_args); + TypeInst* ti_fi = new TypeInst(Location().introduce(),Type::parstring()); + std::vector fi_params(1); + fi_params[0] = vd_aa; + FunctionI* fi = new FunctionI(Location().introduce(),"_toString_"+ident->str().str(),ti_fi,fi_params,aa); + m->addItem(fi); + } else { + TypeInst* ti_aa = new TypeInst(Location().introduce(),Type::parint()); + VarDecl* vd_aa = new VarDecl(Location().introduce(),ti_aa,"x"); + vd_aa->toplevel(false); + + StringLit* sl = new StringLit(Location().introduce(), ASTString(ident->str().str()+"_")); + std::vector showIntArgs(1); + showIntArgs[0] = vd_aa->id(); + Call* showInt = new Call(Location().introduce(), constants().ids.show, showIntArgs); + BinOp* construct_string = new BinOp(Location().introduce(), sl, BOT_PLUSPLUS, showInt); + + TypeInst* ti_fi = new TypeInst(Location().introduce(),Type::parstring()); + std::vector fi_params(1); + fi_params[0] = vd_aa; + FunctionI* fi = new FunctionI(Location().introduce(),"_toString_"+ident->str().str(),ti_fi,fi_params,construct_string); + m->addItem(fi); } - ArrayLit* al = new ArrayLit(Location().introduce(),al_args); - VarDecl* vd = new VarDecl(Location().introduce(),ti,name,al); - m->addItem(new VarDeclI(Location().introduce(),vd)); - TypeInst* ti_aa = new TypeInst(Location().introduce(),Type::parint()); - VarDecl* vd_aa = new VarDecl(Location().introduce(),ti_aa,"x"); - vd_aa->toplevel(false); - std::vector aa_args(1); - aa_args[0] = vd_aa->id(); - ArrayAccess* aa = new ArrayAccess(Location().introduce(),vd->id(),aa_args); + /* + + function _toString_ENUM(array[$U] of ENUM: x) = + let { + array[int] of ENUM: xx = array1d(x) + } in "[" ++ join(", ", [ _toString_ENUM(xx[i]) | i in index_set(xx) ]) ++ "]"; + + */ + + Type argType = Type::parenum(ident->type().enumId()); + + TIId* tiid = new TIId(Location().introduce(),"U"); + TypeInst* ti_range = new TypeInst(Location().introduce(),argType,tiid); + std::vector ranges(1); + ranges[0] = ti_range; + + TypeInst* x_ti = new TypeInst(Location().introduce(),Type::parint(-1),ranges,ident); + VarDecl* vd_x = new VarDecl(Location().introduce(),x_ti,"x"); + vd_x->toplevel(false); + + TypeInst* xx_range = new TypeInst(Location().introduce(),Type::parint(),NULL); + std::vector xx_ranges(1); + xx_ranges[0] = xx_range; + TypeInst* xx_ti = new TypeInst(Location().introduce(),argType,xx_ranges); + + std::vector array1dArgs(1); + array1dArgs[0] = vd_x->id(); + Call* array1dCall = new Call(Location().introduce(),"array1d",array1dArgs); + + VarDecl* vd_xx = new VarDecl(Location().introduce(),xx_ti,"xx",array1dCall); + vd_xx->toplevel(false); + + TypeInst* idx_i_ti = new TypeInst(Location().introduce(),Type::parint()); + VarDecl* idx_i = new VarDecl(Location().introduce(),idx_i_ti,"i"); + idx_i->toplevel(false); + + std::vector aa_xxi_idx(1); + aa_xxi_idx[0] = idx_i->id(); + ArrayAccess* aa_xxi = new ArrayAccess(Location().introduce(),vd_xx->id(),aa_xxi_idx); + + std::vector _toString_ENUMArgs(1); + _toString_ENUMArgs[0] = aa_xxi; + Call* _toString_ENUM = new Call(Location().introduce(),"_toString_"+ident->str().str(),_toString_ENUMArgs); + + std::vector index_set_xx_args(1); + index_set_xx_args[0] = vd_xx->id(); + Call* index_set_xx = new Call(Location().introduce(),"index_set",index_set_xx_args); + std::vector gen_exps(1); + gen_exps[0] = idx_i; + Generator gen(gen_exps,index_set_xx); + + Generators generators; + generators._g.push_back(gen); + Comprehension* comp = new Comprehension(Location().introduce(),_toString_ENUM,generators,false); + + std::vector join_args(2); + join_args[0] = new StringLit(Location().introduce(),", "); + join_args[1] = comp; + Call* join = new Call(Location().introduce(),"join",join_args); + + std::vector let_args(1); + let_args[0] = vd_xx; + Let* let = new Let(Location().introduce(),let_args,join); + TypeInst* ti_fi = new TypeInst(Location().introduce(),Type::parstring()); std::vector fi_params(1); - fi_params[0] = vd_aa; - FunctionI* fi = new FunctionI(Location().introduce(),"_toString_"+ident->str().str(),ti_fi,fi_params,aa); + fi_params[0] = vd_x; + FunctionI* fi = new FunctionI(Location().introduce(),"_toString_"+ident->str().str(),ti_fi,fi_params,let); m->addItem(fi); } void - TopoSorter::add(EnvI& env, VarDecl* vd, bool unique) { + TopoSorter::add(EnvI& env, VarDeclI* vdi, bool unique) { + VarDecl* vd = vdi->e(); if (vd->ti()->isEnum() && vd->e()) { - SetLit* sl = vd->e()->cast(); + unsigned int enumId = env.registerEnum(vdi); + GCLock lock; - for (unsigned int i=0; iv().size(); i++) { - TypeInst* ti_id = new TypeInst(sl->v()[i]->loc(),Type::parint()); - VarDecl* vd_id = new VarDecl(ti_id->loc(),ti_id,sl->v()[i]->cast()->str(),IntLit::a(i+1)); - model->addItem(new VarDeclI(vd_id->loc(),vd_id)); + if (Call* c = vd->e()->dyn_cast()) { + if (c->id()!="anon_enum") { + throw TypeError(env, vd->loc(), "invalid initialisation for enum"); + } + Type vdt = vd->type(); + vdt.enumId(enumId); + vd->ti()->type(vdt); + vd->type(vdt); + createEnumMapper(env, model, enumId, vd->id(), NULL); + } else { + SetLit* sl = vd->e()->cast(); + for (unsigned int i=0; iv().size(); i++) { + TypeInst* ti_id = new TypeInst(sl->v()[i]->loc(),Type::parenum(enumId)); + VarDecl* vd_id = new VarDecl(ti_id->loc(),ti_id,sl->v()[i]->cast()->str(),IntLit::a(i+1)); + model->addItem(new VarDeclI(vd_id->loc(),vd_id)); + } + SetLit* nsl = new SetLit(vd->loc(), IntSetVal::a(1,sl->v().size())); + Type nslt = nsl->type(); + nslt.enumId(enumId); + nsl->type(nslt); + Type vdt = vd->type(); + vdt.enumId(enumId); + vd->ti()->type(vdt); + vd->type(vdt); + createEnumMapper(env, model, enumId, vd->id(), sl); + vd->e(nsl); } - SetLit* nsl = new SetLit(vd->loc(), IntSetVal::a(1,sl->v().size())); - createEnumMapper(env, model, vd->id(), sl); - vd->e(nsl); + } + DeclMap::iterator vd_id = idmap.find(vd->id()); + if (vd_id == idmap.end()) { + Decls nd; nd.push_back(vd); + idmap.insert(vd->id(),nd); + } else { + if (unique) { + GCLock lock; + throw TypeError(env, vd->loc(),"identifier `"+vd->id()->str().str()+ + "' already defined"); + } + vd_id->second.push_back(vd); + } + } + void + TopoSorter::add(EnvI& env, VarDecl* vd, bool unique) { + if (vd->ti()->isEnum() && vd->e()) { + throw TypeError(env, vd->loc(), "enums are only allowed at top level"); } DeclMap::iterator vdi = idmap.find(vd->id()); if (vdi == idmap.end()) { @@ -360,7 +488,7 @@ namespace MiniZinc { KeepAlive ka(c); return ka; } - throw TypeError(env, e->loc(),"cannot determine coercion from type "+e->type().toString()+" to type "+funarg_t.toString()); + throw TypeError(env, e->loc(),"cannot determine coercion from type "+e->type().toString(env)+" to type "+funarg_t.toString(env)); } KeepAlive addCoercion(EnvI& env, Model* m, Expression* e, Expression* funarg) { return addCoercion(env, m, e, funarg->type()); @@ -377,7 +505,7 @@ namespace MiniZinc { void exit(Expression* e) { for (ExpressionSetIter it = e->ann().begin(); it != e->ann().end(); ++it) if (!(*it)->type().isann()) - throw TypeError(_env,(*it)->loc(),"expected annotation, got `"+(*it)->type().toString()+"'"); + throw TypeError(_env,(*it)->loc(),"expected annotation, got `"+(*it)->type().toString(_env)+"'"); } bool enter(Expression*) { return true; } /// Visit integer literal @@ -401,8 +529,8 @@ namespace MiniZinc { ty.ti(Type::TI_VAR); if (sl.v()[i]->type().cv()) ty.cv(true); - if (!Type::bt_subtype(sl.v()[i]->type().bt(), ty.bt())) { - if (ty.bt() == Type::BT_UNKNOWN || Type::bt_subtype(ty.bt(), sl.v()[i]->type().bt())) { + if (!Type::bt_subtype(sl.v()[i]->type(), ty)) { + if (ty.bt() == Type::BT_UNKNOWN || Type::bt_subtype(ty, sl.v()[i]->type())) { ty.bt(sl.v()[i]->type().bt()); } else { throw TypeError(_env,sl.loc(),"non-uniform set literal"); @@ -464,9 +592,13 @@ namespace MiniZinc { if (ty.st() != vi->type().st()) { throw TypeError(_env,al.loc(),"non-uniform array literal"); } + if (ty.enumId() != vi->type().enumId()) { + ty.enumId(0); + } } else { haveInferredType = true; ty.st(vi->type().st()); + ty.enumId(vi->type().enumId()); } if (vi->type().bt() != Type::BT_BOT) { ty.bt(vi->type().bt()); @@ -478,11 +610,18 @@ namespace MiniZinc { if (vi->type().st() != ty.st()) { throw TypeError(_env,al.loc(),"non-uniform array literal"); } + if (ty.enumId() != vi->type().enumId()) { + ty.enumId(0); + } } else { - if (Type::bt_subtype(ty.bt(), vi->type().bt())) { + unsigned int tyEnumId = ty.enumId(); + ty.enumId(vi->type().enumId()); + if (Type::bt_subtype(ty, vi->type())) { ty.bt(vi->type().bt()); } - if (!Type::bt_subtype(vi->type().bt(),ty.bt()) || ty.st() != vi->type().st()) { + if (tyEnumId != vi->type().enumId()) + ty.enumId(0); + if (!Type::bt_subtype(vi->type(),ty) || ty.st() != vi->type().st()) { throw TypeError(_env,al.loc(),"non-uniform array literal"); } } @@ -535,7 +674,7 @@ namespace MiniZinc { aai->type(Type::varint()); } if (aai->type().is_set() || (aai->type().bt() != Type::BT_INT && aai->type().bt() != Type::BT_BOOL) || aai->type().dim() != 0) { - throw TypeError(_env,aai->loc(),"array index must be `int', but is `"+aai->type().toString()+"'"); + throw TypeError(_env,aai->loc(),"array index must be `int', but is `"+aai->type().toString(_env)+"'"); } aa.idx()[i] = addCoercion(_env, _model, aai, Type::varint())(); if (aai->type().isopt()) { @@ -569,7 +708,7 @@ namespace MiniZinc { } else if (c.where()->type() != Type::parbool()) { throw TypeError(_env,c.where()->loc(), "where clause must be bool, but is `"+ - c.where()->type().toString()+"'"); + c.where()->type().toString(_env)+"'"); } if (c.where()->type().cv()) tt.cv(true); @@ -578,7 +717,7 @@ namespace MiniZinc { if (c.e()->type().dim() != 0 || c.e()->type().st() == Type::ST_SET) throw TypeError(_env,c.e()->loc(), "set comprehension expression must be scalar, but is `" - +c.e()->type().toString()+"'"); + +c.e()->type().toString(_env)+"'"); tt.st(Type::ST_SET); } else { if (c.e()->type().dim() != 0) @@ -594,7 +733,8 @@ namespace MiniZinc { const Type& ty_in = g_in->type(); if (ty_in != Type::varsetint() && ty_in != Type::parsetint() && ty_in.dim() != 1) { throw TypeError(_env,g_in->loc(), - "generator expression must be (par or var) set of int or one-dimensional array, but is `"+ty_in.toString()+"'"); + "generator expression must be (par or var) set of int or one-dimensional array, but is `" + +ty_in.toString(_env)+"'"); } Type ty_id; bool needIntLit = false; @@ -636,7 +776,7 @@ namespace MiniZinc { if (eif->type() != Type::parbool() && eif->type() != Type::varbool()) throw TypeError(_env,eif->loc(), "expected bool conditional expression, got `"+ - eif->type().toString()+"'"); + eif->type().toString(_env)+"'"); if (eif->type().cv()) tret.cv(true); if (ethen->type().isunknown()) { @@ -649,15 +789,15 @@ namespace MiniZinc { } else { if (tret.isbot() || tret.isunknown()) tret.bt(ethen->type().bt()); - if ( (!ethen->type().isbot() && !Type::bt_subtype(ethen->type().bt(), tret.bt()) && !Type::bt_subtype(tret.bt(), ethen->type().bt())) || + if ( (!ethen->type().isbot() && !Type::bt_subtype(ethen->type(), tret) && !Type::bt_subtype(tret, ethen->type())) || ethen->type().st() != tret.st() || ethen->type().dim() != tret.dim()) { throw TypeError(_env,ethen->loc(), "type mismatch in branches of conditional. Then-branch has type `"+ - ethen->type().toString()+"', but else branch has type `"+ - tret.toString()+"'"); + ethen->type().toString(_env)+"', but else branch has type `"+ + tret.toString(_env)+"'"); } - if (Type::bt_subtype(tret.bt(), ethen->type().bt())) { + if (Type::bt_subtype(tret, ethen->type())) { tret.bt(ethen->type().bt()); } if (ethen->type().isvar()) allpar=false; @@ -703,8 +843,9 @@ namespace MiniZinc { } else { throw TypeError(_env,bop.loc(), std::string("type error in operator application for `")+ - bop.opToString().str()+"'. No matching operator found with left-hand side type `"+bop.lhs()->type().toString()+ - "' and right-hand side type `"+bop.rhs()->type().toString()+"'"); + bop.opToString().str()+"'. No matching operator found with left-hand side type `" + +bop.lhs()->type().toString(_env)+ + "' and right-hand side type `"+bop.rhs()->type().toString(_env)+"'"); } } /// Visit unary operator @@ -722,7 +863,7 @@ namespace MiniZinc { } else { throw TypeError(_env,uop.loc(), std::string("type error in operator application for `")+ - uop.opToString().str()+"'. No matching operator found with type `"+uop.e()->type().toString()+"'"); + uop.opToString().str()+"'. No matching operator found with type `"+uop.e()->type().toString(_env)+"'"); } } /// Visit call @@ -745,7 +886,7 @@ namespace MiniZinc { oss << "no function or predicate with this signature found: `"; oss << call.id() << "("; for (unsigned int i=0; itype().toString(); + oss << call.args()[i]->type().toString(_env); if (itype().isSubtypeOf(vd.ti()->type())) { _typeErrors.push_back(TypeError(_env,vd.e()->loc(), "initialisation value for `"+vd.id()->str().str()+"' has invalid type-inst: expected `"+ - vd.ti()->type().toString()+"', actual `"+vd.e()->type().toString()+"'")); + vd.ti()->type().toString(_env)+"', actual `"+vd.e()->type().toString(_env)+"'")); } else { vd.e(addCoercion(_env, _model, vd.e(), vd.ti()->type())()); } @@ -807,17 +948,17 @@ namespace MiniZinc { if (ri->type().cv()) tt.cv(true); if (ri->type() == Type::top()) { - if (foundTIId) { - throw TypeError(_env,ri->loc(), - "only one type-inst variable allowed in array index"); - } else { +// if (foundTIId) { +// throw TypeError(_env,ri->loc(), +// "only one type-inst variable allowed in array index"); +// } else { foundTIId = true; - } +// } } else if (ri->type() != Type::parint()) { assert(ri->isa()); throw TypeError(_env,ri->loc(), "invalid type in array index, expected `set of int', actual `"+ - ri->type().toString()+"'"); + ri->type().toString(_env)+"'"); } } tt.dim(foundTIId ? -1 : ti.ranges().size()); @@ -851,6 +992,7 @@ namespace MiniZinc { "type-inst must be int or float"); } tt.bt(ti.domain()->type().bt()); + tt.enumId(ti.domain()->type().enumId()); } else { // assert(ti.domain()==NULL || ti.domain()->isa()); } @@ -878,7 +1020,7 @@ namespace MiniZinc { TSV0(EnvI& env0, TopoSorter& ts0, Model* model0, std::vector& fis0, std::vector& ais0) : env(env0), ts(ts0), model(model0), hadSolveItem(false), fis(fis0), ais(ais0) {} void vAssignI(AssignI* i) { ais.push_back(i); } - void vVarDeclI(VarDeclI* i) { ts.add(env, i->e(), true); } + void vVarDeclI(VarDeclI* i) { ts.add(env, i, true); } void vFunctionI(FunctionI* i) { model->registerFn(env, i); fis.push_back(i); @@ -1014,7 +1156,7 @@ namespace MiniZinc { if (!i->e()->type().isSubtypeOf(i->decl()->ti()->type())) { _typeErrors.push_back(TypeError(env, i->e()->loc(), "assignment value for `"+i->decl()->id()->str().str()+"' has invalid type-inst: expected `"+ - i->decl()->ti()->type().toString()+"', actual `"+i->e()->type().toString()+"'")); + i->decl()->ti()->type().toString(env)+"', actual `"+i->e()->type().toString(env)+"'")); // Assign to "true" constant to avoid generating further errors that the parameter // is undefined i->decl()->e(constants().lit_true); @@ -1023,13 +1165,14 @@ namespace MiniZinc { void vConstraintI(ConstraintI* i) { bu_ty.run(i->e()); if (!i->e()->type().isSubtypeOf(Type::varbool())) - throw TypeError(env, i->e()->loc(), "invalid type of constraint, expected `"+Type::varbool().toString()+"', actual `"+i->e()->type().toString()+"'"); + throw TypeError(env, i->e()->loc(), "invalid type of constraint, expected `" + +Type::varbool().toString(env)+"', actual `"+i->e()->type().toString(env)+"'"); } void vSolveI(SolveI* i) { for (ExpressionSetIter it = i->ann().begin(); it != i->ann().end(); ++it) { bu_ty.run(*it); if (!(*it)->type().isann()) - throw TypeError(env, (*it)->loc(), "expected annotation, got `"+(*it)->type().toString()+"'"); + throw TypeError(env, (*it)->loc(), "expected annotation, got `"+(*it)->type().toString(env)+"'"); } bu_ty.run(i->e()); if (i->e()) { @@ -1037,25 +1180,27 @@ namespace MiniZinc { if (! (et.isSubtypeOf(Type::varint()) || et.isSubtypeOf(Type::varfloat()))) throw TypeError(env, i->e()->loc(), - "objective has invalid type, expected int or float, actual `"+et.toString()+"'"); + "objective has invalid type, expected int or float, actual `"+et.toString(env)+"'"); } } void vOutputI(OutputI* i) { bu_ty.run(i->e()); if (i->e()->type() != Type::parstring(1) && i->e()->type() != Type::bot(1)) - throw TypeError(env, i->e()->loc(), "invalid type in output item, expected `"+Type::parstring(1).toString()+"', actual `"+i->e()->type().toString()+"'"); + throw TypeError(env, i->e()->loc(), "invalid type in output item, expected `" + +Type::parstring(1).toString(env)+"', actual `"+i->e()->type().toString(env)+"'"); } void vFunctionI(FunctionI* i) { for (ExpressionSetIter it = i->ann().begin(); it != i->ann().end(); ++it) { bu_ty.run(*it); if (!(*it)->type().isann()) - throw TypeError(env, (*it)->loc(), "expected annotation, got `"+(*it)->type().toString()+"'"); + throw TypeError(env, (*it)->loc(), "expected annotation, got `"+(*it)->type().toString(env)+"'"); } bu_ty.run(i->ti()); bu_ty.run(i->e()); if (i->e() && !i->e()->type().isSubtypeOf(i->ti()->type())) - throw TypeError(env, i->e()->loc(), "return type of function does not match body, declared type is `"+i->ti()->type().toString()+ - "', body type is `"+i->e()->type().toString()+"'"); + throw TypeError(env, i->e()->loc(), "return type of function does not match body, declared type is `" + +i->ti()->type().toString(env)+ + "', body type is `"+i->e()->type().toString(env)+"'"); if (i->e()) i->e(addCoercion(env, m, i->e(), i->ti()->type())()); } @@ -1114,7 +1259,7 @@ namespace MiniZinc { if (!ai->e()->type().isSubtypeOf(ai->decl()->ti()->type())) { throw TypeError(env.envi(), ai->e()->loc(), "assignment value for `"+ai->decl()->id()->str().str()+"' has invalid type-inst: expected `"+ - ai->decl()->ti()->type().toString()+"', actual `"+ai->e()->type().toString()+"'"); + ai->decl()->ti()->type().toString(env.envi())+"', actual `"+ai->e()->type().toString(env.envi())+"'"); } } diff --git a/share/minizinc/std/builtins.mzn b/share/minizinc/std/builtins.mzn index e589396a8..a48524b71 100644 --- a/share/minizinc/std/builtins.mzn +++ b/share/minizinc/std/builtins.mzn @@ -1978,6 +1978,7 @@ predicate redundant_constraint(var bool: b); /** @group builtins.special Mark \a b as an implied constraint (synonym for redundant_constraint) */ predicate implied_constraint(var bool: b) = redundant_constraint(b); +function set of int: anon_enum(int: n) = 1..n; %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% From 158066396334aadfcde078b1a39564e401b10ab1 Mon Sep 17 00:00:00 2001 From: Guido Tack Date: Tue, 8 Mar 2016 08:35:49 +1100 Subject: [PATCH 03/15] Process enums also in auto-generated output items --- lib/flatten.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/flatten.cpp b/lib/flatten.cpp index 9d2fca1e7..0e634a04a 100644 --- a/lib/flatten.cpp +++ b/lib/flatten.cpp @@ -5540,6 +5540,7 @@ namespace MiniZinc { OutputI* newOutputItem = new OutputI(Location().introduce(),new ArrayLit(Location().introduce(),outputVars)); e.orig->addItem(newOutputItem); outputItem = copy(e,e.cmap, newOutputItem)->cast(); + makePar(e,outputItem->e()); e.output->addItem(outputItem); } From cd99bd6bb7b032c4bd4e168a9b18cfb4e412a055 Mon Sep 17 00:00:00 2001 From: Guido Tack Date: Wed, 9 Mar 2016 09:30:57 +1100 Subject: [PATCH 04/15] Handle enums in assign items --- include/minizinc/typecheck.hh | 2 +- lib/typecheck.cpp | 165 ++++++++++++++++++++++------------ 2 files changed, 107 insertions(+), 60 deletions(-) diff --git a/include/minizinc/typecheck.hh b/include/minizinc/typecheck.hh index e42b712d8..fe9225efd 100644 --- a/include/minizinc/typecheck.hh +++ b/include/minizinc/typecheck.hh @@ -39,7 +39,7 @@ namespace MiniZinc { /// Add a variable declaration void add(EnvI& env, VarDecl* vd, bool unique); /// Add a variable declaration item - void add(EnvI& env, VarDeclI* vd, bool unique); + void add(EnvI& env, VarDeclI* vd, bool unique, bool handleEnums, std::vector& enumItems); /// Remove a variable declaration void remove(EnvI& env, VarDecl* vd); /// Get variable declaration from identifier \a id diff --git a/lib/typecheck.cpp b/lib/typecheck.cpp index abb2a5e47..a7d6877f3 100644 --- a/lib/typecheck.cpp +++ b/lib/typecheck.cpp @@ -54,33 +54,64 @@ namespace MiniZinc { } }; - void createEnumMapper(EnvI& env, Model* m, unsigned int enumId, Id* ident, SetLit* sl) { + AssignI* createEnumMapper(EnvI& env, Model* m, unsigned int enumId, VarDecl* vd, VarDecl* vd_enumToString, std::vector& enumItems) { + + Id* ident = vd->id(); + SetLit* sl = NULL; + + AssignI* ret = NULL; + GCLock lock; + if (Call* c = vd->e()->dyn_cast()) { + if (c->id()!="anon_enum") { + throw TypeError(env, vd->loc(), "invalid initialisation for enum"); + } + } else { + sl = vd->e()->cast(); + for (unsigned int i=0; iv().size(); i++) { + TypeInst* ti_id = new TypeInst(sl->v()[i]->loc(),Type::parenum(enumId)); + VarDecl* vd_id = new VarDecl(ti_id->loc(),ti_id,sl->v()[i]->cast()->str(),IntLit::a(i+1)); + enumItems.push_back(new VarDeclI(vd_id->loc(),vd_id)); + } + SetLit* nsl = new SetLit(vd->loc(), IntSetVal::a(1,sl->v().size())); + Type nslt = nsl->type(); + nslt.enumId(enumId); + nsl->type(nslt); + vd->e(nsl); + } + + if (sl) { - std::vector ranges(1); - ranges[0] = new TypeInst(Location().introduce(),Type::parint()); - TypeInst* ti = new TypeInst(Location().introduce(),Type::parstring(1)); - ti->setRanges(ranges); std::string name = "_enum_to_string_"+ident->str().str(); std::vector al_args(sl->v().size()); for (unsigned int i=0; iv().size(); i++) { al_args[i] = new StringLit(Location().introduce(),sl->v()[i]->cast()->str()); } ArrayLit* al = new ArrayLit(Location().introduce(),al_args); - VarDecl* vd = new VarDecl(Location().introduce(),ti,name,al); - m->addItem(new VarDeclI(Location().introduce(),vd)); + + if (vd_enumToString) { + ret = new AssignI(Location().introduce(),name,al); + ret->decl(vd_enumToString); + } else { + std::vector ranges(1); + ranges[0] = new TypeInst(Location().introduce(),Type::parint()); + TypeInst* ti = new TypeInst(Location().introduce(),Type::parstring(1)); + ti->setRanges(ranges); + vd_enumToString = new VarDecl(Location().introduce(),ti,name,al); + enumItems.push_back(new VarDeclI(Location().introduce(),vd_enumToString)); + } TypeInst* ti_aa = new TypeInst(Location().introduce(),Type::parint()); VarDecl* vd_aa = new VarDecl(Location().introduce(),ti_aa,"x"); vd_aa->toplevel(false); std::vector aa_args(1); aa_args[0] = vd_aa->id(); - ArrayAccess* aa = new ArrayAccess(Location().introduce(),vd->id(),aa_args); + ArrayAccess* aa = new ArrayAccess(Location().introduce(),vd_enumToString->id(),aa_args); TypeInst* ti_fi = new TypeInst(Location().introduce(),Type::parstring()); std::vector fi_params(1); fi_params[0] = vd_aa; FunctionI* fi = new FunctionI(Location().introduce(),"_toString_"+ident->str().str(),ti_fi,fi_params,aa); - m->addItem(fi); + enumItems.push_back(fi); } else { TypeInst* ti_aa = new TypeInst(Location().introduce(),Type::parint()); VarDecl* vd_aa = new VarDecl(Location().introduce(),ti_aa,"x"); @@ -96,7 +127,7 @@ namespace MiniZinc { std::vector fi_params(1); fi_params[0] = vd_aa; FunctionI* fi = new FunctionI(Location().introduce(),"_toString_"+ident->str().str(),ti_fi,fi_params,construct_string); - m->addItem(fi); + enumItems.push_back(fi); } /* @@ -119,7 +150,7 @@ namespace MiniZinc { VarDecl* vd_x = new VarDecl(Location().introduce(),x_ti,"x"); vd_x->toplevel(false); - TypeInst* xx_range = new TypeInst(Location().introduce(),Type::parint(),NULL); + TypeInst* xx_range = new TypeInst(Location().introduce(),argType,NULL); std::vector xx_ranges(1); xx_ranges[0] = xx_range; TypeInst* xx_ti = new TypeInst(Location().introduce(),argType,xx_ranges); @@ -167,43 +198,34 @@ namespace MiniZinc { std::vector fi_params(1); fi_params[0] = vd_x; FunctionI* fi = new FunctionI(Location().introduce(),"_toString_"+ident->str().str(),ti_fi,fi_params,let); - m->addItem(fi); + enumItems.push_back(fi); + + return ret; } void - TopoSorter::add(EnvI& env, VarDeclI* vdi, bool unique) { + TopoSorter::add(EnvI& env, VarDeclI* vdi, bool unique, bool handleEnums, std::vector& enumItems) { VarDecl* vd = vdi->e(); - if (vd->ti()->isEnum() && vd->e()) { + if (handleEnums && vd->ti()->isEnum()) { unsigned int enumId = env.registerEnum(vdi); + Type vdt = vd->type(); + vdt.enumId(enumId); + vd->ti()->type(vdt); + vd->type(vdt); - GCLock lock; - if (Call* c = vd->e()->dyn_cast()) { - if (c->id()!="anon_enum") { - throw TypeError(env, vd->loc(), "invalid initialisation for enum"); - } - Type vdt = vd->type(); - vdt.enumId(enumId); - vd->ti()->type(vdt); - vd->type(vdt); - createEnumMapper(env, model, enumId, vd->id(), NULL); + if (vd->e()) { + (void) createEnumMapper(env, model, enumId, vd, NULL, enumItems); } else { - SetLit* sl = vd->e()->cast(); - for (unsigned int i=0; iv().size(); i++) { - TypeInst* ti_id = new TypeInst(sl->v()[i]->loc(),Type::parenum(enumId)); - VarDecl* vd_id = new VarDecl(ti_id->loc(),ti_id,sl->v()[i]->cast()->str(),IntLit::a(i+1)); - model->addItem(new VarDeclI(vd_id->loc(),vd_id)); - } - SetLit* nsl = new SetLit(vd->loc(), IntSetVal::a(1,sl->v().size())); - Type nslt = nsl->type(); - nslt.enumId(enumId); - nsl->type(nslt); - Type vdt = vd->type(); - vdt.enumId(enumId); - vd->ti()->type(vdt); - vd->type(vdt); - createEnumMapper(env, model, enumId, vd->id(), sl); - vd->e(nsl); + GCLock lock; + std::string name = "_enum_to_string_"+vd->id()->str().str(); + std::vector ranges(1); + ranges[0] = new TypeInst(Location().introduce(),Type::parint()); + TypeInst* ti = new TypeInst(Location().introduce(),Type::parstring(1)); + ti->setRanges(ranges); + VarDecl* vd_enumToString = new VarDecl(Location().introduce(),ti,name,NULL); + enumItems.push_back(new VarDeclI(Location().introduce(),vd_enumToString)); } + } DeclMap::iterator vd_id = idmap.find(vd->id()); if (vd_id == idmap.end()) { @@ -740,6 +762,7 @@ namespace MiniZinc { bool needIntLit = false; if (ty_in.dim()==0) { ty_id = Type::parint(); + ty_id.enumId(ty_in.enumId()); needIntLit = true; } else { ty_id = ty_in; @@ -1008,6 +1031,7 @@ namespace MiniZinc { std::vector functionItems; std::vector assignItems; + std::vector enumItems; class TSV0 : public ItemVisitor { public: @@ -1017,10 +1041,12 @@ namespace MiniZinc { bool hadSolveItem; std::vector& fis; std::vector& ais; - TSV0(EnvI& env0, TopoSorter& ts0, Model* model0, std::vector& fis0, std::vector& ais0) - : env(env0), ts(ts0), model(model0), hadSolveItem(false), fis(fis0), ais(ais0) {} + std::vector& enumis; + TSV0(EnvI& env0, TopoSorter& ts0, Model* model0, std::vector& fis0, std::vector& ais0, + std::vector& enumis0) + : env(env0), ts(ts0), model(model0), hadSolveItem(false), fis(fis0), ais(ais0), enumis(enumis0) {} void vAssignI(AssignI* i) { ais.push_back(i); } - void vVarDeclI(VarDeclI* i) { ts.add(env, i, true); } + void vVarDeclI(VarDeclI* i) { ts.add(env, i, true, true, enumis); } void vFunctionI(FunctionI* i) { model->registerFn(env, i); fis.push_back(i); @@ -1030,35 +1056,56 @@ namespace MiniZinc { throw TypeError(env,si->loc(),"Only one solve item allowed"); hadSolveItem = true; } - } _tsv0(env.envi(),ts,m,functionItems,assignItems); + } _tsv0(env.envi(),ts,m,functionItems,assignItems,enumItems); iterItems(_tsv0,m); + for (unsigned int i=0; idyn_cast()) { + assignItems.push_back(ai); + } else if (VarDeclI* vdi = enumItems[i]->dyn_cast()) { + m->addItem(vdi); + ts.add(env.envi(), vdi, true, false, enumItems); + } else { + FunctionI* fi = enumItems[i]->dyn_cast(); + m->addItem(fi); + m->registerFn(env.envi(),fi); + functionItems.push_back(fi); + } + } + enumItems.clear(); + for (unsigned int i=0; iid(),ai->loc()); if (vd->e()) throw TypeError(env.envi(),ai->loc(),"multiple assignment to the same variable"); + vd->e(ai->e()); if (vd->ti()->isEnum()) { - if (SetLit* sl = ai->e()->dyn_cast()) { - GCLock lock; - for (unsigned int i=0; iv().size(); i++) { - TypeInst* ti_id = new TypeInst(sl->v()[i]->loc(),Type::parint()); - VarDecl* vd_id = new VarDecl(ti_id->loc(),ti_id,sl->v()[i]->cast()->str(),IntLit::a(i+1)); - m->addItem(new VarDeclI(vd_id->loc(),vd_id)); - ts.add(env.envi(),vd_id,true); - } - SetLit* nsl = new SetLit(vd->loc(), IntSetVal::a(1,sl->v().size())); - vd->e(nsl); - } else { - throw TypeError(env.envi(),ai->loc(),"invalid assignment to enum"); - } - } else { - vd->e(ai->e()); + GCLock lock; + ASTString name("_enum_to_string_"+vd->id()->str().str()); + VarDecl* vd_enum = ts.get(env.envi(),name,vd->loc()); + if (vd_enum->e()) + throw TypeError(env.envi(),ai->loc(),"multiple assignment to the same variable"); + AssignI* ai_enum = createEnumMapper(env.envi(), m, vd->ti()->type().enumId(), vd, vd_enum, enumItems); + vd_enum->e(ai_enum->e()); + ai_enum->remove(); } ai->remove(); } + for (unsigned int i=0; idyn_cast()) { + m->addItem(vdi); + ts.add(env.envi(), vdi, true, false, enumItems); + } else { + FunctionI* fi = enumItems[i]->cast(); + m->addItem(fi); + m->registerFn(env.envi(),fi); + functionItems.push_back(fi); + } + } + class TSV1 : public ItemVisitor { public: EnvI& env; From 427449469bedd3b68a276b2894d96cbe92aa85b5 Mon Sep 17 00:00:00 2001 From: Guido Tack Date: Wed, 9 Mar 2016 09:46:04 +1100 Subject: [PATCH 05/15] Add output function for sets of enums --- lib/typecheck.cpp | 179 ++++++++++++++++++++++++++++++---------------- 1 file changed, 116 insertions(+), 63 deletions(-) diff --git a/lib/typecheck.cpp b/lib/typecheck.cpp index a7d6877f3..e4313f30c 100644 --- a/lib/typecheck.cpp +++ b/lib/typecheck.cpp @@ -130,75 +130,128 @@ namespace MiniZinc { enumItems.push_back(fi); } - /* - - function _toString_ENUM(array[$U] of ENUM: x) = - let { - array[int] of ENUM: xx = array1d(x) - } in "[" ++ join(", ", [ _toString_ENUM(xx[i]) | i in index_set(xx) ]) ++ "]"; - - */ + { + /* + + function _toString_ENUM(array[$U] of ENUM: x) = + let { + array[int] of ENUM: xx = array1d(x) + } in "[" ++ join(", ", [ _toString_ENUM(xx[i]) | i in index_set(xx) ]) ++ "]"; + + */ - Type argType = Type::parenum(ident->type().enumId()); + Type argType = Type::parenum(ident->type().enumId()); - TIId* tiid = new TIId(Location().introduce(),"U"); - TypeInst* ti_range = new TypeInst(Location().introduce(),argType,tiid); - std::vector ranges(1); - ranges[0] = ti_range; + TIId* tiid = new TIId(Location().introduce(),"U"); + TypeInst* ti_range = new TypeInst(Location().introduce(),argType,tiid); + std::vector ranges(1); + ranges[0] = ti_range; - TypeInst* x_ti = new TypeInst(Location().introduce(),Type::parint(-1),ranges,ident); - VarDecl* vd_x = new VarDecl(Location().introduce(),x_ti,"x"); - vd_x->toplevel(false); + TypeInst* x_ti = new TypeInst(Location().introduce(),Type::parint(-1),ranges,ident); + VarDecl* vd_x = new VarDecl(Location().introduce(),x_ti,"x"); + vd_x->toplevel(false); - TypeInst* xx_range = new TypeInst(Location().introduce(),argType,NULL); - std::vector xx_ranges(1); - xx_ranges[0] = xx_range; - TypeInst* xx_ti = new TypeInst(Location().introduce(),argType,xx_ranges); - - std::vector array1dArgs(1); - array1dArgs[0] = vd_x->id(); - Call* array1dCall = new Call(Location().introduce(),"array1d",array1dArgs); - - VarDecl* vd_xx = new VarDecl(Location().introduce(),xx_ti,"xx",array1dCall); - vd_xx->toplevel(false); + TypeInst* xx_range = new TypeInst(Location().introduce(),argType,NULL); + std::vector xx_ranges(1); + xx_ranges[0] = xx_range; + TypeInst* xx_ti = new TypeInst(Location().introduce(),argType,xx_ranges); + + std::vector array1dArgs(1); + array1dArgs[0] = vd_x->id(); + Call* array1dCall = new Call(Location().introduce(),"array1d",array1dArgs); + + VarDecl* vd_xx = new VarDecl(Location().introduce(),xx_ti,"xx",array1dCall); + vd_xx->toplevel(false); - TypeInst* idx_i_ti = new TypeInst(Location().introduce(),Type::parint()); - VarDecl* idx_i = new VarDecl(Location().introduce(),idx_i_ti,"i"); - idx_i->toplevel(false); - - std::vector aa_xxi_idx(1); - aa_xxi_idx[0] = idx_i->id(); - ArrayAccess* aa_xxi = new ArrayAccess(Location().introduce(),vd_xx->id(),aa_xxi_idx); - - std::vector _toString_ENUMArgs(1); - _toString_ENUMArgs[0] = aa_xxi; - Call* _toString_ENUM = new Call(Location().introduce(),"_toString_"+ident->str().str(),_toString_ENUMArgs); - - std::vector index_set_xx_args(1); - index_set_xx_args[0] = vd_xx->id(); - Call* index_set_xx = new Call(Location().introduce(),"index_set",index_set_xx_args); - std::vector gen_exps(1); - gen_exps[0] = idx_i; - Generator gen(gen_exps,index_set_xx); - - Generators generators; - generators._g.push_back(gen); - Comprehension* comp = new Comprehension(Location().introduce(),_toString_ENUM,generators,false); - - std::vector join_args(2); - join_args[0] = new StringLit(Location().introduce(),", "); - join_args[1] = comp; - Call* join = new Call(Location().introduce(),"join",join_args); - - std::vector let_args(1); - let_args[0] = vd_xx; - Let* let = new Let(Location().introduce(),let_args,join); + TypeInst* idx_i_ti = new TypeInst(Location().introduce(),Type::parint()); + VarDecl* idx_i = new VarDecl(Location().introduce(),idx_i_ti,"i"); + idx_i->toplevel(false); + + std::vector aa_xxi_idx(1); + aa_xxi_idx[0] = idx_i->id(); + ArrayAccess* aa_xxi = new ArrayAccess(Location().introduce(),vd_xx->id(),aa_xxi_idx); + + std::vector _toString_ENUMArgs(1); + _toString_ENUMArgs[0] = aa_xxi; + Call* _toString_ENUM = new Call(Location().introduce(),"_toString_"+ident->str().str(),_toString_ENUMArgs); + + std::vector index_set_xx_args(1); + index_set_xx_args[0] = vd_xx->id(); + Call* index_set_xx = new Call(Location().introduce(),"index_set",index_set_xx_args); + std::vector gen_exps(1); + gen_exps[0] = idx_i; + Generator gen(gen_exps,index_set_xx); + + Generators generators; + generators._g.push_back(gen); + Comprehension* comp = new Comprehension(Location().introduce(),_toString_ENUM,generators,false); + + std::vector join_args(2); + join_args[0] = new StringLit(Location().introduce(),", "); + join_args[1] = comp; + Call* join = new Call(Location().introduce(),"join",join_args); + + StringLit* sl_open = new StringLit(Location().introduce(),"["); + BinOp* bopp0 = new BinOp(Location().introduce(),sl_open,BOT_PLUSPLUS,join); + StringLit* sl_close = new StringLit(Location().introduce(),"]"); + BinOp* bopp1 = new BinOp(Location().introduce(),bopp0,BOT_PLUSPLUS,sl_close); + + std::vector let_args(1); + let_args[0] = vd_xx; + Let* let = new Let(Location().introduce(),let_args,bopp1); + + TypeInst* ti_fi = new TypeInst(Location().introduce(),Type::parstring()); + std::vector fi_params(1); + fi_params[0] = vd_x; + FunctionI* fi = new FunctionI(Location().introduce(),"_toString_"+ident->str().str(),ti_fi,fi_params,let); + enumItems.push_back(fi); + } - TypeInst* ti_fi = new TypeInst(Location().introduce(),Type::parstring()); - std::vector fi_params(1); - fi_params[0] = vd_x; - FunctionI* fi = new FunctionI(Location().introduce(),"_toString_"+ident->str().str(),ti_fi,fi_params,let); - enumItems.push_back(fi); + { + /* + + function _toString_ENUM(set of ENUM: x) = + "{" ++ join(", ", [ _toString_ENUM(i) | i in x ]) ++ "}"; + + */ + + Type argType = Type::parsetenum(ident->type().enumId()); + TypeInst* x_ti = new TypeInst(Location().introduce(),argType,ident); + VarDecl* vd_x = new VarDecl(Location().introduce(),x_ti,"x"); + vd_x->toplevel(false); + + TypeInst* idx_i_ti = new TypeInst(Location().introduce(),Type::parint()); + VarDecl* idx_i = new VarDecl(Location().introduce(),idx_i_ti,"i"); + idx_i->toplevel(false); + + std::vector _toString_ENUMArgs(1); + _toString_ENUMArgs[0] = idx_i->id(); + Call* _toString_ENUM = new Call(Location().introduce(),"_toString_"+ident->str().str(),_toString_ENUMArgs); + + std::vector gen_exps(1); + gen_exps[0] = idx_i; + Generator gen(gen_exps,vd_x->id()); + + Generators generators; + generators._g.push_back(gen); + Comprehension* comp = new Comprehension(Location().introduce(),_toString_ENUM,generators,false); + + std::vector join_args(2); + join_args[0] = new StringLit(Location().introduce(),", "); + join_args[1] = comp; + Call* join = new Call(Location().introduce(),"join",join_args); + + StringLit* sl_open = new StringLit(Location().introduce(),"{"); + BinOp* bopp0 = new BinOp(Location().introduce(),sl_open,BOT_PLUSPLUS,join); + StringLit* sl_close = new StringLit(Location().introduce(),"}"); + BinOp* bopp1 = new BinOp(Location().introduce(),bopp0,BOT_PLUSPLUS,sl_close); + + TypeInst* ti_fi = new TypeInst(Location().introduce(),Type::parstring()); + std::vector fi_params(1); + fi_params[0] = vd_x; + FunctionI* fi = new FunctionI(Location().introduce(),"_toString_"+ident->str().str(),ti_fi,fi_params,bopp1); + enumItems.push_back(fi); + } return ret; } From fdc338787fe544d03c92b84243d21ca57a1e265f Mon Sep 17 00:00:00 2001 From: Guido Tack Date: Sat, 12 Mar 2016 12:41:30 +1100 Subject: [PATCH 06/15] Enable use of anon_enum in data files --- lib/typecheck.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/typecheck.cpp b/lib/typecheck.cpp index e4313f30c..f67cf6503 100644 --- a/lib/typecheck.cpp +++ b/lib/typecheck.cpp @@ -113,6 +113,11 @@ namespace MiniZinc { FunctionI* fi = new FunctionI(Location().introduce(),"_toString_"+ident->str().str(),ti_fi,fi_params,aa); enumItems.push_back(fi); } else { + if (vd_enumToString) { + /// TODO: find a better solution (don't introduce the vd_enumToString until we + /// know it's a non-anonymous enum) + vd_enumToString->e(new ArrayLit(Location().introduce(), std::vector())); + } TypeInst* ti_aa = new TypeInst(Location().introduce(),Type::parint()); VarDecl* vd_aa = new VarDecl(Location().introduce(),ti_aa,"x"); vd_aa->toplevel(false); @@ -1141,8 +1146,10 @@ namespace MiniZinc { if (vd_enum->e()) throw TypeError(env.envi(),ai->loc(),"multiple assignment to the same variable"); AssignI* ai_enum = createEnumMapper(env.envi(), m, vd->ti()->type().enumId(), vd, vd_enum, enumItems); - vd_enum->e(ai_enum->e()); - ai_enum->remove(); + if (ai_enum) { + vd_enum->e(ai_enum->e()); + ai_enum->remove(); + } } ai->remove(); } From 0368f23cea6f150904744fbcecddbbd200d8de61 Mon Sep 17 00:00:00 2001 From: Guido Tack Date: Sat, 12 Mar 2016 13:28:18 +1100 Subject: [PATCH 07/15] Propagate enums through polymorphic functions --- lib/ast.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ast.cpp b/lib/ast.cpp index 38d2fda90..5bf70e6a4 100644 --- a/lib/ast.cpp +++ b/lib/ast.cpp @@ -731,6 +731,7 @@ namespace MiniZinc { if (it==tmap.end()) throw TypeError(env, fi->loc(),"type-inst variable $"+dh.str()+" used but not defined"); ret.bt(it->second.bt()); + ret.enumId(it->second.enumId()); if (ret.st()==Type::ST_PLAIN) ret.st(it->second.st()); } From 8114aaade4857c42b1518c64e06553545b437912 Mon Sep 17 00:00:00 2001 From: Guido Tack Date: Sat, 12 Mar 2016 17:50:32 +1100 Subject: [PATCH 08/15] Enum builtins --- include/minizinc/ast.hh | 2 ++ lib/builtins.cpp | 50 ++++++++++++++++++++++++++++++++- lib/lexer.lxx | 2 +- lib/typecheck.cpp | 22 +++++++++------ share/minizinc/std/builtins.mzn | 29 +++++++++++++++++++ 5 files changed, 95 insertions(+), 10 deletions(-) diff --git a/include/minizinc/ast.hh b/include/minizinc/ast.hh index 2a48d580b..a7eacb7be 100644 --- a/include/minizinc/ast.hh +++ b/include/minizinc/ast.hh @@ -458,6 +458,8 @@ namespace MiniZinc { 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); }; diff --git a/lib/builtins.cpp b/lib/builtins.cpp index dd71e7ff7..a7166c9a2 100644 --- a/lib/builtins.cpp +++ b/lib/builtins.cpp @@ -2018,6 +2018,37 @@ namespace MiniZinc { return std::tan(f); } + IntVal b_to_enum(EnvI& env, Call* call) { + ASTExprVec args = call->args(); + assert(args.size()==2); + IntSetVal* isv = eval_intset(env, args[0]); + IntVal v = eval_int(env, args[1]); + if (!isv->contains(v)) + throw ResultUndefinedError(env, call->loc(), "value outside of enum range"); + return v; + } + + IntVal b_enum_next(EnvI& env, Call* call) { + ASTExprVec args = call->args(); + IntVal v = eval_int(env, args[0]); + return v+1; + } + + IntVal b_enum_prev(EnvI& env, Call* call) { + ASTExprVec args = call->args(); + IntVal v = eval_int(env, args[0]); + return v-1; + } + + IntSetVal* b_enum_base_set(EnvI& env, Call* call) { + ASTExprVec args = call->args(); + if (args[0]->type().enumId() != 0) { + VarDeclI* enumDecl = env.getEnum(args[0]->type().enumId()); + return eval_intset(env, enumDecl->e()->e()); + } + return IntSetVal::a(-IntVal::infinity(),IntVal::infinity()); + } + void registerBuiltins(Env& e, Model* m) { EnvI& env = e.envi(); @@ -2677,7 +2708,24 @@ namespace MiniZinc { t[0] = Type::parint(); t[1] = Type::parfloat(); rb(env, m, ASTString("binomial"),t,b_binomial); - } + } + { + std::vector t(2); + t[0] = Type::parsetint(); + t[1] = Type::parint(); + rb(env, m, ASTString("to_enum"),t,b_to_enum); + } + { + std::vector t(1); + t[0] = Type::parint(); + rb(env, m, ASTString("enum_next"),t,b_enum_next); + rb(env, m, ASTString("enum_prev"),t,b_enum_prev); + } + { + std::vector t(1); + t[0] = Type::varint(); + rb(env, m, ASTString("enum_base_set"),t,b_enum_base_set); + } } } diff --git a/lib/lexer.lxx b/lib/lexer.lxx index 37cdb4128..bc0abf2e9 100644 --- a/lib/lexer.lxx +++ b/lib/lexer.lxx @@ -484,7 +484,7 @@ _[A-Za-z][A-Za-z0-9_]* { "\xE2\x88\xAA" { return MZN_UNION; } "\xE2\x88\xA9" { return MZN_INTERSECT; } -$[A-Za-z][A-Za-z0-9_]* { +$$?[A-Za-z][A-Za-z0-9_]* { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = strdup(yytext+1); return MZN_TI_IDENTIFIER; } diff --git a/lib/typecheck.cpp b/lib/typecheck.cpp index f67cf6503..9a4de8571 100644 --- a/lib/typecheck.cpp +++ b/lib/typecheck.cpp @@ -1046,14 +1046,20 @@ namespace MiniZinc { } if (ti.domain() && ti.domain()->type().cv()) tt.cv(true); - if (ti.domain() && !ti.domain()->isa()) { - if (ti.domain()->type().ti() != Type::TI_PAR || - ti.domain()->type().st() != Type::ST_SET) - throw TypeError(_env,ti.domain()->loc(), - "type-inst must be par set"); - if (ti.domain()->type().dim() != 0) - throw TypeError(_env,ti.domain()->loc(), - "type-inst cannot be an array"); + if (ti.domain()) { + if (TIId* tiid = ti.domain()->dyn_cast()) { + if (tiid->isEnum()) { + tt.bt(Type::BT_INT); + } + } else { + if (ti.domain()->type().ti() != Type::TI_PAR || + ti.domain()->type().st() != Type::ST_SET) + throw TypeError(_env,ti.domain()->loc(), + "type-inst must be par set"); + if (ti.domain()->type().dim() != 0) + throw TypeError(_env,ti.domain()->loc(), + "type-inst cannot be an array"); + } } if (tt.isunknown()) { assert(ti.domain()); diff --git a/share/minizinc/std/builtins.mzn b/share/minizinc/std/builtins.mzn index a48524b71..0d08d0ce4 100644 --- a/share/minizinc/std/builtins.mzn +++ b/share/minizinc/std/builtins.mzn @@ -1328,6 +1328,35 @@ function bool: trace_stdout(string: msg); /** @group builtins.debug Abort evaluation and print message \a msg. */ function bool: abort(string: msg); +/*** + @groupdef builtins.enum Functions for enums + +*/ + +/** @group builtins.enum Return set of values in enum of \a x */ +function set of $$E: enum_base_set(var $$E: x); + +/** @group builtins.enum Return next greater enum value of \a x */ +function $$E: enum_next($$E: x); +/** @group builtins.enum Return next greater enum value of \a x */ +function var $$E: enum_next(var $$E: x) = + let { constraint x < max(enum_base_set(x)) } in x+1; + +/** @group builtins.enum Return next smaller enum value of \a x */ +function $$E: enum_prev($$E: x); +/** @group builtins.enum Return next smaller enum value of \a x */ +function var $$E: enum_prev(var $$E: x) = + let { constraint x > min(enum_base_set(x)) } in x-1; + +/** @group builtins.enum Convert \a x to enum type \a X */ +function $$E: to_enum(set of $$E: X, int: x); +/** @group builtins.enum Convert \a x to enum type \a X */ +function var $$E: to_enum(set of $$E: X, var int: x) = + let { constraint x in X } in x; + + + + %-----------------------------------------------------------------------------% % % Internal compiler functions From bf4a9ab2a9d7329f78fa9f8e94be42c2486d0e8c Mon Sep 17 00:00:00 2001 From: Guido Tack Date: Sat, 12 Mar 2016 17:58:27 +1100 Subject: [PATCH 09/15] Better location for error message --- lib/typecheck.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/typecheck.cpp b/lib/typecheck.cpp index 9a4de8571..476300f2b 100644 --- a/lib/typecheck.cpp +++ b/lib/typecheck.cpp @@ -64,7 +64,7 @@ namespace MiniZinc { GCLock lock; if (Call* c = vd->e()->dyn_cast()) { if (c->id()!="anon_enum") { - throw TypeError(env, vd->loc(), "invalid initialisation for enum"); + throw TypeError(env, c->loc(), "invalid initialisation for enum"); } } else { sl = vd->e()->cast(); From 82b8c8ec50369ac8bff059c75e61efe6dfdd0617 Mon Sep 17 00:00:00 2001 From: Guido Tack Date: Sat, 12 Mar 2016 19:36:24 +1100 Subject: [PATCH 10/15] Revert change: need to go through all models to find output item --- lib/flatten.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/flatten.cpp b/lib/flatten.cpp index 0e634a04a..a53940e4d 100644 --- a/lib/flatten.cpp +++ b/lib/flatten.cpp @@ -5497,11 +5497,20 @@ namespace MiniZinc { OutputI* outputItem = NULL; GCLock lock; - if (e.orig->outputItem()) { - outputItem = copy(e,e.cmap, e.orig->outputItem())->cast(); - makePar(e,outputItem->e()); - e.output->addItem(outputItem); - } + class OV1 : public ItemVisitor { + public: + EnvI& env; + VarOccurrences& vo; + OutputI*& outputItem; + OV1(EnvI& env0, VarOccurrences& vo0, OutputI*& outputItem0) + : env(env0), vo(vo0), outputItem(outputItem0) {} + void vOutputI(OutputI* oi) { + outputItem = copy(env,env.cmap, oi)->cast(); + makePar(env,outputItem->e()); + env.output->addItem(outputItem); + } + } _ov1(e,e.output_vo,outputItem); + iterItems(_ov1,e.orig); if (outputItem==NULL) { // Create output item for all variables defined at toplevel in the MiniZinc source From 9fe5aba838f3f6568c42d9968f34f4de9d25a809 Mon Sep 17 00:00:00 2001 From: Guido Tack Date: Sat, 12 Mar 2016 20:02:39 +1100 Subject: [PATCH 11/15] Add syntax for arbitrary identifiers (in single quotes) --- lib/flatten.cpp | 17 ++++++++++++++++- lib/lexer.lxx | 3 +++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/flatten.cpp b/lib/flatten.cpp index a53940e4d..acbf2d2f9 100644 --- a/lib/flatten.cpp +++ b/lib/flatten.cpp @@ -4954,7 +4954,8 @@ namespace MiniZinc { VarDecl* it = v->flat(); if (it==NULL) { TypeInst* ti = eval_typeinst(env,v); - VarDecl* vd = newVarDecl(env, ctx, ti, v->id()->idn()==-1 && !v->toplevel() ? NULL : v->id(), v, NULL); + bool reuseVarId = v->type().isann() || ( v->toplevel() && v->id()->idn()==-1 && v->id()->v().c_str()[0]!='\'' ); + VarDecl* vd = newVarDecl(env, ctx, ti, reuseVarId ? v->id() : NULL, v, NULL); v->flat(vd); Ctx nctx; if (v->e() && v->e()->type().bt() == Type::BT_BOOL) @@ -5228,6 +5229,16 @@ namespace MiniZinc { topDown(_decls, e); } + void checkRenameVar(EnvI& e, VarDecl* vd) { + if (vd->id()->idn() != vd->flat()->id()->idn()) { + TypeInst* vd_rename_ti = copy(e,e.cmap,vd->ti())->cast(); + VarDecl* vd_rename = new VarDecl(Location().introduce(), vd_rename_ti, vd->flat()->id()->idn(), NULL); + vd_rename->flat(vd->flat()); + vd->e(vd_rename->id()); + e.output->addItem(new VarDeclI(Location().introduce(), vd_rename)); + } + } + void outputVarDecls(EnvI& env, Item* ci, Expression* e) { class O : public EVisitor { public: @@ -5314,6 +5325,7 @@ namespace MiniZinc { args[0] = al; reallyFlat->addAnnotation(new Call(Location().introduce(),constants().ann.output_array,args,NULL)); } + checkRenameVar(env, nvi->e()); } else { outputVarDecls(env, nvi, nvi->e()->e()); } @@ -5463,6 +5475,7 @@ namespace MiniZinc { args[0] = al; vd->flat()->addAnnotation(new Call(Location().introduce(),constants().ann.output_array,args,NULL)); } + checkRenameVar(e, vd); } } } @@ -5669,6 +5682,7 @@ namespace MiniZinc { assert(vd->flat()); if (vd->type().dim() == 0) { vd->flat()->addAnnotation(constants().ann.output_var); + checkRenameVar(env, vd); } else { bool needOutputAnn = true; if (reallyFlat->e() && reallyFlat->e()->isa()) { @@ -5699,6 +5713,7 @@ namespace MiniZinc { args.resize(1); args[0] = al; vd->flat()->addAnnotation(new Call(Location().introduce(),constants().ann.output_array,args,NULL)); + checkRenameVar(env, vd); } } } diff --git a/lib/lexer.lxx b/lib/lexer.lxx index bc0abf2e9..f98f412e5 100644 --- a/lib/lexer.lxx +++ b/lib/lexer.lxx @@ -455,6 +455,9 @@ _ { beginToken(yyget_extra(yyscanner), yylloc, yytext); [A-Za-z][A-Za-z0-9_]* { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = strdup(yytext); return MZN_IDENTIFIER; } +"'"[^\\'\xa\xd\x0]*"'" { + beginToken(yyget_extra(yyscanner), yylloc, yytext); + yylval->sValue = strdup(yytext); return MZN_IDENTIFIER; } _[A-Za-z][A-Za-z0-9_]* { beginToken(yyget_extra(yyscanner), yylloc, yytext); MiniZinc::ParserState* parm = From f1f06b60ed88acbbb23948bbc43eaed9749cac77 Mon Sep 17 00:00:00 2001 From: Guido Tack Date: Tue, 15 Mar 2016 20:31:04 +1100 Subject: [PATCH 12/15] Fix creation of enum helper names for enums with extended identifiers --- lib/flatten.cpp | 13 ++++++++++++- lib/typecheck.cpp | 40 +++++++++++++++++++++++++++++++--------- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/lib/flatten.cpp b/lib/flatten.cpp index acbf2d2f9..58b61e6b1 100644 --- a/lib/flatten.cpp +++ b/lib/flatten.cpp @@ -5207,6 +5207,17 @@ namespace MiniZinc { } _par; topDown(_par, e); class Decls : public EVisitor { + protected: + static std::string createEnumToStringName(Id* ident, std::string prefix) { + std::string name = ident->str().str(); + if (name[0]=='\'') { + name = "'"+prefix+name.substr(1); + } else { + name = prefix+name; + } + return name; + } + public: EnvI& env; Decls(EnvI& env0) : env(env0) {} @@ -5217,7 +5228,7 @@ namespace MiniZinc { GCLock lock; std::vector args(1); args[0] = c.args()[c.args().size()-1]; - std::string enumName = "_toString_"+ti_id->str().str(); + std::string enumName = createEnumToStringName(ti_id, "_toString_"); Call* convertEnum = new Call(Location().introduce(),enumName,args); convertEnum->type(Type::parstring()); c.args()[c.args().size()-1] = convertEnum; diff --git a/lib/typecheck.cpp b/lib/typecheck.cpp index 476300f2b..ac61cb201 100644 --- a/lib/typecheck.cpp +++ b/lib/typecheck.cpp @@ -54,6 +54,16 @@ namespace MiniZinc { } }; + std::string createEnumToStringName(Id* ident, std::string prefix) { + std::string name = ident->str().str(); + if (name[0]=='\'') { + name = "'"+prefix+name.substr(1); + } else { + name = prefix+name; + } + return name; + } + AssignI* createEnumMapper(EnvI& env, Model* m, unsigned int enumId, VarDecl* vd, VarDecl* vd_enumToString, std::vector& enumItems) { Id* ident = vd->id(); @@ -82,7 +92,7 @@ namespace MiniZinc { if (sl) { - std::string name = "_enum_to_string_"+ident->str().str(); + std::string name = createEnumToStringName(ident,"_enum_to_string_"); std::vector al_args(sl->v().size()); for (unsigned int i=0; iv().size(); i++) { al_args[i] = new StringLit(Location().introduce(),sl->v()[i]->cast()->str()); @@ -110,7 +120,9 @@ namespace MiniZinc { TypeInst* ti_fi = new TypeInst(Location().introduce(),Type::parstring()); std::vector fi_params(1); fi_params[0] = vd_aa; - FunctionI* fi = new FunctionI(Location().introduce(),"_toString_"+ident->str().str(),ti_fi,fi_params,aa); + FunctionI* fi = new FunctionI(Location().introduce(), + createEnumToStringName(ident, "_toString_"), + ti_fi,fi_params,aa); enumItems.push_back(fi); } else { if (vd_enumToString) { @@ -131,7 +143,9 @@ namespace MiniZinc { TypeInst* ti_fi = new TypeInst(Location().introduce(),Type::parstring()); std::vector fi_params(1); fi_params[0] = vd_aa; - FunctionI* fi = new FunctionI(Location().introduce(),"_toString_"+ident->str().str(),ti_fi,fi_params,construct_string); + FunctionI* fi = new FunctionI(Location().introduce(), + createEnumToStringName(ident, "_toString_"), + ti_fi,fi_params,construct_string); enumItems.push_back(fi); } @@ -178,7 +192,9 @@ namespace MiniZinc { std::vector _toString_ENUMArgs(1); _toString_ENUMArgs[0] = aa_xxi; - Call* _toString_ENUM = new Call(Location().introduce(),"_toString_"+ident->str().str(),_toString_ENUMArgs); + Call* _toString_ENUM = new Call(Location().introduce(), + createEnumToStringName(ident, "_toString_"), + _toString_ENUMArgs); std::vector index_set_xx_args(1); index_set_xx_args[0] = vd_xx->id(); @@ -208,7 +224,9 @@ namespace MiniZinc { TypeInst* ti_fi = new TypeInst(Location().introduce(),Type::parstring()); std::vector fi_params(1); fi_params[0] = vd_x; - FunctionI* fi = new FunctionI(Location().introduce(),"_toString_"+ident->str().str(),ti_fi,fi_params,let); + FunctionI* fi = new FunctionI(Location().introduce(), + createEnumToStringName(ident, "_toString_"), + ti_fi,fi_params,let); enumItems.push_back(fi); } @@ -231,7 +249,9 @@ namespace MiniZinc { std::vector _toString_ENUMArgs(1); _toString_ENUMArgs[0] = idx_i->id(); - Call* _toString_ENUM = new Call(Location().introduce(),"_toString_"+ident->str().str(),_toString_ENUMArgs); + Call* _toString_ENUM = new Call(Location().introduce(), + createEnumToStringName(ident, "_toString_"), + _toString_ENUMArgs); std::vector gen_exps(1); gen_exps[0] = idx_i; @@ -254,7 +274,9 @@ namespace MiniZinc { TypeInst* ti_fi = new TypeInst(Location().introduce(),Type::parstring()); std::vector fi_params(1); fi_params[0] = vd_x; - FunctionI* fi = new FunctionI(Location().introduce(),"_toString_"+ident->str().str(),ti_fi,fi_params,bopp1); + FunctionI* fi = new FunctionI(Location().introduce(), + createEnumToStringName(ident, "_toString_"), + ti_fi,fi_params,bopp1); enumItems.push_back(fi); } @@ -275,7 +297,7 @@ namespace MiniZinc { (void) createEnumMapper(env, model, enumId, vd, NULL, enumItems); } else { GCLock lock; - std::string name = "_enum_to_string_"+vd->id()->str().str(); + std::string name = createEnumToStringName(vd->id(),"_enum_to_string_"); std::vector ranges(1); ranges[0] = new TypeInst(Location().introduce(),Type::parint()); TypeInst* ti = new TypeInst(Location().introduce(),Type::parstring(1)); @@ -1147,7 +1169,7 @@ namespace MiniZinc { if (vd->ti()->isEnum()) { GCLock lock; - ASTString name("_enum_to_string_"+vd->id()->str().str()); + ASTString name(createEnumToStringName(vd->id(),"_enum_to_string_")); VarDecl* vd_enum = ts.get(env.envi(),name,vd->loc()); if (vd_enum->e()) throw TypeError(env.envi(),ai->loc(),"multiple assignment to the same variable"); From 426048227066f1342b819ceac48a3fb1f68ee783 Mon Sep 17 00:00:00 2001 From: Guido Tack Date: Tue, 15 Mar 2016 20:33:06 +1100 Subject: [PATCH 13/15] Patch version for this branch --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 123a0b606..f5bf40401 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,7 @@ set(HAS_GUROBI_OLD FALSE) # The version number. set (libminizinc_VERSION_MAJOR 2) set (libminizinc_VERSION_MINOR 0) -set (libminizinc_VERSION_PATCH 12) +set (libminizinc_VERSION_PATCH 13_enum) if (ADDITIONAL_DATE_STRING) set (libminizinc_VERSION_PATCH "${libminizinc_VERSION_PATCH}.${ADDITIONAL_DATE_STRING}") From e5c94d7b35cedae6cfd564af7d1c34c53eedcfcd Mon Sep 17 00:00:00 2001 From: Guido Tack Date: Mon, 4 Apr 2016 15:34:20 +1000 Subject: [PATCH 14/15] Always turn arrays of enums into 1d arrays before producing output (fixes the problem that the _toString_ function for an enum is only defined on 1d arrays) --- lib/flatten.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/flatten.cpp b/lib/flatten.cpp index 58b61e6b1..9a458373a 100644 --- a/lib/flatten.cpp +++ b/lib/flatten.cpp @@ -5228,6 +5228,13 @@ namespace MiniZinc { GCLock lock; std::vector args(1); args[0] = c.args()[c.args().size()-1]; + if (args[0]->type().dim() > 1) { + Call* array1d = new Call(Location().introduce(),ASTString("array1d"),args); + Type array1dt = args[0]->type(); + array1dt.dim(1); + array1d->type(array1dt); + args[0] = array1d; + } std::string enumName = createEnumToStringName(ti_id, "_toString_"); Call* convertEnum = new Call(Location().introduce(),enumName,args); convertEnum->type(Type::parstring()); From 0b082d37391ca778c01efde2786d0b1fb6f58c6d Mon Sep 17 00:00:00 2001 From: Guido Tack Date: Fri, 3 Jun 2016 17:36:22 +1000 Subject: [PATCH 15/15] Constrain result of function call based on function return type if necessary --- lib/flatten.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/lib/flatten.cpp b/lib/flatten.cpp index 54a6499f0..4c43931ba 100644 --- a/lib/flatten.cpp +++ b/lib/flatten.cpp @@ -4905,6 +4905,37 @@ namespace MiniZinc { } else { ret = flat_exp(env,ctx,decl->e(),r,NULL); args_ee.push_back(ret); + if (decl->ti()->domain() && !decl->ti()->domain()->isa()) { + BinOpType bot; + if (ret.r()->type().st() == Type::ST_SET) { + bot = BOT_SUBSET; + } else { + bot = BOT_IN; + } + + KeepAlive domconstraint; + if (decl->e()->type().dim() > 0) { + GCLock lock; + std::vector domargs(2); + domargs[0] = ret.r(); + domargs[1] = decl->ti()->domain(); + Call* c = new Call(Location().introduce(),"var_dom",domargs); + c->type(Type::varbool()); + c->decl(env.orig->matchFn(env,c)); + domconstraint = c; + } else { + GCLock lock; + domconstraint = new BinOp(Location().introduce(),ret.r(),bot,decl->ti()->domain()); + } + domconstraint()->type(ret.r()->type().ispar() ? Type::parbool() : Type::varbool()); + if (ctx.b == C_ROOT) { + (void) flat_exp(env, Ctx(), domconstraint(), constants().var_true, constants().var_true); + } else { + EE ee = flat_exp(env, Ctx(), domconstraint(), NULL, constants().var_true); + ee.b = ee.r; + args_ee.push_back(ee); + } + } } ret.b = conj(env,b,Ctx(),args_ee); }