1
2 /******************************************************************************
3 * MODULE : tree_brackets.cpp
4 * DESCRIPTION: upgrade to tree with matching brackets
5 * COPYRIGHT : (C) 2010 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 "tree_correct.hpp"
13 #include "tree_analyze.hpp"
14 #include "scheme.hpp"
15
16 static array<tree> upgrade_brackets (array<tree> a, int level);
17
18 /******************************************************************************
19 * Extra routines for symbol types
20 ******************************************************************************/
21
22 static bool
is_dubious_open_middle(array<int> tp,int j)23 is_dubious_open_middle (array<int> tp, int j) {
24 j--;
25 while (j >= 0 && (tp[j] == SYMBOL_SKIP || tp[j] == SYMBOL_SCRIPT))
26 j--;
27 return
28 j < 0 ||
29 tp[j] == SYMBOL_PREFIX ||
30 tp[j] == SYMBOL_INFIX ||
31 tp[j] == SYMBOL_SEPARATOR;
32 }
33
34 static bool
is_dubious_close_middle(array<int> tp,int j)35 is_dubious_close_middle (array<int> tp, int j) {
36 j++;
37 while (j < N(tp) && (tp[j] == SYMBOL_SKIP || tp[j] == SYMBOL_SCRIPT))
38 j++;
39 return
40 j >= N(tp) ||
41 tp[j] == SYMBOL_POSTFIX ||
42 tp[j] == SYMBOL_INFIX ||
43 tp[j] == SYMBOL_SEPARATOR;
44 }
45
46 static array<int>
downgrade_dubious(array<int> tp_in)47 downgrade_dubious (array<int> tp_in) {
48 array<int> tp= copy (tp_in);
49 // NOTE: we also might forbid combinations such as OPEN MIDDLE
50 for (int i=0; i<N(tp); i++)
51 if (tp[i] >= SYMBOL_PROBABLE_OPEN && tp[i] <= SYMBOL_PROBABLE_CLOSE) {
52 if (is_dubious_open_middle (tp, i)) {
53 if (tp[i] == SYMBOL_PROBABLE_MIDDLE) tp[i]= SYMBOL_DUBIOUS_MIDDLE;
54 if (tp[i] == SYMBOL_PROBABLE_CLOSE) tp[i]= SYMBOL_DUBIOUS_CLOSE;
55 }
56 if (is_dubious_close_middle (tp, i)) {
57 if (tp[i] == SYMBOL_PROBABLE_OPEN) tp[i]= SYMBOL_DUBIOUS_OPEN;
58 if (tp[i] == SYMBOL_PROBABLE_MIDDLE) tp[i]= SYMBOL_DUBIOUS_MIDDLE;
59 }
60 }
61 return tp;
62 }
63
64 static array<int>
upgrade_probable(array<int> tp_in)65 upgrade_probable (array<int> tp_in) {
66 array<int> tp= copy (tp_in);
67 for (int i=0; i<N(tp); i++)
68 if (tp[i] >= SYMBOL_PROBABLE_OPEN) {
69 int j= i-1;
70 while (j >= 0 && (tp[j] == SYMBOL_SKIP || tp[j] == SYMBOL_SCRIPT))
71 j--;
72 if (j < 0 ||
73 tp[j] == SYMBOL_PREFIX ||
74 tp[j] == SYMBOL_INFIX ||
75 tp[j] == SYMBOL_SEPARATOR)
76 tp[i]= SYMBOL_PROBABLE_OPEN;
77 j= i+1;
78 while (j < N(tp) && (tp[j] == SYMBOL_SKIP || tp[j] == SYMBOL_SCRIPT))
79 j++;
80 if (j >= N(tp) ||
81 tp[j] == SYMBOL_POSTFIX ||
82 tp[j] == SYMBOL_INFIX ||
83 tp[j] == SYMBOL_SEPARATOR)
84 tp[i]= SYMBOL_PROBABLE_CLOSE;
85 }
86 return tp;
87 }
88
89 static array<int>
confirm_all(array<int> tp_in)90 confirm_all (array<int> tp_in) {
91 array<int> tp= upgrade_probable (tp_in);
92 for (int i=0; i<N(tp); i++)
93 if (tp[i] == SYMBOL_PROBABLE_OPEN) tp[i]= SYMBOL_OPEN;
94 else if (tp[i] == SYMBOL_PROBABLE_MIDDLE) tp[i]= SYMBOL_MIDDLE;
95 else if (tp[i] == SYMBOL_PROBABLE_CLOSE) tp[i]= SYMBOL_CLOSE;
96 return tp;
97 }
98
99 static bool
admits_brackets(array<int> tp)100 admits_brackets (array<int> tp) {
101 for (int i=0; i<N(tp); i++)
102 if (tp[i] >= SYMBOL_OPEN) return true;
103 return false;
104 }
105
106 static bool
admits_bigops(array<int> tp)107 admits_bigops (array<int> tp) {
108 for (int i=0; i<N(tp); i++)
109 if (tp[i] == SYMBOL_OPEN_BIG) return true;
110 return false;
111 }
112
113 static array<tree>
replace_dummies(array<tree> a)114 replace_dummies (array<tree> a) {
115 array<tree> b (N(a));
116 for (int i=0; i<N(a); i++)
117 if (a[i] == "<cdot>") b[i]= "<cdummy>";
118 else b[i]= a[i];
119 return b;
120 }
121
122 /******************************************************************************
123 * Heuristic determination of several bracket notations
124 ******************************************************************************/
125
126 static array<int>
detect_french_interval(array<tree> a,array<int> tp_in)127 detect_french_interval (array<tree> a, array<int> tp_in) {
128 // NOTE: we might only allow [ and ]
129 array<int> tp= upgrade_probable (tp_in);
130 int last_open= -1, last_comma= -1;
131 for (int i=0; i<N(tp); i++)
132 if (tp[i] == SYMBOL_SEPARATOR) {
133 if (a[i] == "," && last_comma == -1) last_comma= i;
134 else last_open= last_comma= -1;
135 }
136 else if (tp[i] >= SYMBOL_OPEN) {
137 if (tp[i] == SYMBOL_OPEN || tp[i] == SYMBOL_PROBABLE_OPEN) {
138 last_open= i;
139 last_comma= -1;
140 }
141 else if (tp[i] == SYMBOL_CLOSE || tp[i] == SYMBOL_PROBABLE_CLOSE) {
142 if (last_open != -1 && last_comma != -1 && last_comma != i-1) {
143 tp[last_open]= SYMBOL_OPEN;
144 tp[i]= SYMBOL_CLOSE;
145 }
146 else last_open= last_comma= -1;
147 }
148 else if (tp[i] == SYMBOL_MIDDLE || tp[i] == SYMBOL_PROBABLE_MIDDLE);
149 else last_open= last_comma= -1;
150 }
151 return tp;
152 }
153
154 static array<int>
detect_absolute(array<tree> a,array<int> tp_in,bool insist)155 detect_absolute (array<tree> a, array<int> tp_in, bool insist) {
156 array<int> tp= upgrade_probable (tp_in);
157 //cout << " a = " << a << "\n";
158 //cout << " in= " << tp_in << "\n";
159 //cout << " tp= " << tp << "\n";
160 int last_open= -1;
161 for (int i=0; i<N(tp); i++)
162 if (tp[i] == SYMBOL_SEPARATOR) last_open= -1;
163 else if (tp[i] >= SYMBOL_OPEN) {
164 if (tp[i] == SYMBOL_PROBABLE_OPEN ||
165 (last_open == -1 && tp[i] == SYMBOL_PROBABLE_MIDDLE))
166 last_open= i;
167 else if (tp[i] == SYMBOL_PROBABLE_CLOSE ||
168 (last_open != -1 && tp[i] == SYMBOL_PROBABLE_MIDDLE))
169 {
170 if (last_open != -1 &&
171 a[i] == a[last_open] &&
172 ((tp[last_open] == SYMBOL_PROBABLE_OPEN) ||
173 (tp[i] == SYMBOL_PROBABLE_CLOSE) ||
174 //(i == last_open + 2 &&
175 //a[i-1] == "<cdot>") ||
176 (insist &&
177 !is_dubious_open_middle (tp, last_open) &&
178 !is_dubious_close_middle (tp, i))))
179 {
180 tp[last_open]= SYMBOL_OPEN;
181 tp[i]= SYMBOL_CLOSE;
182 last_open= -1;
183 }
184 else if (tp[i] == SYMBOL_PROBABLE_MIDDLE) last_open= i;
185 else last_open= -1;
186 }
187 else last_open= -1;
188 }
189 return tp;
190 }
191
192 static array<int>
detect_probable(array<tree> a,array<int> tp_in)193 detect_probable (array<tree> a, array<int> tp_in) {
194 array<int> tp= upgrade_probable (tp_in);
195 int last_open= -1;
196 for (int i=0; i<N(tp); i++)
197 if (tp[i] >= SYMBOL_OPEN) {
198 if (tp[i] == SYMBOL_OPEN || tp[i] == SYMBOL_PROBABLE_OPEN)
199 last_open= i;
200 else if (tp[i] == SYMBOL_CLOSE || tp[i] == SYMBOL_PROBABLE_CLOSE) {
201 if (last_open != -1) {
202 tp[last_open]= SYMBOL_OPEN;
203 tp[i]= SYMBOL_CLOSE;
204 }
205 else last_open= -1;
206 }
207 else if (tp[i] == SYMBOL_MIDDLE || tp[i] == SYMBOL_PROBABLE_MIDDLE);
208 else last_open= -1;
209 }
210 return tp;
211 }
212
213 /******************************************************************************
214 * Process matching brackets
215 ******************************************************************************/
216
217 static tree
make_small(tree br)218 make_small (tree br) {
219 if (is_atomic (br)) return br;
220 if (is_func (br, LEFT) ||
221 is_func (br, MID) ||
222 is_func (br, RIGHT) ||
223 is_func (br, BIG))
224 if (N(br) > 0 && is_atomic (br[0])) {
225 string s= br[0]->label;
226 if (s == ".") return "<nobracket>";
227 if (N(s) <= 1) return s;
228 return "<" * s * ">";
229 }
230 return "<nobracket>";
231 }
232
233 static tree
make_around(tree l,tree m,tree r)234 make_around (tree l, tree m, tree r) {
235 tree_label kind= VAR_AROUND;
236 if (is_atomic (l) && is_atomic (r)) kind= AROUND;
237 return tree (kind, make_small (l), m, make_small (r));
238 }
239
240 static tree
make_around(tree l,tree m)241 make_around (tree l, tree m) {
242 return tree (BIG_AROUND, make_small (l), m);
243 }
244
245 static array<tree>
simplify_matching(array<tree> a,array<int> tp_in,int level)246 simplify_matching (array<tree> a, array<int> tp_in, int level) {
247 //cout << "Simplify matching " << a << ", " << tp_in << "\n";
248 array<int> tp= copy (tp_in);
249 int last_open= -1;
250 for (int i=0; i<N(tp); i++) {
251 if (tp[i] == SYMBOL_OPEN) last_open= i;
252 else if (tp[i] >= SYMBOL_PROBABLE_OPEN) last_open= -1;
253 else if (tp[i] == SYMBOL_CLOSE && last_open != -1) {
254 array<tree> b= range (a, last_open+1, i);
255 b= upgrade_brackets (b, level+1);
256 tree body= concat_recompose (b);
257 a[last_open]= make_around (a[last_open], body, a[i]);
258 tp[last_open]= SYMBOL_BASIC;
259 for (int j= last_open+1; j<=i; j++) tp[j]= SYMBOL_DELETED;
260 last_open= -1;
261 }
262 }
263
264 array<tree> r;
265 for (int i=0; i<N(tp); i++)
266 if (tp[i] != SYMBOL_DELETED)
267 r << a[i];
268 return r;
269 }
270
271 static array<tree>
add_missing_left(array<tree> a,array<int> tp)272 add_missing_left (array<tree> a, array<int> tp) {
273 array<tree> b;
274 for (int i=0; i<N(tp); i++)
275 if (tp[i] == SYMBOL_CLOSE) {
276 tree body= concat_recompose (b);
277 b= array<tree> ();
278 if (is_atomic (a[i])) b << make_around ("<nobracket>", body, a[i]);
279 else b << make_around (tree (LEFT, "."), body, a[i]);
280 }
281 else b << a[i];
282 return b;
283 }
284
285 static array<tree>
add_missing_right(array<tree> a,array<int> tp)286 add_missing_right (array<tree> a, array<int> tp) {
287 array<tree> b;
288 for (int i=N(tp)-1; i>=0; i--)
289 if (tp[i] == SYMBOL_OPEN) {
290 tree body= concat_recompose (reverse (b));
291 b= array<tree> ();
292 if (is_atomic (a[i])) b << make_around (a[i], body, "<nobracket>");
293 else b << make_around (a[i], body, tree (RIGHT, "."));
294 }
295 else b << a[i];
296 return reverse (b);
297 }
298
299 /******************************************************************************
300 * Splitting concats with big operators
301 ******************************************************************************/
302
303 static array<tree>
prefix_split(array<tree> a,array<int> tp,int level)304 prefix_split (array<tree> a, array<int> tp, int level) {
305 for (int i=1; i<N(tp); i++)
306 if (tp[i] == SYMBOL_OPEN_BIG) {
307 array<tree> r= range (a, 0, i);
308 r << upgrade_brackets (range (a, i, N(tp)), level);
309 return r;
310 }
311 return a;
312 }
313
314 static array<tree>
infix_split(array<tree> a,array<int> tp_in,array<int> pri,int level)315 infix_split (array<tree> a, array<int> tp_in, array<int> pri, int level) {
316 array<int> tp= upgrade_probable (tp_in);
317 int weakest= PRIORITY_RADICAL;
318 for (int i=0; i<N(tp); i++)
319 if (tp[i] == SYMBOL_OPEN_BIG)
320 weakest= min (weakest, pri[i]);
321 else if (tp[i] == SYMBOL_INFIX ||
322 tp[i] == SYMBOL_SEPARATOR ||
323 tp[i] == SYMBOL_MIDDLE ||
324 tp[i] == SYMBOL_PROBABLE_MIDDLE)
325 if (pri[i] <= weakest) {
326 array<tree> r= upgrade_brackets (range (a, 0, i), level);
327 r << range (a, i, i+1);
328 r << upgrade_brackets (range (a, i+1, N(a)), level);
329 return r;
330 }
331 return a;
332 }
333
334 static array<tree>
postfix_split(array<tree> a,array<int> tp_in,int level)335 postfix_split (array<tree> a, array<int> tp_in, int level) {
336 array<int> tp= upgrade_probable (tp_in);
337 int i= N(a);
338 while (i>0 &&
339 (tp[i-1] == SYMBOL_PREFIX ||
340 tp[i-1] == SYMBOL_INFIX ||
341 tp[i-1] == SYMBOL_SEPARATOR ||
342 tp[i-1] == SYMBOL_OPEN ||
343 tp[i-1] == SYMBOL_MIDDLE ||
344 tp[i-1] == SYMBOL_PROBABLE_OPEN ||
345 tp[i-1] == SYMBOL_PROBABLE_MIDDLE ||
346 tp[i-1] == SYMBOL_SKIP ||
347 a[i-1] == "."))
348 i--;
349 if (i != N(a)) {
350 array<tree> r= upgrade_brackets (range (a, 0, i), level);
351 r << range (a, i, N(a));
352 return r;
353 }
354 return a;
355 }
356
357 /******************************************************************************
358 * Extra subroutines for big operators
359 ******************************************************************************/
360
361 static bool
is_concat_big(tree t)362 is_concat_big (tree t) {
363 if (!is_concat (t) || N(t) == 0 || !is_func (t[0], BIG)) return false;
364 for (int i=1; i<N(t); i++)
365 if (!is_func (t[i], RSUB, 1) && !is_func (t[i], RSUP, 1))
366 return false;
367 return true;
368 }
369
370 tree
upgrade_above_below(tree t)371 upgrade_above_below (tree t) {
372 if (is_atomic (t)) return t;
373 else if (is_concat (t)) {
374 tree r (CONCAT);
375 for (int i=0; i<N(t); i++) {
376 tree x= upgrade_above_below (t[i]);
377 if (is_concat (x)) r << A(x);
378 else r << x;
379 }
380 return r;
381 }
382 else {
383 int i, n= N(t);
384 tree r (t, n);
385 for (i=0; i<n; i++)
386 r[i]= upgrade_above_below (t[i]);
387 if (is_func (r, ABOVE, 2)) {
388 if (is_func (r[0], BIG))
389 r= tree (CONCAT, r[0], tree (RSUP, r[1]));
390 else if (is_concat_big (r[0]))
391 r= tree (r[0] * tree (CONCAT, tree (RSUP, r[1])));
392 }
393 if (is_func (r, BELOW, 2)) {
394 if (is_func (r[0], BIG))
395 r= tree (CONCAT, r[0], tree (RSUB, r[1]));
396 else if (is_concat_big (r[0]))
397 r= tree (r[0] * tree (CONCAT, tree (RSUB, r[1])));
398 }
399 return r;
400 }
401 }
402
403 /******************************************************************************
404 * Master routine for upgrading brackets
405 ******************************************************************************/
406
407 static array<tree>
upgrade_brackets(array<tree> a,int level)408 upgrade_brackets (array<tree> a, int level) {
409 array<int> tp= symbol_types (a);
410 //cout << "Upgrade " << a << ", " << tp << "\n";
411 if (admits_brackets (tp)) {
412 //cout << " Downgrade dubious\n";
413 array<tree> r= simplify_matching (a, downgrade_dubious (tp), level);
414 if (r != a) return upgrade_brackets (r, level);
415 //cout << " Detect french\n";
416 r= simplify_matching (a, detect_french_interval (a, tp), level);
417 if (r != a) return upgrade_brackets (r, level);
418 //cout << " Detect absolute 1\n";
419 r= simplify_matching (a, detect_absolute (a, tp, false), level);
420 if (r != a) return upgrade_brackets (r, level);
421 //cout << " Detect absolute 2\n";
422 r= simplify_matching (a, detect_absolute (a, tp, true), level);
423 if (r != a) return upgrade_brackets (r, level);
424 //cout << " Detect probable\n";
425 r= simplify_matching (a, detect_probable (a, tp), level);
426 if (r != a) return upgrade_brackets (r, level);
427 //cout << " Detect dummy substitution\n";
428 if (replace_dummies (a) != a) {
429 array<tree> a2= replace_dummies (a);
430 array<int> tp2= symbol_types (a2);
431 r= simplify_matching (a2, detect_probable (a2, tp2), level);
432 if (r != a2) return upgrade_brackets (r, level);
433 }
434 //cout << " Confirm all\n";
435 r= simplify_matching (a, confirm_all (tp), level);
436 if (r != a) return upgrade_brackets (r, level);
437 //cout << " Missing left\n";
438 if (get_preference ("automatic brackets") != "off")
439 r= add_missing_left (a, tp);
440 if (r != a) return upgrade_brackets (r, level);
441 //cout << " Missing right\n";
442 if (get_preference ("automatic brackets") != "off")
443 r= add_missing_right (a, tp);
444 if (r != a) return upgrade_brackets (r, level);
445 }
446 if (admits_bigops (tp)) {
447 array<tree> r= prefix_split (a, tp, level);
448 if (r != a) return upgrade_brackets (r, level);
449 r= infix_split (a, tp, symbol_priorities (a), level);
450 if (r != a) return upgrade_brackets (r, level);
451 r= postfix_split (a, tp, level);
452 if (r != a) return upgrade_brackets (r, level);
453 ASSERT (tp[0] == SYMBOL_OPEN_BIG, "invalid situation");
454 r= upgrade_brackets (range (a, 1, N(a)), level + 1);
455 tree body= concat_recompose (r);
456 r= array<tree> ();
457 r << make_around (a[0], body);
458 return r;
459 }
460 return a;
461 }
462
463 static tree
upgrade_brackets_bis(tree t,string mode)464 upgrade_brackets_bis (tree t, string mode) {
465 //cout << "Upgrade " << t << ", " << mode << "\n";
466 tree r= t;
467 if (is_compound (t)) {
468 int i, n= N(t);
469 r= tree (t, n);
470 for (i=0; i<n; i++) {
471 tree tmode= the_drd->get_env_child (t, i, MODE, mode);
472 string smode= (is_atomic (tmode)? tmode->label: string ("text"));
473 if (is_correctable_child (t, i, true))
474 r[i]= upgrade_brackets_bis (t[i], smode);
475 else r[i]= t[i];
476 }
477 }
478
479 if (mode == "math") {
480 array<tree> a= concat_tokenize (r);
481 a= upgrade_brackets (a, 0);
482 tree ret= concat_recompose (a);
483 //if (ret != r) cout << "< " << r << LF << "> " << ret << LF;
484 return ret;
485 }
486 else return r;
487 }
488
489 tree
upgrade_brackets(tree t,string mode)490 upgrade_brackets (tree t, string mode) {
491 //cout << "Upgrade " << t << "\n";
492 with_drd drd (get_document_drd (t));
493 t= upgrade_above_below (t);
494 return upgrade_brackets_bis (t, mode);
495 }
496
497 tree
upgrade_big_bis(tree t)498 upgrade_big_bis (tree t) {
499 if (is_atomic (t)) return t;
500 int i, n= N(t);
501 tree r (t, n);
502 for (i=0; i<n; i++)
503 r[i]= upgrade_big_bis (t[i]);
504 if (is_concat (r))
505 for (int j=0; j<N(r); j++)
506 if (is_func (r[j], BIG)) {
507 array<tree> a= concat_tokenize (r);
508 a= upgrade_brackets (a, 0);
509 return concat_recompose (a);
510 }
511 return r;
512 }
513
514 tree
upgrade_big(tree t)515 upgrade_big (tree t) {
516 with_drd drd (get_document_drd (t));
517 return upgrade_big_bis (t);
518 }
519
520 /******************************************************************************
521 * Downgrading brackets
522 ******************************************************************************/
523
524 static tree
downgrade_bracket(tree t,bool large)525 downgrade_bracket (tree t, bool large) {
526 if (!is_atomic (t)) {
527 if (large && N(t) > 0)
528 if (is_func (t, LEFT) || is_func (t, MID) || is_func (t, RIGHT))
529 return t[0];
530 return t;
531 }
532 string s= t->label;
533 if (large) {
534 if (t == "<nobracket>") return tree (".");
535 if (starts (s, "<") && ends (s, ">")) return s (1, N(s)-1);
536 }
537 else if (s == "<nobracket>") return "";
538 return t;
539 }
540
541 tree
downgrade_brackets(tree t,bool delete_missing,bool big_dot)542 downgrade_brackets (tree t, bool delete_missing, bool big_dot) {
543 if (is_atomic (t)) return t;
544 int i, n= N(t);
545 tree r (t, n);
546 for (i=0; i<n; i++)
547 r[i]= downgrade_brackets (t[i], delete_missing, big_dot);
548 if (is_func (r, AROUND, 3)) {
549 if (delete_missing && r[0] == "<nobracket>" && r[2] == "<nobracket>")
550 return concat (r[0], r[1], r[2]);
551 tree lb= downgrade_bracket (r[0], false);
552 tree rb= downgrade_bracket (r[2], false);
553 r= concat (lb, r[1], rb);
554 }
555 if (is_func (r, VAR_AROUND, 3)) {
556 tree lb= tree (LEFT, downgrade_bracket (r[0], true));
557 tree rb= tree (RIGHT, downgrade_bracket (r[2], true));
558 if (delete_missing) {
559 if (lb == tree (LEFT, ".") && rb == tree (RIGHT, "."));
560 else if (lb == tree (LEFT, ".")) lb= "";
561 else if (rb == tree (RIGHT, ".")) rb= "";
562 }
563 r= concat (lb, r[1], rb);
564 }
565 if (is_func (r, BIG_AROUND, 2)) {
566 tree op= downgrade_bracket (r[0], true);
567 if (big_dot) r= concat (tree (BIG, op), r[1], tree (BIG, "."));
568 else r= concat (tree (BIG, op), r[1]);
569 }
570 if (is_concat (r)) r= concat_recompose (concat_decompose (r));
571 return r;
572 }
573
574 tree
downgrade_big(tree t)575 downgrade_big (tree t) {
576 if (is_atomic (t)) return t;
577 int i, n= N(t);
578 tree r (t, n);
579 for (i=0; i<n; i++)
580 r[i]= downgrade_big (t[i]);
581 if (is_func (r, BIG_AROUND, 2)) {
582 tree op= downgrade_bracket (r[0], true);
583 r= concat (tree (BIG, op), r[1]);
584 }
585 if (is_concat (r)) r= concat_recompose (concat_decompose (r));
586 return r;
587 }
588
589 /******************************************************************************
590 * Moving wrongly brackets across 'math' tag boundary
591 ******************************************************************************/
592
593 static bool
is_simple_opening(string s)594 is_simple_opening (string s) {
595 return s == "(" || s == "[" || s == "{" || s == "|";
596 }
597
598 static bool
is_simple_closing(string s)599 is_simple_closing (string s) {
600 return s == ")" || s == "]" || s == "}" || s == "|";
601 }
602
603 static bool
is_simple_matching(string l,string r)604 is_simple_matching (string l, string r) {
605 return
606 (l == "(" && r == ")") ||
607 (l == "[" && r == "]") ||
608 (l == "{" && r == "}") ||
609 (l == "|" && r == "|");
610 }
611
612 static tree
move_brackets_sub(tree t,bool in)613 move_brackets_sub (tree t, bool in) {
614 //cout << t << INDENT << LF;
615 if (is_compound (t)) {
616 int i, n= N(t);
617 tree r= tree (t, n);
618 for (i=0; i<n; i++)
619 r[i]= move_brackets_sub (t[i], in);
620 t= r;
621 }
622
623 while (true) {
624 tree r= t;
625 bool search= true;
626 if (is_concat (t))
627 for (int i=0; i<N(t) && search; i++)
628 if (is_compound (t[i], "math")) {
629 array<tree> a= concat_tokenize (t[i][0]);
630 for (int j=0; j<N(a) && search; j++)
631 if (is_atomic (a[j]) && is_simple_opening (a[j]->label))
632 for (int k= i+1; k<N(t) && search; k++)
633 if (is_atomic (t[k])) {
634 string s= t[k]->label;
635 for (int l=0; l<N(s) && search; tm_char_forwards (s, l))
636 if (is_simple_matching (a[j]->label, s (l, l+1))) {
637 if (k == i+1 && l == 0 && in) {
638 array<tree> c= concat_decompose (t);
639 a << tree (s (0, 1));
640 c[i]= compound ("math", concat_recompose (a));
641 c[i]= upgrade_brackets (c[i]);
642 c[i+1]= s (1, N(s));
643 r= move_brackets_sub (concat_recompose (c), in);
644 search= false;
645 }
646 else if (j == 0 && !in) {
647 tree x= a[0];
648 array<tree> c= concat_decompose (t);
649 a= range (a, 1, N(a));
650 c[i]= compound ("math", concat_recompose (a));
651 c= append (range (c, 0, i),
652 append (x, range (c, i, N(c))));
653 r= move_brackets_sub (concat_recompose (c), in);
654 search= false;
655 }
656 }
657 }
658 for (int j=N(a)-1; j>=0 && search; j--)
659 if (is_atomic (a[j]) && is_simple_closing (a[j]->label))
660 for (int k= i-1; k>=0 && search; k--)
661 if (is_atomic (t[k])) {
662 string s= t[k]->label;
663 for (int l=N(s); l>0 && search; tm_char_backwards (s, l))
664 if (is_simple_matching (s (l-1, l), a[j]->label)) {
665 if (k == i-1 && l == N(s) && in) {
666 array<tree> c= concat_decompose (t);
667 a= append (tree (s (l-1, l)), a);
668 c[i]= compound ("math", concat_recompose (a));
669 c[i]= upgrade_brackets (c[i]);
670 c[i-1]= s (0, l-1);
671 r= move_brackets_sub (concat_recompose (c), in);
672 search= false;
673 }
674 else if (j == N(a)-1 && !in) {
675 tree x= a[j];
676 array<tree> c= concat_decompose (t);
677 a= range (a, 0, j);
678 c[i]= compound ("math", concat_recompose (a));
679 c= append (range (c, 0, i+1),
680 append (x, range (c, i+1, N(c))));
681 r= move_brackets_sub (concat_recompose (c), in);
682 search= false;
683 }
684 }
685 }
686 }
687 if (search) break;
688 else {
689 //cout << "< " << t << LF;
690 //cout << "> " << r << LF;
691 t= r;
692 }
693 }
694 //cout << UNINDENT << "Done" << LF;
695 return t;
696 }
697
698 tree
move_brackets(tree t)699 move_brackets (tree t) {
700 return move_brackets_sub (move_brackets_sub (t, true), false);
701 }
702