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