PageRenderTime 73ms CodeModel.GetById 37ms app.highlight 32ms RepoModel.GetById 1ms app.codeStats 0ms

/TeXmacs-1.0.7.11-src/src/Typeset/Line/lazy_typeset.cpp

#
C++ | 545 lines | 425 code | 53 blank | 67 comment | 95 complexity | 3fa671be22c5768d9f37df3ccdf66db4 MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0, MPL-2.0-no-copyleft-exception
  1
  2/******************************************************************************
  3* MODULE     : lazy_typeset.cpp
  4* DESCRIPTION: Lazy typesetting of various primitives
  5* COPYRIGHT  : (C) 1999  Joris van der Hoeven
  6*******************************************************************************
  7* This software falls under the GNU general public license version 3 or later.
  8* It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
  9* in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
 10******************************************************************************/
 11
 12#include "Line/lazy_typeset.hpp"
 13#include "Line/lazy_vstream.hpp"
 14#include "Format/format.hpp"
 15#include "Stack/stacker.hpp"
 16#include "Boxes/construct.hpp"
 17#include "analyze.hpp"
 18#include "packrat.hpp"
 19
 20array<line_item> typeset_marker (edit_env env, path ip);
 21array<line_item> typeset_concat (edit_env, tree t, path ip);
 22array<line_item> join (array<line_item> a, array<line_item> b);
 23lazy make_lazy_paragraph (edit_env env, tree t, path ip);
 24lazy make_lazy_table (edit_env env, tree t, path ip);
 25lazy make_lazy_canvas (edit_env env, tree t, path ip);
 26lazy make_lazy_ornament (edit_env env, tree t, path ip);
 27
 28/******************************************************************************
 29* Documents
 30******************************************************************************/
 31
 32lazy_document_rep::lazy_document_rep (edit_env env, tree t, path ip):
 33  lazy_rep (LAZY_DOCUMENT, ip), par (N(t))
 34{
 35  int i, n= N(t);
 36  for (i=0; i<n; i++)
 37    par[i]= make_lazy (env, t[i], descend (ip, i));
 38}
 39
 40format
 41lazy_document_rep::query (lazy_type request, format fm) {
 42  if ((request == LAZY_BOX) && (fm->type == QUERY_VSTREAM_WIDTH)) {
 43    query_vstream_width qvw= (query_vstream_width) fm;
 44    array<line_item> before= qvw->before;
 45    array<line_item> after = qvw->after;
 46
 47    SI w= 1;
 48    int i, n= N(par);
 49    for (i=0; i<n; i++) {
 50      format tmp_fm= make_query_vstream_width (
 51        i==0  ? before: array<line_item> (),
 52	i==n-1? after : array<line_item> ());
 53      format ret_fm= par[i]->query (request, tmp_fm);
 54      format_width fmw= (format_width) ret_fm;
 55      w= max (w, fmw->width);
 56    }
 57    return make_format_width (w);
 58  }
 59  return lazy_rep::query (request, fm);
 60}
 61
 62lazy
 63lazy_document_rep::produce (lazy_type request, format fm) {
 64  if (request == type) return this;
 65  if (request == LAZY_VSTREAM) {
 66    int i, n= N(par);
 67    SI width= 1;
 68    array<line_item> before;
 69    array<line_item> after;
 70    if (fm->type == FORMAT_VSTREAM) {
 71      format_vstream fs= (format_vstream) fm;
 72      width = fs->width ;
 73      before= fs->before;
 74      after = fs->after ;
 75    }
 76    array<page_item> l;
 77    stack_border     sb;
 78    for (i=0; i<n; i++) {
 79      format tmp_fm= make_format_vstream (width,
 80        i==0  ? before: array<line_item> (),
 81	i==n-1? after : array<line_item> ());
 82      lazy tmp= par[i]->produce (request, tmp_fm);
 83      lazy_vstream tmp_vs= (lazy_vstream) tmp;
 84      if (i == 0) {
 85	l = tmp_vs->l ;
 86	sb= tmp_vs->sb;
 87      }
 88      else merge_stack (l, sb, tmp_vs->l, tmp_vs->sb);
 89    }
 90    return lazy_vstream (ip, "", l, sb);
 91  }
 92  return lazy_rep::produce (request, fm);
 93}
 94
 95/******************************************************************************
 96* Surround
 97******************************************************************************/
 98
 99lazy_surround_rep::lazy_surround_rep (edit_env env, tree t, path ip):
