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

/Users/magix/mmx/mmxlight/glue/glue_control.cpp

Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : control_glue.cpp
00004 * DESCRIPTION: Mathemagix control structures
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/mmxlight_glue.hpp>
00014 #include <mmxlight/base_evaluator.hpp>
00015 #include <basix/source_track.hpp>
00016 namespace mmx {
00017 
00018 /******************************************************************************
00019 * Foreign declarations
00020 ******************************************************************************/
00021 
00022 generic
00023 mmx_foreign (const generic& x) {
00024   (void) x;
00025   return void_value ();
00026 }
00027 
00028 /******************************************************************************
00029 * Begin statement
00030 ******************************************************************************/
00031 
00032 generic
00033 mmx_begin (const generic& x) {
00034   nat i, n= N(x);
00035   if (n==1) return void_value ();
00036   for (i=1; i<n-1; i++) {
00037     //mmout << "Evaluate " << x[i] << "\n";
00038     generic aux= eval (x[i]);
00039     if (is<exception> (aux)) return aux;
00040   }
00041   return eval (x[i]);
00042 }
00043 
00044 /******************************************************************************
00045 * Boolean operations
00046 ******************************************************************************/
00047 
00048 generic
00049 mmx_seqand (const generic& x) {
00050   if (N(x) != 3) return wrong_nr_args (x);
00051   generic r= eval_as<bool> (x[1]);
00052   if (is<exception> (r) || !as<bool> (r)) return r;
00053   return eval_as<bool> (x[2]);
00054 }
00055 
00056 generic
00057 mmx_seqor (const generic& x) {
00058   if (N(x) != 3) return wrong_nr_args (x);
00059   generic r= eval_as<bool> (x[1]);
00060   if (is<exception> (r) || as<bool> (r)) return r;
00061   return eval_as<bool> (x[2]);
00062 }
00063 
00064 bool
00065 mmx_not (const bool& x) {
00066   return !x;
00067 }
00068 
00069 bool
00070 mmx_xor (const bool& x1, const bool& x2) {
00071   return x1 ^ x2;
00072 }
00073 
00074 /******************************************************************************
00075 * If statement
00076 ******************************************************************************/
00077 
00078 generic
00079 mmx_if (const generic& x) {
00080   if (N(x) < 3 || N(x) > 4) return wrong_nr_args (x);
00081   generic cond= eval_as<bool> (x[1]);
00082   if (is<exception> (cond)) return cond;
00083   if (as<bool> (cond)) return eval (x[2]);
00084   else if (N(x) == 4) return eval (x[3]);
00085   else return void_value ();
00086 }
00087 
00088 /******************************************************************************
00089 * Loop statement
00090 ******************************************************************************/
00091 
00092 generic
00093 mmx_loop (const generic& x) {
00094   nat i, n= N(x)-1;
00095   if (n < 1) return wrong_nr_args (x);
00096   bool stop= false;
00097   generic aux, ret= void_value ();
00098   select_evaluator (base_evaluator (current_ev));
00099 
00100   table<iterator<generic>, generic> its;
00101   table<nat, generic> tps (0);
00102   for (i=1; i<n; i++)
00103     if (is_func (x[i], GEN_FOR, 1) && is_func (x[i][1], GEN_IN, 2)) {
00104       generic var= x[i][1][1];
00105       if (is_func (var, GEN_TYPE, 2)) {
00106         generic tp= eval (var[2]);
00107         if (is<exception> (tp)) { ret= tp; stop= true; break; }
00108         nat tid= type_id (tp);
00109         if (tid == 1) {
00110           ret= type_mismatch (GEN_TYPE_TYPE, var[2]); stop= true; break; }
00111         var= var[1];
00112         tps [var]= tid;
00113       }
00114       generic val= eval_as<iterator<generic> > (x[i][1][2]);
00115       if (is<exception> (val)) { ret= val; stop= true; break; }
00116       its [var]= as<iterator<generic> > (val);
00117     }
00118     else if (is_func (x[i], GEN_FOR, 1)) {
00119       aux= eval (x[i][1]);
00120       if (is<exception> (aux)) {
00121         stop= true;
00122         ret= aux;
00123         break;
00124       }
00125     }
00126 
00127   while (!stop) {
00128     for (i=1; i<n; i++)
00129       if (is_func (x[i], GEN_FOR, 1) && is_func (x[i][1], GEN_IN, 2)) {
00130         generic var= x[i][1][1];
00131         bool typed= is_func (var, GEN_TYPE, 2);
00132         if (typed) var= var[1];
00133         iterator<generic>& it= its [var];
00134         if (done (it)) { stop= true; break; }
00135         aux= *it; ++it;
00136         if (typed) aux= convert_to (aux, read (tps, var), x[i][1][2]);
00137         if (is<exception> (aux)) { ret= aux; stop= true; break; }
00138         current_ev->set (var, aux);
00139       }
00140       else if (is_func (x[i], GEN_WHILE, 1)) {
00141         generic cond= eval_as<bool> (x[i][1]);
00142         if (is<exception> (cond)) { ret= cond; stop= true; break; }
00143         if (!as<bool> (cond)) { stop= true; break; }
00144       }
00145     if (stop) break;
00146 
00147     select_evaluator (base_evaluator (current_ev));
00148     aux= eval (x[n]);
00149     restore_evaluator ();    
00150 
00151     if (is<exception> (aux)) {
00152       generic msg= *as<exception> (aux);
00153       if (exact_eq (msg, gen (GEN_CONTINUE)));
00154       else if (exact_eq (msg, gen (GEN_BREAK))) break;
00155       else { ret= aux; break; }
00156     }
00157 
00158     for (i=1; i<n; i++)
00159       if (is_func (x[i], GEN_UNTIL, 1)) {
00160         generic cond= eval_as<bool> (x[i][1]);
00161         if (is<exception> (cond)) { ret= cond; stop= true; break; }
00162         if (as<bool> (cond)) { stop= true; break; }
00163       }
00164       else if (is_func (x[i], GEN_STEP, 1)) {
00165         aux= eval (x[i][1]);
00166         if (is<exception> (aux)) { ret= aux; stop= true; break; }
00167       }
00168   }
00169 
00170   restore_evaluator ();
00171   return ret;
00172 }
00173 
00174 generic
00175 mmx_break (const generic& x) {
00176   if (N(x) != 1) return wrong_nr_args (x);
00177   return as<generic> (exception (gen (GEN_BREAK)));
00178 }
00179 
00180 generic
00181 mmx_continue (const generic& x) {
00182   if (N(x) != 1) return wrong_nr_args (x);
00183   return as<generic> (exception (gen (GEN_CONTINUE)));
00184 }
00185 
00186 /******************************************************************************
00187 * Range generation
00188 ******************************************************************************/
00189 
00190 class count_iterator_rep: public iterator_rep<generic> {
00191   int start, end;
00192 public:
00193   count_iterator_rep (const int& s, const int& e): start (s), end (e) {}
00194   ~count_iterator_rep () {}
00195 protected:
00196   bool is_busy () { return start < end; }
00197   void advance () { start++; }
00198   generic current () { return as<generic> (start); }
00199   iterator_rep<generic>* clone () {
00200     return new count_iterator_rep (start, end); }
00201 };
00202 
00203 static iterator<generic>
00204 count_iterator (const int& start, const int& end) {
00205   return iterator<generic> (new count_iterator_rep (start, end));
00206 }
00207 
00208 generic
00209 mmx_count (const int& end) {
00210   return as<generic> (count_iterator (0, end));
00211 }
00212 
00213 generic
00214 mmx_range (const generic& start, const generic& end) {
00215   return as<generic> (range_iterator<generic> (start, end, 1, true));
00216 }
00217 
00218 generic
00219 mmx_to (const generic& start, const generic& end) {
00220   return as<generic> (range_iterator<generic> (start, end, 1, false));
00221 }
00222 
00223 generic
00224 mmx_downto (const generic& start, const generic& end) {
00225   return as<generic> (range_iterator<generic> (start, end, -1, false));
00226 }
00227 
00228 /******************************************************************************
00229 * Where generators
00230 ******************************************************************************/
00231 
00232 class extract_iterator_rep: public iterator_rep<generic> {
00233   evaluator ev;
00234   generic var;
00235   iterator<generic> it;
00236   generic cond;
00237   generic body;
00238   generic value;
00239 
00240   void spool () {
00241     select_evaluator (ev);
00242     while (busy (it)) {
00243       generic val= *it;
00244       current_ev->set (var, val);
00245       generic ok= eval_as<bool> (cond);
00246       if (is<exception> (ok)) {
00247         value= ok;
00248         break;
00249       }
00250       else if (as<bool> (ok)) {
00251         value= eval (body);
00252         break;
00253       }
00254       else ++it;
00255     }
00256     restore_evaluator ();
00257     if (done (it)) value= void_value ();
00258   }
00259 
00260 public:
00261   extract_iterator_rep (const evaluator& e, const generic& v,
00262                         const iterator<generic>& i, const generic& c,
00263                         const generic& b):
00264       ev (e), var (v), it (i), cond (c), body (b) { spool (); }
00265   ~extract_iterator_rep () {
00266     /*
00267     mmout << "Destroy iterator on " << flush_now;
00268     mmout << as_lisp (var) << ": " << as_lisp (body);
00269     mmout << ", " << ev->ref_count;
00270     mmout << "\n";
00271     //mmout << "Destroy " << body << " where "
00272     //<< var << " in iterator satisfies " << cond << "\n";
00273     */
00274   }
00275 
00276 protected:
00277   bool is_busy () { return busy (it); }
00278   void advance () { ++it; spool(); }
00279   generic current () { return value; }
00280   iterator_rep<generic>* clone () {
00281     extract_iterator_rep* rep=
00282       new extract_iterator_rep (ev, var, it, cond, body);
00283     rep->value= value;
00284     return rep;
00285   }
00286 };
00287 
00288 
00289 inline iterator<generic>
00290 extract_iterator (const evaluator& ev, const generic& var,
00291                   const iterator<generic>& it, const generic& cond,
00292                   const generic& v)
00293 {
00294   return iterator<generic> (new extract_iterator_rep (ev, var, it, cond, v));
00295 }
00296 
00297 class unnest_iterator_rep: public iterator_rep<generic> {
00298   iterator<generic> it;
00299   iterator<generic> subit;
00300 
00301   void spool () {
00302     while (busy (it)) {
00303       generic val= *it; ++it;
00304       if (!is<exception> (val) && !is<iterator<generic> > (val))
00305         val= type_mismatch (gen (GEN_GENERATOR_TYPE, GEN_GENERIC_TYPE), val);
00306       if (is<exception> (val)) subit= seq<generic> (val);
00307       else subit= as<iterator<generic> > (val);
00308       if (busy (subit)) break;
00309     }
00310   }
00311 
00312 public:
00313   unnest_iterator_rep (const iterator<generic>& i):
00314     it (i) { spool (); }
00315   unnest_iterator_rep (const iterator<generic>& i, const iterator<generic>& j):
00316     it (i), subit (j) {}
00317   ~unnest_iterator_rep () {}
00318 
00319 protected:
00320   bool is_busy () { return busy (subit); }
00321   void advance () { ++subit; if (done (subit)) spool(); }
00322   generic current () { return *subit; }
00323   iterator_rep<generic>* clone () {
00324     unnest_iterator_rep* rep= new unnest_iterator_rep (it, subit);
00325     return rep;
00326   }
00327 };
00328 
00329 inline iterator<generic>
00330 unnest_iterator (const iterator<generic>& it) {
00331   return iterator<generic> (new unnest_iterator_rep (it));
00332 }
00333 
00334 generic
00335 mmx_where (const generic& x) {
00336   nat i, n= N(x);
00337   if (n < 3) return wrong_nr_args (x);
00338   if (is_func (x[1], GEN_IN, 2)) {
00339     // TODO: generalize syntax when x[1] is a tuple
00340     // with elements of the form 'variable in generator'.
00341     return mmx_where (append (gen (x[0], x[1][1], x[1]), range (x, 2, N(x))));
00342   }
00343   if (!is_func (x[2], GEN_IN, 2))
00344     return std_exception ("'variable in generator' expected", x[2]);
00345   for (i=3; i<n; i++)
00346     if (is_func (x[i], GEN_IN, 2))
00347       break;
00348   if (i == n) {
00349     generic cond= GEN_TRUE;
00350     if (i > 3) {
00351       cond= x[i-1];
00352       for (nat j=i-2; j>=3; j--)
00353         cond= gen (GEN_SEQAND, x[j], cond);
00354     }
00355     generic body= x[1];
00356     generic var = x[2][1];
00357     if (is_func (var, GEN_TYPE, 2)) {
00358       // FIXME: should really declare variable of specified type
00359       var = var[1];
00360     }
00361     if (!is<literal> (var)) return type_mismatch (GEN_LITERAL_TYPE, var);
00362     generic val= eval_as<iterator<generic> > (x[2][2]);
00363     if (is<exception> (val)) return val;
00364     evaluator ev= base_evaluator (current_ev);
00365     iterator<generic> it= as<iterator<generic> > (val);
00366     iterator<generic> r = extract_iterator (ev, var, it, cond, body);
00367     generic ret= as<generic> (r);
00368     return ret;
00369   }
00370   else {
00371     generic inner= append (gen (x[0], x[1]), range (x, i, n));
00372     generic outer= append (gen (x[0], inner), range (x, 2, i));
00373     generic it= mmx_where (outer);
00374     if (is<exception> (it)) return it;
00375     return as<generic> (unnest_iterator (as<iterator<generic> > (it)));
00376   }
00377 }
00378 
00379 /******************************************************************************
00380 * Grouping (tuples and generators)
00381 ******************************************************************************/
00382 
00383 tuple<generic>
00384 mmx_fill (const generic& x, const int& nr) {
00385   ASSERT (nr >= 0, "positive integer expected");
00386   return as_tuple (fill<generic> (x, nr));
00387 }
00388 
00389 tuple<generic>
00390 mmx_tuple (const tuple<generic>& t) {
00391   return t;
00392 }
00393 
00394 iterator<generic>
00395 mmx_explode (const iterator<generic>& it) {
00396   return it;
00397 }
00398 
00399 generic
00400 mmx_protect (const generic& x) {
00401   if (N(x) != 2) return wrong_nr_args (x);
00402   generic it= eval (x[1]);
00403   if (is<exception> (it)) return it;
00404   else return gen ("protect", it);
00405 }
00406 
00407 generic
00408 mmx_unprotect (const generic& x) {
00409   if (N(x) != 2) return wrong_nr_args (x);
00410   generic it= eval (x[1]);
00411   if (is<compound> (it) && N(it) == 2 && it[0] == "protect") return it[1];
00412   return std_exception ("protected generator expected", x[1]);
00413 }
00414 
00415 /******************************************************************************
00416 * Error handling
00417 ******************************************************************************/
00418 
00419 extern nat backtrace_depth;
00420 
00421 class backtrace_depth_rep: public alias_rep<int> {
00422 MMX_ALLOCATORS
00423   int prec;
00424 public:
00425   inline backtrace_depth_rep () {}
00426   int get () const { return backtrace_depth; }
00427   int& open () const { return *((int*) ((void*) (&backtrace_depth))); }
00428   void close () const {}
00429 };
00430 
00431 class var_exception {
00432 MMX_ALLOCATORS
00433   generic rep;
00434 public:
00435   inline generic operator * () const { return rep; }
00436   inline var_exception (const generic& g): rep (g) {}
00437 };
00438 
00439 inline syntactic flatten (const var_exception& e) { return flatten (*e); }
00440 WRAP_INDIRECT_IMPL(inline,var_exception)
00441 
00442 var_exception
00443 mmx_exception (const string& msg, const generic& where) {
00444   return var_exception (std_exception (msg, where));
00445 }
00446 
00447 string
00448 mmx_exception_as_string (const var_exception& exc) {
00449   return source_exception (as<exception> (*exc));
00450 }
00451 
00452 generic
00453 mmx_try (const generic& x) {
00454   if (N(x) < 2) return wrong_nr_args (x);
00455 
00456   generic body= x[1];
00457   if (!is_func (body, GEN_BEGIN)) body= gen (GEN_BEGIN, body);
00458   vector<generic> v= compound_to_vector (x);
00459   v= range (v, 2, N(v));
00460   v << cdr (compound_to_vector (body));
00461   body= gen (GEN_BEGIN, v);
00462 
00463   select_evaluator (base_evaluator (current_ev));
00464   generic r= eval (body);
00465   if (is<exception> (r)) {
00466     generic err= *as<exception> (r), ret;
00467     if (is<vector<generic> > (err[1]))
00468       ret= current_ev->apply (GEN_CATCH, as<vector<generic> > (err[1]));
00469     else ret= current_ev->apply (GEN_CATCH, as<generic> (var_exception (r)));
00470     if (!is_func (ret, GEN_CATCH)) r= ret;
00471   }
00472   restore_evaluator ();
00473 
00474   return r;
00475 }
00476 
00477 generic
00478 mmx_raise (const generic& x) {
00479   vector<generic> args;
00480   for (nat i=1; i<N(x); i++) {
00481     generic r= eval (x[i]);
00482     if (is<exception> (r)) return r;
00483     else args << r;
00484   }
00485   if (N(args) == 1 && is<var_exception> (args[0]))
00486     return *as<var_exception> (args[0]);
00487   else return user_exception (args, x);
00488 }
00489 
00490 /******************************************************************************
00491 * Interface
00492 ******************************************************************************/
00493 
00494 void
00495 glue_control () {
00496   static alias<int> depth= new backtrace_depth_rep ();
00497   define_constant<alias<int> > ("backtrace_depth", depth);
00498   define_type<var_exception> ("Exception");
00499   define_type<iterator<generic> > (gen("Generator",generic("Generic")));
00500   define_primitive (GEN_FOREIGN, mmx_foreign);
00501   define_primitive (GEN_BEGIN, mmx_begin);
00502   define_primitive (GEN_SEQAND, mmx_seqand);
00503   define_primitive (GEN_SEQOR, mmx_seqor);
00504   define           (GEN_NOT, mmx_not);
00505   define           (GEN_XOR, mmx_xor);
00506   define_primitive (GEN_IF, mmx_if);
00507   define_primitive (GEN_LOOP, mmx_loop);
00508   define_primitive (GEN_BREAK, mmx_break);
00509   define_primitive (GEN_CONTINUE, mmx_continue);
00510   define           (GEN_RANGE, mmx_range);
00511   define           ("count", mmx_count);
00512   define           (GEN_TO, mmx_to);
00513   define           (GEN_DOWNTO, mmx_downto);
00514   define_primitive (GEN_WHERE, mmx_where);
00515   define_primitive (GEN_VWHERE, mmx_where);
00516   define           (GEN_FILL, mmx_fill);
00517   define           (GEN_TUPLE, mmx_tuple);
00518   define           (GEN_EXPLODE, mmx_explode);
00519   define_primitive ("protect", mmx_protect);
00520   define_primitive ("unprotect", mmx_unprotect);
00521   define           ("exception", mmx_exception);
00522   define           ("as_string", mmx_exception_as_string);
00523   define_primitive (GEN_TRY, mmx_try);
00524   define_primitive (GEN_RAISE, mmx_raise);
00525 }
00526 
00527 } // namespace mmx

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