/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}