1
2 /******************************************************************************
3 * MODULE : concat_macro.cpp
4 * DESCRIPTION: Typesetting markup around macro expansion mechanisms
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 "concater.hpp"
13
14 /******************************************************************************
15 * Typesetting environment changes
16 ******************************************************************************/
17
18 void
typeset_assign(tree t,path ip)19 concater_rep::typeset_assign (tree t, path ip) {
20 if (N(t) != 2) { typeset_error (t, ip); return; }
21 tree r= env->exec (t[0]);
22 if (!is_atomic (r)) return;
23 string var= r->label;
24 env->assign (var, copy (t[1]));
25 if (env->var_type [var] == Env_Paragraph)
26 control (tuple ("env_par", var, env->read (var)), ip);
27 else if (env->var_type [var] == Env_Page)
28 control (tuple ("env_page", var, env->read (var)), ip);
29 else control (t, ip);
30 }
31
32 void
typeset_with(tree t,path ip)33 concater_rep::typeset_with (tree t, path ip) {
34 int i, n= N(t), k= (n-1)>>1; // is k=0 allowed ?
35 if ((n&1) != 1) { typeset_error (t, ip); return; }
36
37 STACK_NEW_ARRAY(vars,string,k);
38 STACK_NEW_ARRAY(oldv,tree,k);
39 STACK_NEW_ARRAY(newv,tree,k);
40 for (i=0; i<k; i++) {
41 tree var_t= env->exec (t[i<<1]);
42 if (is_atomic (var_t)) {
43 string var= var_t->label;
44 vars[i]= var;
45 oldv[i]= env->read (var);
46 newv[i]= env->exec (t[(i<<1)+1]);
47 }
48 else {
49 STACK_DELETE_ARRAY(vars);
50 STACK_DELETE_ARRAY(oldv);
51 STACK_DELETE_ARRAY(newv);
52 return;
53 }
54 }
55
56 marker (descend (ip, 0));
57 // for (i=0; i<k; i++) env->monitored_write_update (vars[i], newv[i]);
58 for (i=0; i<k; i++) env->write_update (vars[i], newv[i]);
59 typeset (t[n-1], descend (ip, n-1));
60 for (i=k-1; i>=0; i--) env->write_update (vars[i], oldv[i]);
61 marker (descend (ip, 1));
62 STACK_DELETE_ARRAY(vars);
63 STACK_DELETE_ARRAY(oldv);
64 STACK_DELETE_ARRAY(newv);
65 }
66
67 void
typeset_compound(tree t,path ip)68 concater_rep::typeset_compound (tree t, path ip) {
69 int d; tree f;
70 if (L(t) == COMPOUND) {
71 if (N(t) == 0) { typeset_error (t, ip); return; }
72 d= 1;
73 f= t[0];
74 if (is_compound (f)) f= env->exec (f);
75 if (is_atomic (f)) {
76 string var= f->label;
77 if (!env->provides (var)) {
78 typeset_error (t, ip);
79 return;
80 }
81 f= env->read (var);
82 }
83 }
84 else {
85 string var= as_string (L(t));
86 if (!env->provides (var)) {
87 typeset_error (t, ip);
88 return;
89 }
90 d= 0;
91 f= env->read (var);
92 }
93
94 if (is_applicable (f)) {
95 int i, n=N(f)-1, m=N(t)-d;
96 env->macro_arg= list<hashmap<string,tree> > (
97 hashmap<string,tree> (UNINIT), env->macro_arg);
98 env->macro_src= list<hashmap<string,path> > (
99 hashmap<string,path> (path (DECORATION)), env->macro_src);
100 if (L(f) == XMACRO) {
101 if (is_atomic (f[0])) {
102 string var= f[0]->label;
103 env->macro_arg->item (var)= t;
104 env->macro_src->item (var)= ip;
105 }
106 }
107 else for (i=0; i<n; i++)
108 if (is_atomic (f[i])) {
109 string var= f[i]->label;
110 env->macro_arg->item (var)=
111 i<m? t[i+d]: attach_dip (tree (UNINIT), decorate_right(ip));
112 env->macro_src->item (var)= i<m? descend (ip,i+d): decorate_right(ip);
113 }
114 if (is_decoration (ip))
115 typeset (attach_here (f[n], ip));
116 else {
117 /*IF_NON_CHILD_ENFORCING(t)*/ marker (descend (ip, 0));
118 typeset (attach_right (f[n], ip));
119 /*IF_NON_CHILD_ENFORCING(t)*/ marker (descend (ip, 1));
120 }
121 env->macro_arg= env->macro_arg->next;
122 env->macro_src= env->macro_src->next;
123 }
124 else {
125 if (is_decoration (ip)) typeset (attach_here (f, ip));
126 else {
127 /*IF_NON_CHILD_ENFORCING(t)*/ marker (descend (ip, 0));
128 typeset (attach_right (f, ip));
129 /*IF_NON_CHILD_ENFORCING(t)*/ marker (descend (ip, 1));
130 }
131 }
132 }
133
134 void
typeset_auto(tree t,path ip,tree f)135 concater_rep::typeset_auto (tree t, path ip, tree f) {
136 env->macro_arg= list<hashmap<string,tree> > (
137 hashmap<string,tree> (UNINIT), env->macro_arg);
138 env->macro_src= list<hashmap<string,path> > (
139 hashmap<string,path> (path (DECORATION)), env->macro_src);
140 string var= f[0]->label;
141 env->macro_arg->item (var)= t;
142 env->macro_src->item (var)= ip;
143 typeset (attach_right (f[1], ip));
144 env->macro_arg= env->macro_arg->next;
145 env->macro_src= env->macro_src->next;
146 }
147
148 void
typeset_include(tree t,path ip)149 concater_rep::typeset_include (tree t, path ip) {
150 if (N(t) != 1) { typeset_error (t, ip); return; }
151 url file_name= url_unix (env->exec_string (t[0]));
152 url incl_file= relative (env->base_file_name, file_name);
153 tree incl= load_inclusion (incl_file);
154 url save_name= env->cur_file_name;
155 env->cur_file_name= incl_file;
156 env->secure= is_secure (env->cur_file_name);
157 typeset_dynamic (incl, ip);
158 env->cur_file_name= save_name;
159 env->secure= is_secure (env->cur_file_name);
160 }
161
162 void
typeset_drd_props(tree t,path ip)163 concater_rep::typeset_drd_props (tree t, path ip) {
164 (void) env->exec (t);
165 flag ("drd-properties", ip, brown);
166 control (t, ip);
167 }
168
169 void
typeset_eval(tree t,path ip)170 concater_rep::typeset_eval (tree t, path ip) {
171 if (N(t) != 1) { typeset_error (t, ip); return; }
172 tree r= env->exec (t[0]);
173 typeset_dynamic (r, ip);
174 }
175
176 void
typeset_value(tree t,path ip)177 concater_rep::typeset_value (tree t, path ip) {
178 // cout << "Value " << t << ", " << ip << "\n";
179 if (N(t) != 1) { typeset_error (t, ip); return; }
180 tree r= env->exec (t[0]);
181 if (is_compound (r)) {
182 typeset_error (t, ip);
183 return;
184 }
185 string name= r->label;
186 if (!env->provides (name)) {
187 typeset_error (t, ip);
188 return;
189 }
190 typeset_dynamic (env->read (name), ip);
191 }
192
193 void
typeset_argument(tree t,path ip)194 concater_rep::typeset_argument (tree t, path ip) {
195 // cout << "Argument " << t << ", " << ip << "\n";
196 if (N(t) == 0) { typeset_error (t, ip); return; }
197 tree r= t[0];
198 if (is_compound (r) ||
199 is_nil (env->macro_arg) ||
200 (!env->macro_arg->item->contains (r->label)))
201 {
202 typeset_error (t, ip);
203 return;
204 }
205
206 string name = r->label;
207 tree value= env->macro_arg->item [name];
208 path valip= decorate_right (ip);
209 if (!is_func (value, BACKUP)) {
210 path new_valip= env->macro_src->item [name];
211 if (is_accessible (new_valip)) valip= new_valip;
212 }
213 // cout << "Src " << name << "=\t " << valip << "\n";
214
215 marker (descend (ip, 0));
216 list<hashmap<string,tree> > old_var= env->macro_arg;
217 list<hashmap<string,path> > old_src= env->macro_src;
218 if (!is_nil (env->macro_arg)) env->macro_arg= env->macro_arg->next;
219 if (!is_nil (env->macro_src)) env->macro_src= env->macro_src->next;
220
221 if (N(t) > 1) {
222 int i, n= N(t);
223 for (i=1; i<n; i++) {
224 tree r= env->exec (t[i]);
225 if (!is_int (r)) {
226 value= tree (ERROR, "arg " * name);
227 valip= decorate_right (ip);
228 break;
229 }
230 int nr= as_int (r);
231 if ((!is_compound (value)) || (nr<0) || (nr>=N(value))) {
232 value= tree (ERROR, "arg " * name);
233 valip= decorate_right (ip);
234 break;
235 }
236 value= value[nr];
237 valip= descend (valip, nr);
238 }
239 }
240 typeset (attach_here (value, valip));
241
242 env->macro_arg= old_var;
243 env->macro_src= old_src;
244 marker (descend (ip, 1));
245 }
246
247 void
typeset_eval_args(tree t,path ip)248 concater_rep::typeset_eval_args (tree t, path ip) {
249 if (N(t) != 1) { typeset_error (t, ip); return; }
250 marker (descend (ip, 0));
251 typeset_inactive (attach_right (env->exec (t), ip));
252 marker (descend (ip, 1));
253 }
254
255 void
typeset_mark(tree t,path ip)256 concater_rep::typeset_mark (tree t, path ip) {
257 // cout << "Mark: " << t << ", " << ip << "\n\n";
258 if (N(t) != 2) { typeset_error (t, ip); return; }
259 if (is_func (t[0], ARG) &&
260 is_atomic (t[0][0]) &&
261 (!is_nil (env->macro_arg)) &&
262 env->macro_arg->item->contains (t[0][0]->label))
263 {
264 string name = t[0][0]->label;
265 tree value= env->macro_arg->item [name];
266 path valip= decorate_right (ip);
267 if (!is_func (value, BACKUP)) {
268 path new_valip= env->macro_src->item [name];
269 if (is_accessible (new_valip)) valip= new_valip;
270 }
271 // cout << "Src " << name << "=\t " << valip << "\n";
272
273 if (N(t[0]) > 1) {
274 int i, n= N(t[0]);
275 for (i=1; i<n; i++) {
276 tree r= env->exec (t[0][i]);
277 if (!is_int (r)) break;
278 int nr= as_int (r);
279 if ((!is_compound (value)) || (nr<0) || (nr>=N(value))) break;
280 value= value[nr];
281 valip= descend (valip, nr);
282 }
283 }
284
285 marker (descend (valip, 0));
286 typeset (t[1], descend (ip, 1));
287 marker (descend (valip, right_index (value)));
288 }
289 else typeset (t[1], descend (ip, 1));
290 }
291
292 void
typeset_expand_as(tree t,path ip)293 concater_rep::typeset_expand_as (tree t, path ip) {
294 // cout << "Mark: " << t << ", " << ip << "\n\n";
295 if (N(t) != 2) { typeset_error (t, ip); return; }
296 marker (descend (ip, 0));
297 typeset (t[1], descend (ip, 1));
298 marker (descend (ip, 1));
299 }
300
301 void
typeset_executable(tree t,path ip)302 concater_rep::typeset_executable (tree t, path ip) {
303 tree r= env->exec (t);
304 typeset_dynamic (r, ip);
305 }
306
307 void
typeset_rewrite(tree t,path ip)308 concater_rep::typeset_rewrite (tree t, path ip) {
309 tree r= env->rewrite (t);
310 typeset_dynamic (r, ip);
311 }
312
313 void
typeset_dynamic(tree t,path ip)314 concater_rep::typeset_dynamic (tree t, path ip) {
315 // ATTENTION: in the future, the ip should still be passed to
316 // this routine, since the typesetting depends on whether ip
317 // is a decoration or not
318
319 // cout << "Dynamic " << t << ", " << ip << "\n";
320 if (is_decoration (ip)) {
321 typeset (attach_here (t, ip));
322 return;
323 }
324
325 marker (descend (ip, 0));
326 // int start= N(a);
327 typeset (attach_right (t, ip));
328 // int end= N(a), i;
329
330 /* Old style unaccessible text, using left and middle decorations
331 SI total= 0, half= 0, mid;
332 for (i=start; i<end; i++)
333 total += a[i]->b->w();
334 for (mid=start; mid<end; mid++) {
335 half += a[mid]->b->w();
336 if (half >= (total>>1)) break;
337 }
338 for (i=start; i<mid; i++)
339 a[i]->b->relocate (decorate_left (ip));
340 if (i<end) {
341 if (a[i]->b->decoration ())
342 if ((a[i]->type==STD_ITEM) ||
343 (a[i]->type == MARKER_ITEM) ||
344 (a[i]->type==STRING_ITEM))
345 a[i]->b= macro_box (decorate_right (ip), a[i]->b);
346 a[i]->b->relocate (decorate_middle (ip));
347 i++;
348 }
349 */
350
351 marker (descend (ip, 1));
352
353 /*
354 for (i=start-1; i<end+1; i++)
355 cout << i << ": " << a[i]->b
356 << ", " << a[i]->b->find_lip ()
357 << ", " << a[i]->b->find_rip () << "\n";
358 */
359
360 /*
361 for (i=start; i<end; i++)
362 cout << i << ": " << a[i]->b << ", " << a[i]->b->ip << "\n";
363 */
364 }
365
366 void
typeset_range(tree t,path ip)367 concater_rep::typeset_range (tree t, path ip) {
368 if (N(t) != 3) { typeset_error (t, ip); return; }
369 tree t1= env->exec (t[0]);
370 tree t2= env->exec (t[1]);
371 tree t3= env->exec (t[2]);
372 if (!(is_int (t2) && is_int (t3)))
373 typeset_dynamic (tree (ERROR, "bad range"), ip);
374 else if (is_compound (t1)) {
375 if (is_tuple (t1)) {
376 int i1= max (0, as_int (t2));
377 int i2= min (N (t1), as_int (t3));
378 i2 = max (i1, i2);
379 typeset_dynamic (t1 (i1, i2), ip);
380 }
381 else typeset_dynamic (tree (ERROR, "bad range"), ip);
382 }
383 else {
384 int i1= max (0, as_int (t2));
385 int i2= min (N(t1->label), as_int (t3));
386 i2 = max (i1, i2);
387 path ip1= obtain_ip (t1);
388 if (is_decoration (ip1))
389 typeset_dynamic (t1->label (i1, i2), ip);
390 else {
391 marker (descend (ip, 0));
392 if (env->mode == 1)
393 typeset_text_string (t1->label, ip1, i1, i2);
394 else if (env->mode == 2)
395 typeset_math_string (t1->label, ip1, i1, i2);
396 else if (env->mode == 3)
397 typeset_prog_string (t1 , ip1, i1, i2);
398 else
399 typeset_text_string (t1->label, ip1, i1, i2);
400 marker (descend (ip, 1));
401 }
402 }
403 }
404