Back to index

texmacs  1.0.7.15
lazy_typeset.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : lazy_typeset.cpp
00004 * DESCRIPTION: Lazy typesetting of various primitives
00005 * COPYRIGHT  : (C) 1999  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 "Line/lazy_typeset.hpp"
00013 #include "Line/lazy_vstream.hpp"
00014 #include "Format/format.hpp"
00015 #include "Stack/stacker.hpp"
00016 #include "Boxes/construct.hpp"
00017 #include "analyze.hpp"
00018 #include "packrat.hpp"
00019 
00020 array<line_item> typeset_marker (edit_env env, path ip);
00021 array<line_item> typeset_concat (edit_env, tree t, path ip);
00022 array<line_item> join (array<line_item> a, array<line_item> b);
00023 lazy make_lazy_paragraph (edit_env env, tree t, path ip);
00024 lazy make_lazy_table (edit_env env, tree t, path ip);
00025 lazy make_lazy_canvas (edit_env env, tree t, path ip);
00026 lazy make_lazy_ornament (edit_env env, tree t, path ip);
00027 
00028 /******************************************************************************
00029 * Documents
00030 ******************************************************************************/
00031 
00032 lazy_document_rep::lazy_document_rep (edit_env env, tree t, path ip):
00033   lazy_rep (LAZY_DOCUMENT, ip), par (N(t))
00034 {
00035   int i, n= N(t);
00036   for (i=0; i<n; i++)
00037     par[i]= make_lazy (env, t[i], descend (ip, i));
00038 }
00039 
00040 format
00041 lazy_document_rep::query (lazy_type request, format fm) {
00042   if ((request == LAZY_BOX) && (fm->type == QUERY_VSTREAM_WIDTH)) {
00043     query_vstream_width qvw= (query_vstream_width) fm;
00044     array<line_item> before= qvw->before;
00045     array<line_item> after = qvw->after;
00046 
00047     SI w= 1;
00048     int i, n= N(par);
00049     for (i=0; i<n; i++) {
00050       format tmp_fm= make_query_vstream_width (
00051         i==0  ? before: array<line_item> (),
00052        i==n-1? after : array<line_item> ());
00053       format ret_fm= par[i]->query (request, tmp_fm);
00054       format_width fmw= (format_width) ret_fm;
00055       w= max (w, fmw->width);
00056     }
00057     return make_format_width (w);
00058   }
00059   return lazy_rep::query (request, fm);
00060 }
00061 
00062 lazy
00063 lazy_document_rep::produce (lazy_type request, format fm) {
00064   if (request == type) return this;
00065   if (request == LAZY_VSTREAM) {
00066     int i, n= N(par);
00067     SI width= 1;
00068     array<line_item> before;
00069     array<line_item> after;
00070     if (fm->type == FORMAT_VSTREAM) {
00071       format_vstream fs= (format_vstream) fm;
00072       width = fs->width ;
00073       before= fs->before;
00074       after = fs->after ;
00075     }
00076     array<page_item> l;
00077     stack_border     sb;
00078     for (i=0; i<n; i++) {
00079       format tmp_fm= make_format_vstream (width,
00080         i==0  ? before: array<line_item> (),
00081        i==n-1? after : array<line_item> ());
00082       lazy tmp= par[i]->produce (request, tmp_fm);
00083       lazy_vstream tmp_vs= (lazy_vstream) tmp;
00084       if (i == 0) {
00085        l = tmp_vs->l ;
00086        sb= tmp_vs->sb;
00087       }
00088       else merge_stack (l, sb, tmp_vs->l, tmp_vs->sb);
00089     }
00090     return lazy_vstream (ip, "", l, sb);
00091   }
00092   return lazy_rep::produce (request, fm);
00093 }
00094 
00095 /******************************************************************************
00096 * Surround
00097 ******************************************************************************/
00098 
00099 lazy_surround_rep::lazy_surround_rep (edit_env env, tree t, path ip):
00100   lazy_rep (LAZY_SURROUND, ip)
00101 {
00102   a  = typeset_concat (env, t[0], descend (ip, 0));
00103   b  = typeset_concat (env, t[1], descend (ip, 1));
00104   par= make_lazy (env, t[2], descend (ip, 2));
00105 }
00106 
00107 lazy_surround_rep::lazy_surround_rep (
00108   array<line_item> a2, array<line_item> b2, lazy par2, path ip):
00109   lazy_rep (LAZY_SURROUND, ip), a (a2), b (b2), par (par2) {}
00110 
00111 format
00112 lazy_surround_rep::query (lazy_type request, format fm) {
00113   if ((request == LAZY_BOX) && (fm->type == QUERY_VSTREAM_WIDTH)) {
00114     query_vstream_width qvw= (query_vstream_width) fm;
00115     array<line_item> before= qvw->before;
00116     array<line_item> after = qvw->after;
00117     if (N(a) != 0) before= join (before, a);
00118     if (N(b) != 0) after = join (b, after);
00119     format tmp_fm= make_query_vstream_width (before, after);
00120     return par->query (request, tmp_fm);
00121   }
00122   return lazy_rep::query (request, fm);
00123 }
00124 
00125 lazy
00126 lazy_surround_rep::produce (lazy_type request, format fm) {
00127   if (request == type) return this;
00128   if (request == LAZY_VSTREAM) {
00129     SI               width = 1;
00130     array<line_item> before= a;
00131     array<line_item> after = b;
00132     if (fm->type == FORMAT_VSTREAM) {
00133       format_vstream fs= (format_vstream) fm;
00134       width = fs->width ;
00135       before= join (fs->before, before);
00136       after = join (after, fs->after);
00137     }
00138     format ret_fm= make_format_vstream (width, before, after);
00139     return par->produce (request, ret_fm);
00140   }
00141   return lazy_rep::produce (request, fm);
00142 }
00143 
00144 /******************************************************************************
00145 * Hidden
00146 ******************************************************************************/
00147 
00148 lazy
00149 make_lazy_hidden (edit_env env, tree t, path ip) {
00150   (void) make_lazy (env, t[0], descend (ip, 0));
00151   return lazy_document (env, tree (DOCUMENT), ip);
00152 }
00153 
00154 /******************************************************************************
00155 * Formatting
00156 ******************************************************************************/
00157 
00158 lazy
00159 make_lazy_formatting (edit_env env, tree t, path ip, string v) {
00160   int last= N(t)-1;
00161   tree new_format= env->read (v) * t (0, last);
00162   tree old_format= env->local_begin (v, new_format);
00163   array<line_item> a;
00164   array<line_item> b;
00165   if (v != CELL_FORMAT) {
00166     a= typeset_marker (env, descend (ip, 0));
00167     b= typeset_marker (env, descend (ip, 1));
00168   }
00169   lazy par= make_lazy (env, t[last], descend (ip, last));
00170   env->local_end (v, old_format);
00171   return lazy_surround (a, b, par, ip);
00172 }
00173 
00174 /******************************************************************************
00175 * With
00176 ******************************************************************************/
00177 
00178 lazy
00179 make_lazy_with (edit_env env, tree t, path ip) {
00180   int last= N(t)-1;
00181   int i, k= last>>1; // is k=0 allowed ?
00182   // if ((last&1) != 0) return;
00183   
00184   STACK_NEW_ARRAY(vars,string,k);
00185   STACK_NEW_ARRAY(oldv,tree,k);
00186   STACK_NEW_ARRAY(newv,tree,k);
00187   for (i=0; i<k; i++) {
00188     tree var_t= env->exec (t[i<<1]);
00189     if (is_atomic (var_t)) {
00190       string var= var_t->label;
00191       vars[i]= var;
00192       oldv[i]= env->read (var);
00193       newv[i]= env->exec (t[(i<<1)+1]);
00194     }
00195     /*
00196     else {
00197       STACK_DELETE_ARRAY(vars);
00198       STACK_DELETE_ARRAY(oldv);
00199       STACK_DELETE_ARRAY(newv);
00200       return;
00201     }
00202     */
00203   }
00204 
00205   // for (i=0; i<k; i++) env->monitored_write_update (vars[i], newv[i]);
00206   for (i=0; i<k; i++) env->write_update (vars[i], newv[i]);
00207   array<line_item> a= typeset_marker (env, descend (ip, 0));
00208   array<line_item> b= typeset_marker (env, descend (ip, 1));
00209   lazy par= make_lazy (env, t[last], descend (ip, last));
00210   for (i=k-1; i>=0; i--) env->write_update (vars[i], oldv[i]);
00211   STACK_DELETE_ARRAY(vars);
00212   STACK_DELETE_ARRAY(oldv);
00213   STACK_DELETE_ARRAY(newv);
00214   return lazy_surround (a, b, par, ip);
00215 }
00216 
00217 /******************************************************************************
00218 * Compound
00219 ******************************************************************************/
00220 
00221 lazy
00222 make_lazy_compound (edit_env env, tree t, path ip) {
00223   int d; tree f;
00224   if (L(t) == COMPOUND) {
00225     d= 1;
00226     f= t[0];
00227     if (is_compound (f)) f= env->exec (f);
00228     if (is_atomic (f)) {
00229       string var= f->label;
00230       if (env->provides (var)) f= env->read (var);
00231       else f= tree (ERROR, "compound " * var);
00232     }
00233   }
00234   else {
00235     string var= as_string (L(t));
00236     if (env->provides (var)) f= env->read (var);
00237     else f= tree (ERROR, "compound " * var);
00238     d= 0;
00239   }
00240 
00241   array<line_item> a;
00242   array<line_item> b;
00243   if (/*NON_CHILD_ENFORCING(t)&&*/ (!is_decoration (ip))) {
00244     a= typeset_marker (env, descend (ip, 0));
00245     b= typeset_marker (env, descend (ip, 1));
00246   }
00247   lazy par;
00248 
00249   if (is_applicable (f)) {
00250     int i, n=N(f)-1, m=N(t)-d;
00251     env->macro_arg= list<hashmap<string,tree> > (
00252       hashmap<string,tree> (UNINIT), env->macro_arg);
00253     env->macro_src= list<hashmap<string,path> > (
00254       hashmap<string,path> (path (DECORATION)), env->macro_src);
00255     if (L(f) == XMACRO) {
00256       if (is_atomic (f[0])) {
00257        string var= f[0]->label;
00258        env->macro_arg->item (var)= t;
00259        env->macro_src->item (var)= ip;
00260       }
00261     }
00262     else for (i=0; i<n; i++)
00263       if (is_atomic (f[i])) {
00264        string var= f[i]->label;
00265        env->macro_arg->item (var)=
00266          i<m? t[i+d]: attach_dip (tree (UNINIT), decorate_right(ip));
00267        env->macro_src->item (var)= i<m? descend (ip,i+d): decorate_right(ip);
00268       }
00269     if (is_decoration (ip)) par= make_lazy (env, attach_here (f[n], ip));
00270     else par= make_lazy (env, attach_right (f[n], ip));
00271     env->macro_arg= env->macro_arg->next;
00272     env->macro_src= env->macro_src->next;
00273   }
00274   else {
00275     if (is_decoration (ip)) par= make_lazy (env, attach_here (f, ip));
00276     else par= make_lazy (env, attach_right (f, ip));
00277   }
00278   return lazy_surround (a, b, par, ip);
00279 }
00280 
00281 /******************************************************************************
00282 * Rewrite
00283 ******************************************************************************/
00284 
00285 lazy
00286 make_lazy_rewrite (edit_env env, tree t, path ip) {
00287   tree r= env->rewrite (t);
00288   array<line_item> a= typeset_marker (env, descend (ip, 0));
00289   array<line_item> b= typeset_marker (env, descend (ip, 1));
00290   lazy par= make_lazy (env, attach_right (r, ip));
00291   return lazy_surround (a, b, par, ip);
00292 }
00293 
00294 /******************************************************************************
00295 * Eval
00296 ******************************************************************************/
00297 
00298 lazy
00299 make_lazy_eval (edit_env env, tree t, path ip) {
00300   tree r= env->exec (is_func (t, EVAL, 1)? t[0]: tree (QUASIQUOTE, t[0]));
00301   array<line_item> a= typeset_marker (env, descend (ip, 0));
00302   array<line_item> b= typeset_marker (env, descend (ip, 1));
00303   lazy par= make_lazy (env, attach_right (r, ip));
00304   return lazy_surround (a, b, par, ip);
00305 }
00306 
00307 /******************************************************************************
00308 * Auto
00309 ******************************************************************************/
00310 
00311 lazy
00312 make_lazy_auto (edit_env env, tree t, path ip, tree f) {
00313   array<line_item> a;
00314   array<line_item> b;
00315   if (!is_decoration (ip)) {
00316     a= typeset_marker (env, descend (ip, 0));
00317     b= typeset_marker (env, descend (ip, 1));
00318   }
00319 
00320   lazy par;
00321   env->macro_arg= list<hashmap<string,tree> > (
00322     hashmap<string,tree> (UNINIT), env->macro_arg);
00323   env->macro_src= list<hashmap<string,path> > (
00324     hashmap<string,path> (path (DECORATION)), env->macro_src);
00325   string var= f[0]->label;
00326   env->macro_arg->item (var)= t;
00327   env->macro_src->item (var)= ip;
00328   if (is_decoration (ip)) par= make_lazy (env, attach_here (f[1], ip));
00329   else par= make_lazy (env, attach_right (f[1], ip));
00330   env->macro_arg= env->macro_arg->next;
00331   env->macro_src= env->macro_src->next;
00332 
00333   return lazy_surround (a, b, par, ip);
00334 }
00335 
00336 /******************************************************************************
00337 * Argument
00338 ******************************************************************************/
00339 
00340 lazy
00341 make_lazy_argument (edit_env env, tree t, path ip) {
00342   string name;
00343   tree   value;
00344   path   valip= decorate_right (ip);
00345 
00346   tree r= t[0];
00347   if (is_compound (r)) value= tree (ERROR, "bad arg");
00348   else {
00349     name = r->label;
00350     if ((!is_nil (env->macro_arg)) && env->macro_arg->item->contains (r->label)) {
00351       value= env->macro_arg->item [name];
00352       if (!is_func (value, BACKUP)) {
00353        path new_valip= env->macro_src->item [name];
00354        if (is_accessible (new_valip)) valip= new_valip;
00355       }
00356     }
00357     else value= tree (ERROR, "arg " * name);
00358   }
00359 
00360   array<line_item> a= typeset_marker (env, descend (ip, 0));
00361   array<line_item> b= typeset_marker (env, descend (ip, 1));
00362   list<hashmap<string,tree> > old_var= env->macro_arg;
00363   list<hashmap<string,path> > old_src= env->macro_src;
00364   if (!is_nil (env->macro_arg)) env->macro_arg= env->macro_arg->next;
00365   if (!is_nil (env->macro_src)) env->macro_src= env->macro_src->next;
00366 
00367   if (N(t) > 1) {
00368     int i, n= N(t);
00369     for (i=1; i<n; i++) {
00370       tree r= env->exec (t[i]);
00371       if (!is_int (r)) {
00372         value= tree (ERROR, "arg " * name);
00373         valip= decorate_right (ip);
00374         break;
00375       }
00376       int nr= as_int (r);
00377       if ((!is_compound (value)) || (nr<0) || (nr>=N(value))) {
00378         value= tree (ERROR, "arg " * name);
00379         valip= decorate_right (ip);
00380         break;
00381       }
00382       value= value[nr];
00383       valip= descend (valip, nr);
00384     }
00385   }
00386   lazy par= make_lazy (env, attach_here (value, valip));
00387 
00388   env->macro_arg= old_var;
00389   env->macro_src= old_src;
00390   return lazy_surround (a, b, par, ip);
00391 }
00392 
00393 /******************************************************************************
00394 * Mark and expand_as
00395 ******************************************************************************/
00396 
00397 lazy
00398 make_lazy_mark (edit_env env, tree t, path ip) {
00399   // cout << "Lazy mark: " << t << ", " << ip << "\n";
00400   array<line_item> a= typeset_marker (env, descend (ip, 0));
00401   array<line_item> b= typeset_marker (env, descend (ip, 1));
00402 
00403   if (is_func (t[0], ARG) &&
00404       is_atomic (t[0][0]) &&
00405       (!is_nil (env->macro_arg)) &&
00406       env->macro_arg->item->contains (t[0][0]->label))
00407     {
00408       string name = t[0][0]->label;
00409       tree   value= env->macro_arg->item [name];
00410       path   valip= decorate_right (ip);
00411       if (!is_func (value, BACKUP)) {
00412        path new_valip= env->macro_src->item [name];
00413        if (is_accessible (new_valip)) valip= new_valip;
00414       }
00415 
00416       if (N(t[0]) > 1) {
00417        int i, n= N(t[0]);
00418        for (i=1; i<n; i++) {
00419          tree r= env->exec (t[0][i]);
00420          if (!is_int (r)) break;
00421          int nr= as_int (r);
00422          if ((!is_compound (value)) || (nr<0) || (nr>=N(value))) break;
00423          value= value[nr];
00424          valip= descend (valip, nr);
00425        }
00426       }
00427       if (is_compound (value)) {
00428        a= typeset_marker (env, descend (valip, 0));
00429        b= typeset_marker (env, descend (valip, 1));
00430       }
00431     }
00432 
00433   lazy par= make_lazy (env, t[1], descend (ip, 1));
00434   return lazy_surround (a, b, par, ip);
00435 }
00436 
00437 lazy
00438 make_lazy_expand_as (edit_env env, tree t, path ip) {
00439   array<line_item> a= typeset_marker (env, descend (ip, 0));
00440   array<line_item> b= typeset_marker (env, descend (ip, 1));
00441   lazy par= make_lazy (env, t[1], descend (ip, 1));
00442   return lazy_surround (a, b, par, ip);
00443 }
00444 
00445 /******************************************************************************
00446 * Locus
00447 ******************************************************************************/
00448 
00449 lazy
00450 make_lazy_locus (edit_env env, tree t, path ip) {
00451   extern bool build_locus (edit_env env, tree t, list<string>& ids, string& c);
00452   list<string> ids;
00453   string col;
00454   if (!build_locus (env, t, ids, col))
00455     system_warning ("Ignored unaccessible loci");
00456   int last= N(t)-1;
00457   tree old_col= env->read (COLOR);
00458   env->write_update (COLOR, col);
00459   array<line_item> a= typeset_marker (env, descend (ip, 0));
00460   array<line_item> b= typeset_marker (env, descend (ip, 1));
00461   lazy par= make_lazy (env, t[last], descend (ip, last));
00462   env->write_update (COLOR, old_col);
00463   return lazy_surround (a, b, par, ip);
00464 }
00465 
00466 /******************************************************************************
00467 * Main routine
00468 ******************************************************************************/
00469 
00470 static tree inactive_m
00471   (MACRO, "x",
00472    tree (REWRITE_INACTIVE, tree (ARG, "x", "0"), "once*"));
00473 static tree var_inactive_m
00474   (MACRO, "x",
00475    tree (REWRITE_INACTIVE, tree (ARG, "x", "0"), "recurse*"));
00476 
00477 lazy
00478 make_lazy (edit_env env, tree t, path ip) {
00479   /*
00480   if (is_accessible (ip)) {
00481     if (obtain_ip (t) != ip)
00482       cout << "TeXmacs] Wrong ip: " << t << "\n";
00483   }
00484   */
00485 
00486   if (!is_accessible (ip)) {
00487     path ip2= obtain_ip (t);
00488     if (ip2 != path (DETACHED))
00489       ip= ip2;
00490   }
00491 
00492   if (env->hl_lan != 0)
00493     env->lan->highlight (t);
00494 
00495   switch (L(t)) {
00496   case DOCUMENT:
00497     return lazy_document (env, t, ip);
00498   case SURROUND:
00499     return lazy_surround (env, t, ip);
00500     //case HIDDEN:
00501     //return make_lazy_hidden (env, t, ip);
00502   case DATOMS:
00503     return make_lazy_formatting (env, t, ip, ATOM_DECORATIONS);
00504   case DLINES:
00505     return make_lazy_formatting (env, t, ip, LINE_DECORATIONS);
00506   case DPAGES:
00507     return make_lazy_formatting (env, t, ip, PAGE_DECORATIONS);
00508   case TFORMAT:
00509     return make_lazy_formatting (env, t, ip, CELL_FORMAT);
00510   case TABLE:
00511     return make_lazy_table (env, t, ip);
00512   case WITH:
00513     return make_lazy_with (env, t, ip);
00514   case ARG:
00515     return make_lazy_argument (env, t, ip);
00516   case MARK:
00517     return make_lazy_mark (env, t, ip);
00518   case EXPAND_AS:
00519     return make_lazy_expand_as (env, t, ip);
00520   case EVAL:
00521   case QUASI:
00522     return make_lazy_eval (env, t, ip);
00523   case COMPOUND:
00524     return make_lazy_compound (env, t, ip);
00525   case EXTERN:
00526     return make_lazy_rewrite (env, t, ip);
00527   case INCLUDE:
00528     return make_lazy_rewrite (env, t, ip);
00529   case STYLE_ONLY:
00530   case VAR_STYLE_ONLY:
00531   case ACTIVE:
00532   case VAR_ACTIVE:
00533     return make_lazy_compound (env, t, ip);
00534   case INACTIVE:
00535     return make_lazy_auto (env, t, ip, inactive_m);
00536   case VAR_INACTIVE:
00537     return make_lazy_auto (env, t, ip, var_inactive_m);
00538   case REWRITE_INACTIVE:
00539     return make_lazy_rewrite (env, t, ip);
00540   case LOCUS:
00541     return make_lazy_locus (env, t, ip);
00542   case HLINK:
00543   case ACTION:
00544     return make_lazy_compound (env, t, ip);
00545   case CANVAS:
00546     return make_lazy_canvas (env, t, ip);
00547   case ORNAMENT:
00548     return make_lazy_ornament (env, t, ip);
00549   default:
00550     if (L(t) < START_EXTENSIONS) return make_lazy_paragraph (env, t, ip);
00551     else return make_lazy_compound (env, t, ip);
00552   }
00553 }