• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

/Users/magix/mmx/mmxlight/src/overload.cpp

Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : overload.cpp
00004 * DESCRIPTION: Overloading routines
00005 * COPYRIGHT  : (C) 2006  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license and comes WITHOUT
00008 * ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
00009 * If you don't have this file, write to the Free Software Foundation, Inc.,
00010 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00011 ******************************************************************************/
00012 
00013 #include <mmxlight/environment.hpp>
00014 #include <basix/mmx_syntax.hpp>
00015 #include <basix/routine.hpp>
00016 #include <basix/tuple.hpp>
00017 #include <basix/alias.hpp>
00018 #include <basix/dynamic.hpp>
00019 #include <basix/glue.hpp>
00020 namespace mmx {
00021 
00022 /******************************************************************************
00023 * Exception routines
00024 ******************************************************************************/
00025 
00026 class exception_routine_rep: public routine_rep {
00027   generic ex_name;
00028 public:
00029   exception_routine_rep (): routine_rep (GEN_ERROR) {}
00030   exception_routine_rep (const generic& f):
00031     routine_rep (GEN_ERROR), ex_name (f) {}
00032   generic apply (const vector<generic>& v) const {
00033     vector<generic> t (generic (), N(v));
00034     for (nat i=0; i<N(v); i++)
00035       if (is<exception> (v[i])) return v[i];
00036     for (nat i=0; i<N(v); i++) 
00037       t[i]= type_name (v[i]);
00038     string msg= string ("invalid function application ")
00039       * flatten_as_mmx (gen (name, gen (ex_name, t)));
00040 #ifdef BASIX_ENABLE_EXCEPTIONS
00041     throw error_message (msg);
00042 #else
00043     assert (false);
00044 #endif
00045     return gen (name, gen (ex_name, v)); }
00046   vector<nat> signature () const { return vec<nat> (); }
00047 };
00048 
00049 routine
00050 exception_routine () {
00051   return new exception_routine_rep ();
00052 }
00053 
00054 routine
00055 exception_routine (const generic& f) {
00056   return new exception_routine_rep (f);
00057 }
00058 
00059 /******************************************************************************
00060 * Dynamic routines
00061 ******************************************************************************/
00062 
00063 class dynamic_routine_rep: public routine_rep {
00064   routine r;
00065 public:
00066   dynamic_routine_rep (const routine& r2):
00067     routine_rep (gen ("dynamic", r2->name)), r (r2) {}
00068   generic apply (const vector<generic>& v) const {
00069     vector<dynamic> a= fill<generic> (N(v));
00070     for (nat i=0; i<N(v); i++)
00071       if (is<dynamic> (v[i])) a[i]= as<dynamic> (v[i]);
00072       else a[i]= dynamic (v[i]);
00073     return as<generic> (dynamic (r, a)); }
00074   vector<nat> signature () const {
00075     return vec<nat> (type_information<dynamic>::id,
00076                      type_information<tuple<dynamic> >::id); }
00077 };
00078 
00079 routine
00080 dynamic_routine (const routine& r) {
00081   return new dynamic_routine_rep (r);
00082 }
00083 
00084 /******************************************************************************
00085 * Flatten out tuple arguments in one big tuple
00086 ******************************************************************************/
00087 
00088 vector<generic>
00089 equalize (const vector<generic>& args) {
00090   vector<generic> v= vec<generic> ();
00091   for (nat i=0; i<N(args); i++) {
00092     if (is_tuple_type (type (args[i]))) {
00093       vector<generic> w= compound_to_vector (*as<tuple<generic> > (args[i]));
00094       v << cdr (w);
00095     }
00096     else if (is<iterator<generic> > (args[i])) {
00097       iterator<generic> it= as<iterator<generic> > (args[i]);
00098       while (busy (it)) {
00099         generic next= *it; ++it;
00100         v << next;
00101         if (is<exception> (next)) return v;
00102       }
00103     }
00104     else v << args[i];
00105   }
00106   return v;
00107 }
00108 
00109 generic
00110 equalize (const generic& name, const vector<generic>& args) {
00111   vector<generic> v= equalize (args);
00112   if (N(v)>0 && is<exception> (v[N(v)-1])) return v[N(v)-1];
00113   return gen (name, v);
00114 }
00115 
00116 class equalize_grouped_routine_rep: public routine_rep {
00117   routine fun;
00118   vector<nat> sig;
00119 public:
00120   equalize_grouped_routine_rep (const routine& fun2, const vector<nat>& sig2):
00121     routine_rep (gen (GEN_EQUALIZE_GROUPED, fun2->name)),
00122     fun (fun2), sig (sig2) {}
00123   generic apply (const vector<generic>& args) const {
00124     vector<generic> v= equalize (args);
00125     if (N(v)>0 && is<exception> (v[N(v)-1])) return v[N(v)-1];
00126     else return fun->apply (v); }
00127   vector<nat> signature () const { return sig; }
00128 };
00129 
00130 routine
00131 equalize_grouped_routine (const routine& fun, const vector<nat>& sig) {
00132   return new equalize_grouped_routine_rep (fun, sig);
00133 }
00134 
00135 /******************************************************************************
00136 * Apply routines which operate on tuples
00137 ******************************************************************************/
00138 
00139 class via_tuple_routine_rep: public routine_rep {
00140   routine fun;
00141   vector<nat> sig;
00142   nat n;
00143 public:
00144   via_tuple_routine_rep (const routine& fun2, const vector<nat>& sig2, nat n2):
00145     routine_rep (gen (GEN_VIA_TUPLE, fun2->name)),
00146     fun (fun2), sig (sig2), n (n2) {}
00147   generic apply (const vector<generic>& v) const {
00148     vector<generic> w= range (v, 0, n-2);
00149     generic t= gen (GEN_TUPLE, range (v, n-2, N(v)));
00150     w << as<generic> (tuple<generic> (t));
00151     return fun->apply (w); }
00152   vector<nat> signature () const { return sig; }
00153 };
00154 
00155 routine
00156 via_tuple_routine (const routine& fun, const vector<nat>& sig, nat n) {
00157   return new via_tuple_routine_rep (fun, sig, n);
00158 }
00159 
00160 /******************************************************************************
00161 * Specialization of Alias Generic to Generic_alias T for some T
00162 ******************************************************************************/
00163 
00164 class specialize_alias_routine_rep: public routine_rep {
00165   routine fun;
00166   vector<nat> sig;
00167 public:
00168   specialize_alias_routine_rep (const routine& fun2, const vector<nat>& sig2):
00169     routine_rep (gen (GEN_SPECIALIZE_ALIAS, fun2->name)),
00170     fun (fun2), sig (sig2) {}
00171   generic apply (const vector<generic>& args) const {
00172     nat i, n= N(args);
00173     vector<generic> v= fill<generic> (n);
00174     for (i=0; i<n; i++)
00175       if (type (args[i]) == type_id<alias<generic> > ())
00176         v[i]= specialize_alias (args[i]);
00177       else v[i]= args[i];
00178     return fun->apply (v); }
00179   vector<nat> signature () const { return sig; }
00180 };
00181 
00182 routine
00183 specialize_alias_routine (const routine& fun, const vector<nat>& sig) {
00184   return new specialize_alias_routine_rep (fun, sig);
00185 }
00186 
00187 /******************************************************************************
00188 * Overloaded generic routines
00189 ******************************************************************************/
00190 
00191 static vector<nat>
00192 type (const vector<generic>& args) {
00193   nat i, n= N(args);
00194   vector<nat> r= fill<nat> ((nat) 0, n);
00195   for (i=0; i<n; i++)
00196     r[i]= type (args[i]);
00197   return r;
00198 }
00199 
00200 vector<generic>
00201 type_name (const vector<nat>& ids) {
00202   nat i, n= N(ids);
00203   vector<generic> r= fill<generic> (n);
00204   for (i=0; i<n; i++)
00205     r[i]= type_name (ids[i]);
00206   return r;
00207 }
00208 
00209 static nat
00210 conversion_penalty (const environment& env, nat id1, nat id2) {
00211   nat penalty;
00212   generic r= env->get_converter (id1, id2, penalty);
00213   //mmout << "  Convert " << id1 << ", " << id2 << " -> " << r << "\n";
00214   ASSERT (is<routine> (r), "routine expected (conversion_penalty)");
00215   return penalty;
00216 }
00217 
00218 static vector<nat>
00219 untuple (const vector<nat>& ids, nat total) {
00220   nat i, n= N(ids), tupid= tuple_to_scalar (ids[n-1]);
00221   vector<nat> r= fill<nat> ((nat) 0, total);
00222   for (i=0; i<n-1; i++)
00223     r[i]= ids[i];
00224   for (; i<total; i++)
00225     r[i]= tupid;
00226   return r;
00227 }
00228 
00229 static nat
00230 conversion_penalty (const environment& env,
00231                     const vector<nat>& ids1, const vector<nat>& ids2)
00232 {
00233   if (N(ids1) < N(ids2)-1) return PENALTY_INVALID;
00234   if (is_tuple_type (ids2[N(ids2)-1]))
00235     return conversion_penalty (env, ids1, untuple (ids2, N(ids1)));
00236   if (N(ids1) != N(ids2)) return PENALTY_INVALID;
00237   nat i, n= N(ids1), penalty= 0;
00238   for (i=1; i<n; i++)
00239     penalty= max (penalty, conversion_penalty (env, ids1[i], ids2[i]));
00240   return penalty;
00241 }
00242 
00243 static routine
00244 build (const environment& env, const routine& fun,
00245        const vector<nat>& ids1, const vector<nat>& ids2)
00246 {
00247   if (is_tuple_type (ids2[N(ids2)-1])) {
00248     vector<nat> ids3= untuple (ids2, N(ids1));
00249     routine vtfun= via_tuple_routine (fun, ids3, N(ids2));
00250     return build (env, vtfun, ids1, ids3);
00251   }
00252   nat i, n= N(ids1) - 1;
00253   vector<routine> v= fill<routine> (n);
00254   for (i=0; i<n; i++) {
00255     nat penalty;
00256     generic r= env->get_converter (ids1[i+1], ids2[i+1], penalty);
00257     ASSERT (is<routine> (r), "routine expected (build)");
00258     v[i]= as<routine> (r);
00259   }
00260   return compose (fun, v);
00261 }
00262 
00263 class overloaded_routine_rep: public routine_rep {
00264   vector<routine>    funs;
00265   environment        env;    // environment with applicable converters
00266   nat                serial; // time stamp for correctness of cache
00267   routine            nullary;
00268   table<routine,nat> unary;
00269   table<routine,nat> binary;
00270   table<routine,vector<nat> > n_ary;
00271   routine            fall_back;
00272   nat                status;
00273 
00274 public:
00275   overloaded_routine_rep (const generic& name, const environment& env2):
00276     routine_rep (name),
00277     env (env2),
00278     serial (env->serial),
00279     nullary (exception_routine (name)),
00280     fall_back (exception_routine (name)),
00281     status (0) {}
00282   overloaded_routine_rep (const generic& name,
00283                           const vector<routine>& funs2,
00284                           const environment& env2,
00285                           const nat& serial2,
00286                           const routine& nullary2,
00287                           const table<routine,nat>& unary2,
00288                           const table<routine,nat>& binary2,
00289                           const table<routine,vector<nat> >& n_ary2,
00290                           const routine& fall_back2,
00291                           const nat& status2):
00292     routine_rep (name), funs (funs2), env (env2), serial (serial2),
00293     nullary (nullary2), unary (unary2), binary (binary2),
00294     n_ary (n_ary2), fall_back (fall_back2), status (status2) {}
00295   void invalidate () const {
00296     overloaded_routine_rep* me=
00297       const_cast<overloaded_routine_rep*> (this);
00298     me->unary = table<routine,nat> ();
00299     me->binary= table<routine,nat> ();
00300     me->n_ary = table<routine,vector<nat> > ();
00301     me->serial= env->serial;
00302   }
00303   inline void up_to_date () const {
00304     if (!is_nil (env->next) && env->next_serial != env->next->serial)
00305       env->ensure_up_to_date ();
00306     if (serial != env->serial) invalidate ();
00307   }
00308   routine resolve (const vector<generic>& args) const {
00309     overloaded_routine_rep* me=
00310       const_cast<overloaded_routine_rep*> (this);
00311     routine best;
00312     const vector<nat> ids= cons<nat> (0, type (args));
00313     bool exc_args= false;
00314     bool grouped_args= false;
00315     bool genalias_args= false;
00316     for (nat i=1; i<N(ids); i++) {
00317       exc_args     = exc_args      || ids[i] == type_id<exception> ();
00318       grouped_args = grouped_args  || is_tuple_type (ids[i]);
00319       grouped_args = grouped_args  || ids[i] == type_id<iterator<generic> > ();
00320       genalias_args= genalias_args || ids[i] == type_id<alias<generic> > ();
00321     }
00322     if (exc_args) best= exception_routine (name);
00323     else if (grouped_args)
00324       best= equalize_grouped_routine (routine (me, true), ids);
00325     else if (genalias_args)
00326       best= specialize_alias_routine (routine (me, true), ids);
00327     else {
00328       vector<nat> best_ids;
00329       nat best_pen= PENALTY_INVALID;
00330       for (nat i=0; i<N(funs); i++) {
00331         vector<nat> fun_ids= funs[i]->signature ();
00332         nat pen= conversion_penalty (env, ids, fun_ids);
00333         //mmout << "Try " << name << ", " << type_name (fun_ids)
00334         //<< " on " << type_name (ids) << "\n";
00335         if (pen <= best_pen && pen < PENALTY_INVALID) {
00336           if (pen < best_pen ||
00337               conversion_penalty (env, fun_ids, best_ids) <
00338               conversion_penalty (env, best_ids, fun_ids))
00339             {
00340               //mmout << "  OK, and better (" << pen << ")\n";
00341               best= build (env, funs[i], ids, fun_ids);
00342               best_ids= fun_ids;
00343               best_pen= pen;
00344             }
00345           //else mmout << "  OK, but less good (" << pen << ")\n";
00346         }
00347       }
00348     }
00349     if (is_nil (best)) {
00350       bool dyn_flag= false;
00351       for (nat i=0; i<N(args); i++)
00352         if (is<dynamic> (args[i])) dyn_flag= true;
00353       if (dyn_flag) {
00354         // FIXME: routine no longer freed due to circular dependency
00355         best= dynamic_routine (routine (this, true));
00356       }
00357       else best= fall_back;
00358     }
00359     if (N(ids) == 2) me->unary [ids[1]]= best;
00360     else if (N(ids) == 3) me->binary [binary_id (ids[1], ids[2])]= best;
00361     if (N(ids) <= 7) me->n_ary [cdr (ids)]= best;
00362     return best;
00363   }
00364   generic apply () const {
00365     return nullary->apply ();
00366   }
00367   generic apply (const generic& x1) const {
00368     if (is<iterator<generic> > (x1)) {
00369       vector<generic> v;
00370       iterator<generic> it= as<iterator<generic> > (x1);
00371       while (busy (it)) {
00372         generic next= *it; ++it;
00373         v << next;
00374         if (is<exception> (next)) return next;
00375       }
00376       if (N(v) == 0) return apply ();
00377       else if (N(v) == 1) return apply (v[0]);
00378       else if (N(v) == 2) return apply (v[0], v[1]);
00379       else return apply (v);
00380     }
00381     up_to_date ();
00382     routine fun= unary[type (x1)];
00383     if (is_nil (fun)) fun= resolve (vec<generic> (x1));
00384     return fun->apply (x1);
00385   }
00386   generic apply (const generic& x1, const generic& x2) const {
00387     up_to_date ();
00388     nat id1= type (x1), id2= type (x2);
00389     routine fun= binary[binary_id (id1, id2)];
00390     if (is_nil (fun)) fun= resolve (vec<generic> (x1, x2));
00391     return fun->apply (x1, x2);
00392   }
00393   generic apply (const vector<generic>& v) const {
00394     up_to_date ();
00395     routine fun= n_ary[type (v)];
00396     if (is_nil (fun)) fun= resolve (v);
00397     return fun->apply (v);
00398   }
00399   vector<nat> signature () const { return vec<nat> (); }
00400   void overload (const routine& fun) const {
00401     if (fun->is_overloaded ()) {
00402       vector<routine> rs= fun->meanings ();
00403       for (nat i=0; i<N(rs); i++)
00404         overload (rs[i]);
00405       return;
00406     }
00407 
00408     overloaded_routine_rep* me=
00409       const_cast<overloaded_routine_rep*> (this);
00410     vector<nat> ids= fun->signature ();
00411     /*
00412     if (!using_simple () && exact_eq (fun->name, GEN_TIMES)) {
00413       mmout << fun << "\t: " << type_name (ids) << "\n";
00414       //mmout << "\t: " << env << "\n";
00415     }
00416     */
00417     if (N(ids) == 0) { me->fall_back= fun; me->status |= 1; }
00418     else if (N(ids) == 1) { me->nullary= fun; me->status |= 2; }
00419     else {
00420       nat i, n= N(funs);
00421       for (i=0; i<n; i++) {
00422         vector<nat> ids2= funs[i]->signature ();
00423         if (cdr (ids) == cdr (ids2)) {
00424           me->funs[i]= fun;
00425           break;
00426         }
00427       }
00428       if (i==n) me->funs << fun;
00429       if (N(ids) == 2 && is_tuple_type (ids[1]))
00430         if (exact_neq (fun->name, GEN_SQTUPLE) ||
00431             ids[1] == type_id<tuple<generic> > ())
00432           me->nullary= via_tuple_routine (fun, vec<nat> (ids[0]), 2);
00433     }
00434     me->invalidate ();
00435   }
00436   bool is_overloaded () const { return true; }
00437   vector<routine> meanings () const { return funs; }
00438   generic function_type () const {
00439     generic r= comma ();
00440     if (status & 1) r= comma (fall_back->function_type(), r);
00441     if (status & 2) r= comma (nullary->function_type(), r);
00442     for (nat i=0; i<N(funs); i++)
00443       r= comma (funs[i]->function_type(), r);
00444     return xsqtuple (r);
00445   }
00446   generic function_body () const {
00447     generic r= comma ();
00448     if (status & 1) r= comma (fall_back->function_body (), r);
00449     if (status & 2) r= comma (nullary->function_body (), r);
00450     for (nat i=0; i<N(funs); i++)
00451       r= comma (funs[i]->function_body (), r);
00452     return xsqtuple (r);
00453   }
00454   routine clone () const {
00455     return new overloaded_routine_rep
00456       (name, funs, env, serial,
00457        nullary, copy (unary), copy (binary),
00458        copy (n_ary), fall_back, status);
00459   }
00460 };
00461 
00462 routine
00463 overloaded_routine (const generic& name, const environment& env) {
00464   return new overloaded_routine_rep (name, env);
00465 }
00466 
00467 } // namespace mmx

Generated on Mon May 2 2011 17:04:34 for mmxlight:doc by  doxygen 1.7.2