100  lazy_rep (LAZY_SURROUND, ip)
101{
102  a  = typeset_concat (env, t[0], descend (ip, 0));
103  b  = typeset_concat (env, t[1], descend (ip, 1));
104  par= make_lazy (env, t[2], descend (ip, 2));
105}
106
107lazy_surround_rep::lazy_surround_rep (
108  array<line_item> a2, array<line_item> b2, lazy par2, path ip):
109  lazy_rep (LAZY_SURROUND, ip), a (a2), b (b2), par (par2) {}
110
111format
112lazy_surround_rep::query (lazy_type request, format fm) {
113  if ((request == LAZY_BOX) && (fm->type == QUERY_VSTREAM_WIDTH)) {
114    query_vstream_width qvw= (query_vstream_width) fm;
115    array<line_item> before= qvw->before;
116    array<line_item> after = qvw->after;
117    if (N(a) != 0) before= join (before, a);
118    if (N(b) != 0) after = join (b, after);
119    format tmp_fm= make_query_vstream_width (before, after);
120    return par->query (request, tmp_fm);
121  }
122  return lazy_rep::query (request, fm);
123}
124
125lazy
126lazy_surround_rep::produce (lazy_type request, format fm) {
127  if (request == type) return this;
128  if (request == LAZY_VSTREAM) {
129    SI               width = 1;
130    array<line_item> before= a;
131    array<line_item> after = b;
132    if (fm->type == FORMAT_VSTREAM) {
133      format_vstream fs= (format_vstream) fm;
134      width = fs->width ;
135      before= join (fs->before, before);
136      after = join (after, fs->after);
137    }
138    format ret_fm= make_format_vstream (width, before, after);
139    return par->produce (request, ret_fm);
140  }
141  return lazy_rep::produce (request, fm);
142}
143
144/******************************************************************************
145* Hidden
146******************************************************************************/
147
148lazy
149make_lazy_hidden (edit_env env, tree t, path ip) {
150  (void) make_lazy (env, t[0], descend (ip, 0));
151  return lazy_document (env, tree (DOCUMENT), ip);
152}
153
154/******************************************************************************
155* Formatting
156******************************************************************************/
157
158lazy
159make_lazy_formatting (edit_env env, tree t, path ip, string v) {
160  int last= N(t)-1;
161  tree new_format= env->read (v) * t (0, last);
162  tree old_format= env->local_begin (v, new_format);
163  array<line_item> a;
164  array<line_item> b;
165  if (v != CELL_FORMAT) {
166    a= typeset_marker (env, descend (ip, 0));
167    b= typeset_marker (env, descend (ip, 1));
168  }
169  lazy par= make_lazy (env, t[last], descend (ip, last));
170  env->local_end (v, old_format);
171  return lazy_surround (a, b, par, ip);
172}
173
174/******************************************************************************
175* With
176******************************************************************************/
177
178lazy
179make_lazy_with (edit_env env, tree t, path ip) {
180  int last= N(t)-1;
181  int i, k= last>>1; // is k=0 allowed ?
182  // if ((last&1) != 0) return;
183  
184  STACK_NEW_ARRAY(vars,string,k);
185  STACK_NEW_ARRAY(oldv,tree,k);
186  STACK_NEW_ARRAY(newv,tree,k);
187  for (i=0; i<k; i++) {
188    tree var_t= env->exec (t[i<<1]);
189    if (is_atomic (var_t)) {
190      string var= var_t->label;
191      vars[i]= var;
192      oldv[i]= env->read (var);
193      newv[i]= env->exec (t[(i<<1)+1]);
194    }
195    /*
196    else {
197      STACK_DELETE_ARRAY(vars);
198      STACK_DELETE_ARRAY(oldv);
199      STACK_DELETE_ARRAY(newv);
200      return;
201    }
202    */
203  }
204
205  // for (i=0; i<k; i++) env->monitored_write_update (vars[i], newv[i]);
206  for (i=0; i<k; i++) env->write_update (vars[i], newv[i]);
207  array<line_item> a= typeset_marker (env, descend (ip, 0));
208  array<line_item> b= typeset_marker (env, descend (ip, 1));
209  lazy par= make_lazy (env, t[last], descend (ip, last));
210  for (i=k-1; i>=0; i--) env->write_update (vars[i], oldv[i]);
211  STACK_DELETE_ARRAY(vars);
212  STACK_DELETE_ARRAY(oldv);
213  STACK_DELETE_ARRAY(newv);
214  return lazy_surround (a, b, par, ip);
215}
216
217/******************************************************************************
218* Compound
219******************************************************************************/
220
221lazy
222make_lazy_compound (edit_env env, tree t, path ip) {
223  int d; tree f;
224  if (L(t) == COMPOUND) {
225    d= 1;
226    f= t[0];
227    if (is_compound (f)) f= env->exec (f);
228    if (is_atomic (f)) {
229      string var= f->label;
230      if (env->provides (var)) f= env->read (var);
231      else f= tree (ERROR, "compound " * var);
232    }
233  }
234  else {
235    string var= as_string (L(t));
236    if (env->provides (var)) f= env->read (var);
237    else f= tree (ERROR, "compound " * var);
238    d= 0;
239  }
240
241  array<line_item> a;
242  array<line_item> b;
243  if (/*NON_CHILD_ENFORCING(t)&&*/ (!is_decoration (ip))) {
244    a= typeset_marker (env, descend (ip, 0));
245    b= typeset_marker (env, descend (ip, 1));
246  }
247  lazy par;
248
249  if (is_applicable (f)) {
250    int i, n=N(f)-1, m=N(t)-d;
251    env->macro_arg= list<hashmap<string,tree> > (
252      hashmap<string,tree> (UNINIT), env->macro_arg);
253    env->macro_src= list<hashmap<string,path> > (
254      hashmap<string,path> (path (DECORATION)), env->macro_src);
255    if (L(f) == XMACRO) {
256      if (is_atomic (f[0])) {
257	string var= f[0]->label;
258	env->macro_arg->item (var)= t;
259	env->macro_src->item (var)= ip;
260      }
261    }
262    else for (i=0; i<n; i++)
263      if (is_atomic (f[i])) {
264	string var= f[i]->label;
265	env->macro_arg->item (var)=
266	  i<m? t[i+d]: attach_dip (tree (UNINIT), decorate_right(ip));
267	env->macro_src->item (var)= i<m? descend (ip,i+d): decorate_right(ip);
268      }
269    if (is_decoration (ip)) par= make_lazy (env, attach_here (f[n], ip));
270    else par= make_lazy (env, attach_right (f[n], ip));
271    env->macro_arg= env->macro_arg->next;
272    env->macro_src= env->macro_src->next;
273  }
274  else {
275    if (is_decoration (ip)) par= make_lazy (env, attach_here (f, ip));
276    else par= make_lazy (env, attach_right (f, ip));
277  }
278  return lazy_surround (a, b, par, ip);
279}
280
281/******************************************************************************
282* Rewrite
283******************************************************************************/
284
285lazy
286make_lazy_rewrite (edit_env env, tree t, path ip) {
287  tree r= env->rewrite (t);
288  array<line_item> a= typeset_marker (env, descend (ip, 0));
289  array<line_item> b= typeset_marker (env, descend (ip, 1));
290  lazy par= make_lazy (env, attach_right (r, ip));
291  return lazy_surround (a, b, par, ip);
292}
293
294/******************************************************************************
295* Eval
296******************************************************************************/
297
298lazy
299make_lazy_eval (edit_env env, tree t, path ip) {
300  tree r= env->exec (is_func (t, EVAL, 1)? t[0]: tree (QUASIQUOTE, t[0]));
301  array<line_item> a= typeset_marker (env, descend (ip, 0));
302  array<line_item> b= typeset_marker (env, descend (ip, 1));
303  lazy par= make_lazy (env, attach_right (r, ip));
304  return lazy_surround (a, b, par, ip);
305}
306
307/******************************************************************************
308* Auto
309******************************************************************************/
310
311lazy
312make_lazy_auto (edit_env env, tree t, path ip, tree f) {
313  array<line_item> a;
314  array<line_item> b;
315  if (!is_decoration (ip)) {
316    a= typeset_marker (env, descend (ip, 0));
317    b= typeset_marker (env, descend (ip, 1));
318  }
319
320  lazy par;
321  env->macro_arg= list<hashmap<string,tree> > (
322    hashmap<string,tree> (UNINIT), env->macro_arg);
323  env->macro_src= list<hashmap<string,path> > (
324    hashmap<string,path> (path (DECORATION)), env->macro_src);
325  string var= f[0]->label;
326  env->macro_arg->item (var)= t;
327  env->macro_src->item (var)= ip;
328  if (is_decoration (ip)) par= make_lazy (env, attach_here (f[1], ip));
329  else par= make_lazy (env, attach_right (f[1], ip));
330  env->macro_arg= env->macro_arg->next;
331  env->macro_src= env->macro_src->next;
332
333  return lazy_surround (a, b, par, ip);
334}
335
336/******************************************************************************
337* Argument
338******************************************************************************/
339
340lazy
341make_lazy_argument (edit_env env, tree t, path ip) {
342  string name;
343  tree   value;
344  path   valip= decorate_right (ip);
345
346  tree r= t[0];
347  if (is_compound (r)) value= tree (ERROR, "value");
348  else {
349    name = r->label;
350    if ((!is_nil (env->macro_arg)) && env->macro_arg->item->contains (r->label)) {
351      value= env->macro_arg->item [name];
352      if (!is_func (value, BACKUP)) {
353	path new_valip= env->macro_src->item [name];
354	if (is_accessible (new_valip)) valip= new_valip;
355      }
356    }
357    else value= tree (ERROR, "value " * name);
358  }
359
360  array<line_item> a= typeset_marker (env, descend (ip, 0));
361  array<line_item> b= typeset_marker (env, descend (ip, 1));
362  list<hashmap<string,tree> > old_var= env->macro_arg;
363  list<hashmap<string,path> > old_src= env->macro_src;
364  if (!is_nil (env->macro_arg)) env->macro_arg= env->macro_arg->next;
365  if (!is_nil (env->macro_src)) env->macro_src= env->macro_src->next;
366
367  if (N(t) > 1) {
368    int i, n= N(t);
369    for (i=1; i<n; i++) {
370      tree r= env->exec (t[i]);
371      if (!is_int (r)) break;
372      int nr= as_int (r);
373      if ((!is_compound (value)) || (nr<0) || (nr>=N(value))) break;
374      value= value[nr];
375      valip= descend (valip, nr);
376    }
377  }
378  lazy par= make_lazy (env, attach_here (value, valip));
379
380  env->macro_arg= old_var;
381  env->macro_src= old_src;
382  return lazy_surround (a, b, par, ip);
383}
384
385/******************************************************************************
386* Mark and expand_as
387******************************************************************************/
388
389lazy
390make_lazy_mark (edit_env env, tree t, path ip) {
391  // cout << "Lazy mark: " << t << ", " << ip << "\n";
392  array<line_item> a= typeset_marker (env, descend (ip, 0));
393  array<line_item> b= typeset_marker (env, descend (ip, 1));
394
395  if (is_func (t[0], ARG) &&
396      is_atomic (t[0][0]) &&
397      (!is_nil (env->macro_arg)) &&
398      env->macro_arg->item->contains (t[0][0]->label))
399    {
400      string name = t[0][0]->label;
401      tree   value= env->macro_arg->item [name];
402      path   valip= decorate_right (ip);
403      if (!is_func (value, BACKUP)) {
404	path new_valip= env->macro_src->item [name];
405	if (is_accessible (new_valip)) valip= new_valip;
406      }
407
408      if (N(t[0]) > 1) {
409	int i, n= N(t[0]);
410	for (i=1; i<n; i++) {
411	  tree r= env->exec (t[0][i]);
412	  if (!is_int (r)) break;
413	  int nr= as_int (r);
414	  if ((!is_compound (value)) || (nr<0) || (nr>=N(value))) break;
415	  value= value[nr];
416	  valip= descend (valip, nr);
417	}
418      }
419      if (is_compound (value)) {
420	a= typeset_marker (env, descend (valip, 0));
421	b= typeset_marker (env, descend (valip, 1));
422      }
423    }
424
425  lazy par= make_lazy (env, t[1], descend (ip, 1));
426  return lazy_surround (a, b, par, ip);
427}
428
429lazy
430make_lazy_expand_as (edit_env env, tree t, path ip) {
431  array<line_item> a= typeset_marker (env, descend (ip, 0));
432  array<line_item> b= typeset_marker (env, descend (ip, 1));
433  lazy par= make_lazy (env, t[1], descend (ip, 1));
434  return lazy_surround (a, b, par, ip);
435}
436
437/******************************************************************************
438* Locus
439******************************************************************************/
440
441lazy
442make_lazy_locus (edit_env env, tree t, path ip) {
443  extern bool build_locus (edit_env env, tree t, list<string>& ids, string& c);
444  list<string> ids;
445  string col;
446  if (!build_locus (env, t, ids, col))
447    system_warning ("Ignored unaccessible loci");
448  int last= N(t)-1;
449  tree old_col= env->read (COLOR);
450  env->write_update (COLOR, col);
451  array<line_item> a= typeset_marker (env, descend (ip, 0));
452  array<line_item> b= typeset_marker (env, descend (ip, 1));
453  lazy par= make_lazy (env, t[last], descend (ip, last));
454  env->write_update (COLOR, old_col);
455  return lazy_surround (a, b, par, ip);
456}
457
458/******************************************************************************
459* Main routine
460******************************************************************************/
461
462static tree inactive_m
463  (MACRO, "x",
464   tree (REWRITE_INACTIVE, tree (ARG, "x", "0"), "once*"));
465static tree var_inactive_m
466  (MACRO, "x",
467   tree (REWRITE_INACTIVE, tree (ARG, "x", "0"), "recurse*"));
468
469lazy
470make_lazy (edit_env env, tree t, path ip) {
471  /*
472  if (is_accessible (ip)) {
473    if (obtain_ip (t) != ip)
474      cout << "TeXmacs] Wrong ip: " << t << "\n";
475  }
476  */
477
478  if (!is_accessible (ip)) {
479    path ip2= obtain_ip (t);
480    if (ip2 != path (DETACHED))
481      ip= ip2;
482  }
483
484  if (env->hl_lan != 0)
485    env->lan->highlight (t);
486
487  switch (L(t)) {
488  case DOCUMENT:
489    return lazy_document (env, t, ip);
490  case SURROUND:
491    return lazy_surround (env, t, ip);
492    //case HIDDEN:
493    //return make_lazy_hidden (env, t, ip);
494  case DATOMS:
495    return make_lazy_formatting (env, t, ip, ATOM_DECORATIONS);
496  case DLINES:
497    return make_lazy_formatting (env, t, ip, LINE_DECORATIONS);
498  case DPAGES:
499    return make_lazy_formatting (env, t, ip, PAGE_DECORATIONS);
500  case TFORMAT:
501    return make_lazy_formatting (env, t, ip, CELL_FORMAT);
502  case TABLE:
503    return make_lazy_table (env, t, ip);
504  case WITH:
505    return make_lazy_with (env, t, ip);
506  case ARG:
507    return make_lazy_argument (env, t, ip);
508  case MARK:
509    return make_lazy_mark (env, t, ip);
510  case EXPAND_AS:
511    return make_lazy_expand_as (env, t, ip);
512  case EVAL:
513  case QUASI:
514    return make_lazy_eval (env, t, ip);
515  case COMPOUND:
516    return make_lazy_compound (env, t, ip);
517  case EXTERN:
518    return make_lazy_rewrite (env, t, ip);
519  case INCLUDE:
520    return make_lazy_rewrite (env, t, ip);
521  case STYLE_ONLY:
522  case VAR_STYLE_ONLY:
523  case ACTIVE:
524  case VAR_ACTIVE:
525    return make_lazy_compound (env, t, ip);
526  case INACTIVE:
527    return make_lazy_auto (env, t, ip, inactive_m);
528  case VAR_INACTIVE:
529    return make_lazy_auto (env, t, ip, var_inactive_m);
530  case REWRITE_INACTIVE:
531    return make_lazy_rewrite (env, t, ip);
532  case LOCUS:
533    return make_lazy_locus (env, t, ip);
534  case HLINK:
535  case ACTION:
536    return make_lazy_compound (env, t, ip);
537  case CANVAS:
538    return make_lazy_canvas (env, t, ip);
539  case ORNAMENT:
540    return make_lazy_ornament (env, t, ip);
541  default:
542    if (L(t) < START_EXTENSIONS) return make_lazy_paragraph (env, t, ip);
543    else return make_lazy_compound (env, t, ip);
544  }
545}