Back to index

texmacs  1.0.7.15
evaluate_inactive.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : evaluate_inactive.cpp
00004 * DESCRIPTION: generate source code representations for inactive trees
00005 * COPYRIGHT  : (C) 2006  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include "evaluate_main.hpp"
00013 #include "memorizer.hpp"
00014 #include "std_environment.hpp"
00015 #include "vars.hpp"
00016 
00017 /******************************************************************************
00018 * Some trees need to be defined only once (ensuring a fixed address)
00019 ******************************************************************************/
00020 
00021 static tree psep_var ("par-par-sep");
00022 static tree psep_0fn ("0fn");
00023 static tree mode_var ("mode");
00024 static tree mode_src ("src");
00025 static tree surround1 ("");
00026 static tree surround2 (VSPACE, "0.5fn");
00027 
00028 /******************************************************************************
00029 * Forward definitions
00030 ******************************************************************************/
00031 
00032 bool is_long_arg (tree t, int i);
00033 bool is_long (tree t);
00034 string arg_type (tree t, int i);
00035 
00036 tree
00037 highlight (tree t, string kind) {
00038   if (is_compound (t))        return t;
00039   else if (kind == "")        return t;
00040   else if (kind == "macro")   return compound ("src-macro", t);
00041   else if (kind == "var")     return compound ("src-var", t);
00042   else if (kind == "arg")     return compound ("src-arg", t);
00043   else if (kind == "tt")      return compound ("src-tt", t);
00044   else if (kind == "integer") return compound ("src-integer", t);
00045   else if (kind == "length")  return compound ("src-length", t);
00046   else if (kind == "error")   return compound ("src-error", t);
00047   return t;
00048 }
00049 
00050 class inactive_style;
00051 tree rewrite_inactive (tree t, inactive_style sty);
00052 tree rewrite_inactive_default (tree t, inactive_style sty);
00053 
00054 /******************************************************************************
00055 * Values for inactive style parameters
00056 ******************************************************************************/
00057 
00058 #define STYLE_ANGULAR         0
00059 #define STYLE_SCHEME          1
00060 #define STYLE_LATEX           2
00061 #define STYLE_FUNCTIONAL      3
00062 
00063 #define SPECIAL_RAW           0
00064 #define SPECIAL_FORMAT        1
00065 #define SPECIAL_NORMAL        2
00066 #define SPECIAL_MAXIMAL       3
00067 
00068 #define COMPACT_ALL           0
00069 #define COMPACT_INLINE_ARGS   1
00070 #define COMPACT_INLINE_START  2
00071 #define COMPACT_INLINE        3
00072 #define COMPACT_NONE          4
00073 
00074 #define CLOSE_MINIMAL         0
00075 #define CLOSE_COMPACT         1
00076 #define CLOSE_LONG            2
00077 #define CLOSE_REPEAT          3
00078 
00079 /******************************************************************************
00080 * Inactive style parameters
00081 ******************************************************************************/
00082 
00083 struct inactive_style_rep {
00084   unsigned style   : 4;
00085   unsigned special : 4;
00086   unsigned compact : 4;
00087   unsigned close   : 4;
00088   unsigned mode    : 4;
00089   unsigned block   : 1;
00090   unsigned flush   : 1;
00091   unsigned recover : 1;
00092 };
00093 
00094 class inactive_style {
00095   int rep;
00096 public:
00097   inline inactive_style (): rep (0) {}
00098   inline inactive_style (const inactive_style& sty): rep (sty.rep) {}
00099   inline inactive_style& operator = (const inactive_style& sty) {
00100     rep= sty.rep; return *this; }
00101   inline inactive_style_rep* operator -> () {
00102     return (inactive_style_rep*) ((void*) &rep); }
00103   inline bool operator == (inactive_style sty) { return rep == sty.rep; }
00104   inline bool operator != (inactive_style sty) { return rep != sty.rep; }
00105        inline friend int hash (inactive_style sty);
00106 };
00107 
00108 inline inactive_style set_bf (inactive_style sty, bool block, bool flush) {
00109   inactive_style new_sty= sty;
00110   new_sty->block= block;
00111   new_sty->flush= flush;
00112   return new_sty; }
00113 
00114 inline inactive_style reset_bf (inactive_style sty) {
00115   inactive_style new_sty= sty;
00116   new_sty->block= 0;
00117   new_sty->flush= 0;
00118   return new_sty; }
00119 
00120 inline int hash (inactive_style sty) {
00121   return sty.rep; }
00122 
00123 inactive_style
00124 retrieve (environment env) {
00125   string s;
00126   inactive_style sty;
00127 
00128   s= as_string (env [SRC_STYLE]);
00129   if (s == "angular") sty->style= STYLE_ANGULAR;
00130   else if (s == "scheme") sty->style= STYLE_SCHEME;
00131   else if (s == "latex") sty->style= STYLE_LATEX;
00132   else if (s == "functional") sty->style= STYLE_FUNCTIONAL;
00133   else sty->style= STYLE_ANGULAR;
00134   
00135   s= as_string (env [SRC_SPECIAL]);
00136   if (s == "raw") sty->special= SPECIAL_RAW;
00137   else if (s == "format") sty->special= SPECIAL_FORMAT;
00138   else if (s == "normal") sty->special= SPECIAL_NORMAL;
00139   else if (s == "maximal") sty->special= SPECIAL_MAXIMAL;
00140   else sty->special= SPECIAL_NORMAL;
00141 
00142   s= as_string (env [SRC_COMPACT]);
00143   if (s == "all") sty->compact= COMPACT_ALL;
00144   else if (s == "inline args") sty->compact= COMPACT_INLINE_ARGS;
00145   else if (s == "normal") sty->compact= COMPACT_INLINE_START;
00146   else if (s == "inline") sty->compact= COMPACT_INLINE;
00147   else if (s == "none") sty->compact= COMPACT_NONE;
00148   else sty->compact= COMPACT_INLINE_START;
00149 
00150   s= as_string (env [SRC_CLOSE]);
00151   if (s == "minimal") sty->close= CLOSE_MINIMAL;
00152   else if (s == "compact") sty->close= CLOSE_COMPACT;
00153   else if (s == "long") sty->close= CLOSE_LONG;
00154   else if (s == "repeat") sty->close= CLOSE_REPEAT;
00155   else sty->close= CLOSE_COMPACT;
00156 
00157   return sty;
00158 }
00159 
00160 /******************************************************************************
00161 * Memorizing rewritings
00162 ******************************************************************************/
00163 
00164 static tree no_tree (UNINIT);
00165 
00166 class memorizer;
00167 class inactive_memorizer_rep: public compound_memorizer_rep {
00168   environment env_in;
00169   tree t_in;
00170   inactive_style sty_in;
00171   environment env_out;
00172   tree t_out;
00173 
00174 public:
00175   inline inactive_memorizer_rep (environment env, tree t, inactive_style sty):
00176     env_in (env), t_in (t), sty_in (sty), env_out (), t_out (no_tree) {}
00177   void print (tm_ostream& out) {
00178     out << "inactive_memorizer (" << t_in << ")"; }
00179 
00180   int type () { return MEMORIZE_INACTIVE; }
00181   int hash () {
00182     return weak_hash (env_in) ^ weak_hash (t_in) ^ ::hash (sty_in); }
00183   bool equal (memorizer_rep* mem) {
00184     inactive_memorizer_rep* rep= (inactive_memorizer_rep*) mem;
00185     return
00186       weak_equal (env_in, rep->env_in) &&
00187       weak_equal (t_in, rep->t_in) &&
00188       sty_in == rep->sty_in; }
00189 
00190   void set_environment (environment env) { env_out= env; }
00191   environment get_environment () { return env_out; }
00192   void set_tree (tree t) { t_out= t; }
00193   tree get_tree () { return t_out; }
00194 };
00195 
00196 inline memorizer
00197 inactive_memorizer (environment env, tree t, inactive_style sty) {
00198   return (memorizer_rep*) tm_new<inactive_memorizer_rep> (env, t, sty);
00199 }
00200 
00201 /******************************************************************************
00202 * Compute rendering of inactive markup
00203 ******************************************************************************/
00204 
00205 tree
00206 rewrite_inactive_arg (tree t, int i, inactive_style sty) {
00207   tree r= t[i];
00208   if ((sty->mode == INACTIVE_INLINE_RECURSE) ||
00209       (sty->mode == INACTIVE_BLOCK_RECURSE))
00210     {
00211       /*
00212       if (N (recover_env) > 0) {
00213        int j;
00214        tree recover= copy (recover_env), old_recover= recover_env;
00215        for (j=0; j<N(recover); j+=2) {
00216          string var= recover[j]->label;
00217          recover[j+1]= read (var);
00218          write_update (var, recover_env[j+1]);
00219        }
00220        recover_env= tuple ();
00221        r= rewrite_inactive (r, sty);
00222        recover_env= old_recover;
00223        for (j=0; j<N(recover); j+=2)
00224          write_update (recover[j]->label, recover[j+1]);
00225       }
00226       else
00227       */
00228        r= rewrite_inactive (r, sty);
00229     }
00230   return highlight (r, arg_type (t, i));
00231 }
00232 
00233 tree
00234 rewrite_inactive_raw_data (tree t, inactive_style sty) {
00235   (void) t;
00236   return rewrite_inactive_default (tree (RAW_DATA), sty);
00237 }
00238 
00239 tree
00240 rewrite_inactive_document (tree t, inactive_style sty) {
00241   if ((sty->block || (sty->compact == COMPACT_NONE)) &&
00242       (sty->special > SPECIAL_RAW) &&
00243       (sty->compact != COMPACT_ALL))
00244     {
00245       int i, n= N(t);
00246       tree r (DOCUMENT, n);
00247       for (i=0; i<n; i++) {
00248        inactive_style ss= set_bf (sty, true, sty->flush || (i<n-1));
00249        r[i]= rewrite_inactive_arg (t, i, ss);
00250       }
00251       return r;
00252     }
00253   return rewrite_inactive_default (t, sty);
00254 }
00255 
00256 tree
00257 rewrite_inactive_concat (tree t, inactive_style sty) {
00258   if ((sty->special > SPECIAL_RAW) && (sty->compact != COMPACT_NONE)) {
00259     int i, n= N(t);
00260     tree r (CONCAT, n);
00261     for (i=0; i<n; i++)
00262       r[i]= rewrite_inactive_arg (t, i, reset_bf (sty));
00263     return r;
00264   }
00265   return rewrite_inactive_default (t, sty);
00266 }
00267 
00268 tree
00269 rewrite_inactive_value (tree t, inactive_style sty) {
00270   if ((N(t) == 1) && is_atomic (t[0]) &&
00271       sty->style != STYLE_SCHEME && sty->special >= SPECIAL_NORMAL)
00272     return highlight (t[0],
00273                     sty->mode == INACTIVE_INLINE_ERROR ||
00274                     sty->mode == INACTIVE_BLOCK_ERROR ?
00275                     string ("error"): string ("var"));
00276   return rewrite_inactive_default (t, sty);
00277 }
00278 
00279 tree
00280 rewrite_inactive_arg (tree t, inactive_style sty) {
00281   if ((N(t) == 1) && is_atomic (t[0]) &&
00282       sty->style != STYLE_SCHEME && sty->special >= SPECIAL_NORMAL)
00283     return highlight (t[0],
00284                     sty->mode == INACTIVE_INLINE_ERROR ||
00285                     sty->mode == INACTIVE_BLOCK_ERROR ?
00286                     string ("error"): string ("arg"));
00287   return rewrite_inactive_default (t, sty);
00288 }
00289 
00290 tree
00291 rewrite_inactive_symbol (tree t, inactive_style sty) {
00292   if ((N(t) == 1) && is_atomic (t[0]) && (sty->special >= SPECIAL_NORMAL))
00293     return tree (INLINE_TAG, t[0]);
00294   return rewrite_inactive_default (t, sty);
00295 }
00296 
00297 tree
00298 rewrite_inactive_style_with (tree t, inactive_style sty, bool once) {
00299   (void) once;
00300   int /*i,*/ n= N(t);
00301   tree recover= tuple ();
00302   /*
00303   for (i=0; i<n-1; i+=2)
00304     if (is_atomic (t[i])) {
00305       recover << t[i] << read (t[i]->label);
00306       write_update (t[i]->label, t[i+1]);
00307     }
00308     if (once) recover_env= recover;
00309   */
00310   tree r= rewrite_inactive (t[n-1], sty);
00311   /*
00312   for (i=0; i<N(recover); i+=2)
00313     write_update (recover[i]->label, recover[i+1]);
00314   if (once) recover_env= tuple ();
00315   */
00316   return r;
00317 }
00318 
00319 tree
00320 rewrite_inactive_active (tree t, inactive_style sty) {
00321   tree st= t[0];
00322   int i, n= N(st);
00323   tree r (st, n);
00324   bool mp= is_multi_paragraph (st);
00325   for (i=0; i<n; i++) {
00326     bool smp= mp && is_long_arg (st, i);
00327     if (is_func (st, WITH) && (i<n-1)) r[i]= st[i];
00328     else {
00329       inactive_style ss= set_bf (sty, sty->block && smp, sty->flush && smp);
00330       r[i]= rewrite_inactive_arg (st, i, ss);
00331     }
00332   }
00333   return r;
00334 }
00335 
00336 tree
00337 rewrite_inactive_var_active (tree t, inactive_style sty) {
00338   tree r= tree (WITH, mode_var, std_env [MODE], t[0]);
00339   if (sty->flush &&
00340       (sty->compact != COMPACT_ALL) &&
00341       (is_multi_paragraph (t[0])) || (sty->compact == COMPACT_NONE))
00342     r= tree (SURROUND, "", compound ("right-flush"), r);
00343   return r;
00344 }
00345 
00346 tree
00347 rewrite_inactive_hybrid (tree t, inactive_style sty) {
00348   if (is_atomic (t[0]) && (sty->special >= SPECIAL_NORMAL)) {
00349     int i, n= N(t);
00350     tree r (INLINE_TAG, n);
00351     r[0]= tree (CONCAT, "\\", highlight (t[0], "var"));
00352     for (i=1; i<n; i++)
00353       r[i]= rewrite_inactive_arg (t, i, reset_bf (sty));
00354     return r;
00355   }
00356   return rewrite_inactive_default (t, sty);
00357 }
00358 
00359 tree
00360 rewrite_inactive_default (tree t, inactive_style sty) {
00361   int i, d= 0, n= N(t);
00362   tree op= as_string (L(t));
00363   if ((L(t) == COMPOUND) &&
00364       is_atomic (t[0]) &&
00365       (sty->special >= SPECIAL_NORMAL))
00366     {
00367       d = 1;
00368       op= highlight (t[0], "var");
00369     }
00370   if (sty->mode == INACTIVE_INLINE_ERROR ||
00371       sty->mode == INACTIVE_BLOCK_ERROR)
00372     op= highlight (op, "error");
00373 
00374   if ((N(t) == d) ||
00375       (sty->compact == COMPACT_ALL) ||
00376       ((!sty->block) && (sty->compact != COMPACT_NONE)) ||
00377       (!is_long (t)) && (sty->compact != COMPACT_NONE))
00378     {
00379       tree r (INLINE_TAG, n+1-d);
00380       r[0]= op;
00381       for (i=d; i<n; i++)
00382        r[i+1-d]= rewrite_inactive_arg (t, i, reset_bf (sty));
00383       return r;
00384     }
00385   else {
00386     tree doc (DOCUMENT);
00387     bool compact= (sty->compact < COMPACT_INLINE);
00388  
00389     for (i=d; i<n; i++) {
00390       tree next;
00391       if ((!compact) || is_long_arg (t, i)) {
00392        if (i==d) doc << tree (OPEN_TAG, op);
00393        inactive_style ss= set_bf (sty, true, sty->close >= CLOSE_LONG);
00394        next= rewrite_inactive_arg (t, i, ss);
00395        next= compound ("indent*", next);
00396        i++;
00397       }
00398 
00399       int start= i;
00400       for (; i<n; i++)
00401        if ((!compact) || is_long_arg (t, i)) break;
00402       int end= i;
00403       tree_label l= MIDDLE_TAG;
00404       if (end == n) l= CLOSE_TAG;
00405       if (start == d) l= OPEN_TAG;
00406       tree u (l, end - start + 1);
00407       u[0]= op;
00408       for (i=0; i<end-start; i++)
00409        u[i+1]= rewrite_inactive_arg (t, start+i, reset_bf (sty));
00410       i= end-1;
00411       compact= (sty->compact < COMPACT_INLINE_START);
00412 
00413       if (start==d) doc << u;
00414       else {
00415        if (sty->close < CLOSE_LONG)
00416          doc << tree (SURROUND, "", u, next);
00417        else doc << next << u;
00418       }
00419     }
00420 
00421     if (sty->flush) doc= tree (SURROUND, "", compound ("right-flush"), doc);
00422     return doc;
00423   }
00424 }
00425 
00426 tree
00427 rewrite_inactive_impl (tree t, inactive_style sty) {
00428   switch (L(t)) {
00429   case UNINIT:
00430     if (sty->special >= SPECIAL_NORMAL)
00431       return highlight ("?", "error");
00432     else return rewrite_inactive_default (t, sty);
00433   case RAW_DATA:
00434     return rewrite_inactive_raw_data (t, sty);
00435   case DOCUMENT:
00436     return rewrite_inactive_document (t, sty);
00437   case CONCAT:
00438     return rewrite_inactive_concat (t, sty);
00439   case VALUE:
00440     return rewrite_inactive_value (t, sty);
00441   case ARG:
00442     return rewrite_inactive_arg (t, sty);
00443   case STYLE_WITH:
00444     return rewrite_inactive_style_with (t, sty, true);
00445   case VAR_STYLE_WITH:
00446     return rewrite_inactive_style_with (t, sty, false);
00447   case STYLE_ONLY:
00448     return rewrite_inactive_active (t, sty);
00449   case VAR_STYLE_ONLY:
00450     return rewrite_inactive_var_active (t, sty);
00451   case ACTIVE:
00452     return rewrite_inactive_active (t, sty);
00453   case VAR_ACTIVE:
00454     return rewrite_inactive_var_active (t, sty);
00455   case SYMBOL:
00456     return rewrite_inactive_symbol (t, sty);
00457   case HYBRID:
00458     return rewrite_inactive_hybrid (t, sty);
00459   default:
00460     return rewrite_inactive_default (t, sty);
00461   }
00462 }
00463 
00464 /******************************************************************************
00465 * Main rewriting routines
00466 ******************************************************************************/
00467 
00468 static tree quote1 (WITH, "color", "blue", "``");
00469 static tree quote2 (WITH, "color", "blue", "''");
00470 
00471 tree
00472 rewrite_inactive (tree t, inactive_style sty) {
00473   if (is_atomic (t)) {
00474     if (sty->style == STYLE_SCHEME)
00475       return tree (CONCAT, quote1, t, quote2);
00476     return t;
00477   }
00478   cout << "Inactive "
00479        << "[" << (t.operator -> ())
00480        << ", " << (std_env.operator -> ()) << "] "
00481        << t << INDENT << LF;
00482   memorizer mem= inactive_memorizer (std_env, t, sty);
00483   if (is_memorized (mem)) {
00484     cout << UNINDENT << "Memorized " << mem->get_tree () << LF;
00485     std_env= mem->get_environment ();
00486     return mem->get_tree ();
00487   }
00488   memorize_start ();
00489   tree r= rewrite_inactive_impl (t, sty);
00490   mem->set_tree (r);
00491   mem->set_environment (std_env);
00492   memorize_end ();
00493   cout << UNINDENT << "Rewritten as " << mem->get_tree () << LF;
00494   return mem->get_tree ();
00495 }
00496 
00497 tree
00498 rewrite_inactive (tree t, int inactive_mode) {
00499   //recover_env= tuple ();
00500   inactive_style sty= retrieve (std_env);
00501   sty->mode= inactive_mode;
00502   bool flag= (sty->mode >= INACTIVE_BLOCK_RECURSE);
00503   sty->block= sty->flush= flag;
00504   tree r= rewrite_inactive (t, sty);
00505   if (is_multi_paragraph (r)) {
00506     r= tree (WITH, psep_var, psep_0fn, r);
00507     r= tree (SURROUND, surround1, surround2, r);
00508   }
00509   if ((sty->mode == INACTIVE_INLINE_RECURSE) ||
00510       (sty->mode == INACTIVE_BLOCK_RECURSE))
00511     r= tree (WITH, mode_var, mode_src, r);
00512   return r;
00513 }