]> git.lyx.org Git - lyx.git/blob - src/mathed/math_extern.C
some work on math-extern
[lyx.git] / src / mathed / math_extern.C
1
2 // This file contains most of the magic that extracts "context
3 // information" from the unstructered layout-oriented stuff in an
4 // MathArray.
5
6
7 #include "math_charinset.h"
8 #include "math_deliminset.h"
9 #include "math_exfuncinset.h"
10 #include "math_funcinset.h"
11 #include "math_matrixinset.h"
12 #include "math_mathmlstream.h"
13 #include "math_scriptinset.h"
14 #include "math_stringinset.h"
15 #include "math_symbolinset.h"
16 #include "debug.h"
17
18
19 std::ostream & operator<<(std::ostream & os, MathArray const & ar)
20 {
21         NormalStream ns(os);    
22         ns << ar;
23         return os;
24 }
25
26
27 MathScriptInset const * asScript(MathArray::const_iterator it)
28 {
29         if (it->nucleus()->asScriptInset())
30                 return 0;
31         ++it;
32         if (!it->nucleus())
33                 return 0;
34         return it->nucleus()->asScriptInset();
35 }
36
37
38
39 // returns sequence of char with same code starting at it up to end
40 // it might be less, though...
41 string charSequence(MathArray::const_iterator it, MathArray::const_iterator end)
42 {
43         string s;
44         MathCharInset const * p = it->nucleus()->asCharInset();
45         if (p) {
46                 for (MathTextCodes c = p->code(); it != end; ++it) {
47                         p = it->nucleus()->asCharInset();
48                         if (!p || p->code() != c)
49                                 break;
50                         s += p->getChar();
51                 }
52         }
53         return s;
54 }
55
56
57 void extractStrings(MathArray & dat)
58 {
59         //lyxerr << "\nStrings from: " << ar << "\n";
60         MathArray ar;
61         MathArray::const_iterator it = dat.begin();
62         while (it != dat.end()) {
63                 if (it->nucleus() && it->nucleus()->asCharInset()) {
64                         string s = charSequence(it, dat.end());
65                         MathTextCodes c = it->nucleus()->asCharInset()->code();
66                         ar.push_back(MathAtom(new MathStringInset(s, c)));
67                         it += s.size();
68                 } else {
69                         ar.push_back(*it);
70                         ++it;
71                 }
72         }
73         ar.swap(dat);
74         //lyxerr << "\nStrings to: " << ar << "\n";
75 }
76
77
78 MathInset * singleItem(MathArray & ar)
79 {
80         return ar.size() == 1 ? ar.begin()->nucleus() : 0;
81 }
82
83
84 void extractMatrices(MathArray & ar)
85 {
86         lyxerr << "\nMatrices from: " << ar << "\n";
87         for (MathArray::iterator it = ar.begin(); it != ar.end(); ++it) {
88                 MathDelimInset * del = (*it)->asDelimInset();
89                 if (!del)
90                         continue;
91                 MathInset * arr = singleItem(del->cell(0));
92                 if (!arr || !arr->asArrayInset())
93                         continue;
94                 *it = MathAtom(new MathMatrixInset(*(arr->asArrayInset())));
95                 lyxerr << "\nMatrices to: " << ar << "\n";
96         }
97
98
99 // convert this inset somehow to a string
100 string extractString(MathInset * p)
101 {
102         if (p && p->getChar())
103                 return string(1, p->getChar());
104         if (p && p->asStringInset())
105                 return p->asStringInset()->str();
106         return string();
107 }
108
109
110 // define a function for tests
111 typedef bool TestItemFunc(MathInset *);
112
113 // define a function for replacing pa
114 typedef MathInset * ReplaceArgumentFunc(const MathArray & ar);
115
116 // search end of nested sequence
117 MathArray::iterator searchNestedEnd(
118         MathArray::iterator it,
119         MathArray::iterator last,
120         TestItemFunc testOpen,
121         TestItemFunc testClose
122 )
123 {
124         for (int level = 0; it != last; ++it) {
125                 if (testOpen(it->nucleus()))
126                         ++level;
127                 if (testClose(it->nucleus()))
128                         --level;
129                 if (level == 0)
130                         break;
131         }
132         return it;
133 }
134
135
136 // replace nested sequences by a real Insets
137 void replaceNested(
138         MathArray & ar,
139         TestItemFunc testOpen,
140         TestItemFunc testClose,
141         ReplaceArgumentFunc replaceArg
142 )
143 {
144         // use indices rather than iterators for the loop  because we are going
145         // to modify the array.
146         for (MathArray::size_type i = 0; i < ar.size(); ++i) {
147                 // check whether this is the begin of the sequence
148                 MathArray::iterator it = ar.begin() + i;
149                 if (!testOpen(it->nucleus()))
150                         continue;
151
152                 // search end of sequence
153                 MathArray::iterator jt = searchNestedEnd(it, ar.end(), testOpen, testClose);
154                 if (jt == ar.end())
155                         continue;
156
157                 // create a proper inset as replacement
158                 MathInset * p = replaceArg(MathArray(it + 1, jt));
159
160                 // replace the original stuff by the new inset
161                 ar.erase(it + 1, jt + 1);
162                 (*it).reset(p);
163         }
164
165
166
167 bool testParanOpen(MathInset * p)
168 {
169         return extractString(p) == "(";
170 }
171
172
173 bool testParanClose(MathInset * p)
174 {
175         return extractString(p) == ")";
176 }
177
178
179 MathInset * replaceByDelimInset(const MathArray & ar)
180 {
181         MathDelimInset * del = new MathDelimInset("(", ")");
182         del->cell(0) = ar;
183         return del;
184 }
185
186
187 // replace '('...')' sequences by a real MathDelimInset
188 void extractDelims(MathArray & ar) {
189         lyxerr << "\nDelims from: " << ar << "\n";
190         replaceNested(ar, testParanOpen, testParanClose, replaceByDelimInset);
191         lyxerr << "\nDelims to: " << ar << "\n";
192 }
193
194
195 // replace 'f' '(...)' and 'f' '^n' '(...)' sequences by a real MathExFuncInset
196 // assume 'extractDelims' ran before
197 void extractFunctions(MathArray & ar)
198 {
199         // we need at least two items...
200         if (ar.size() <= 1)
201                 return;
202
203         lyxerr << "\nFunctions from: " << ar << "\n";
204         for (MathArray::size_type i = 0; i < ar.size() - 1; ++i) {
205                 MathArray::iterator it = ar.begin() + i;
206
207                 // is this a function name?
208                 MathFuncInset * func = (*it)->asFuncInset();
209                 if (!func)
210                         continue;
211
212                 // do we have an exponent?
213                 // simply skippping the postion does the right thing:
214                 // 'sin' '^2' 'x' -> 'sin(x)' '^2'
215                 MathArray::iterator jt = it + 1;
216                 if (MathScriptInset * script = (*jt)->asScriptInset()) {
217                         // allow superscripts only
218                         if (script->hasDown())
219                                 continue;
220                         ++jt;
221                         if (jt == ar.end())
222                                 continue;
223                 }
224
225                 // jt points now to the "argument". Since we had run "extractDelims"
226                 // before, this could be a single argument only. Get hold of this.
227                 MathArray arg;
228                 MathDelimInset * del = (*jt)->asDelimInset();
229                 if (del && del->isParanthesis()) 
230                         arg = del->cell(0);
231                 else
232                         arg.push_back(*jt);
233
234                 // replace the function name by a real function inset
235                 (*it).reset(new MathExFuncInset(func->name(), arg));
236                 
237                 // remove the source of the argument from the array
238                 ar.erase(jt);
239                 lyxerr << "\nFunctions to: " << ar << "\n";
240         }
241
242
243
244 bool testIntSymbol(MathInset * p)
245 {
246         return p->asSymbolInset() && p->asSymbolInset()->name() == "int";
247 }
248
249
250 bool testSmallD(MathInset * p)
251 {
252         string s = extractString(p);
253         return s.size() && s[0] == 'd';
254 }
255
256
257 // replace '\int' ['_^'] x 'd''x'(...)' sequences by a real MathExIntInset
258 // assume 'extractDelims' ran before
259 void extractIntegrals(MathArray & ar)
260 {
261         // we need at least three items...
262         if (ar.size() <= 2)
263                 return;
264
265         lyxerr << "\nIntegrals from: " << ar << "\n";
266         for (MathArray::size_type i = 0; i < ar.size() - 1; ++i) {
267                 MathArray::iterator it = ar.begin() + i;
268
269                 // is this a integral name?
270                 if (!testIntSymbol(it->nucleus()))
271                         continue;
272
273                 // search 'd'
274                 MathArray::iterator jt =
275                         searchNestedEnd(it, ar.end(), testIntSymbol, testSmallD);
276
277                 // create a proper inset as replacement
278                 //MathInset * p = replaceArg(MathArray(it + 1, jt));
279
280                 // replace the original stuff by the new inset
281                 //ar.erase(it + 1, jt + 1);
282                 //(*it).reset(p);
283         }
284 }
285
286
287 void extractStructure(MathArray & ar)
288 {
289         extractStrings(ar);
290         extractMatrices(ar);
291         extractDelims(ar);
292         extractFunctions(ar);
293         extractIntegrals(ar);
294 }
295
296
297 void write(MathArray const & dat, WriteStream & wi)
298 {
299         MathArray ar = dat;
300         extractStrings(ar);
301         for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) {
302                 MathInset const * p = it->nucleus();
303                 if (it + 1 != ar.end()) {
304                         if (MathScriptInset const * q = asScript(it)) {
305                                 q->write(p, wi);
306                                 ++it;
307                                 continue;
308                         } 
309                 }
310                 p->write(wi);
311         }
312 }
313
314
315 void normalize(MathArray const & ar, NormalStream & os)
316 {
317         for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it)
318                 (*it)->normalize(os);
319 }
320
321
322 void octavize(MathArray const & dat, OctaveStream & os)
323 {
324         MathArray ar = dat;
325         extractStructure(ar);
326         for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) {
327                 MathInset const * p = it->nucleus();
328                 if (it + 1 != ar.end()) {
329                         if (MathScriptInset const * q = asScript(it)) {
330                                 q->octavize(p, os);
331                                 ++it;   
332                                 continue;
333                         }
334                 }
335                 p->octavize(os);
336         }
337 }
338
339
340 void maplize(MathArray const & dat, MapleStream & os)
341 {
342         MathArray ar = dat;
343         extractStructure(ar);
344         for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) {
345                 MathInset const * p = it->nucleus();
346                 if (it + 1 != ar.end()) {
347                         if (MathScriptInset const * q = asScript(it)) {
348                                 q->maplize(p, os);
349                                 ++it;   
350                                 continue;
351                         }
352                 }
353                 p->maplize(os);
354         }
355 }
356
357
358 void mathmlize(MathArray const & dat, MathMLStream & os)
359 {
360         MathArray ar = dat;
361         extractStructure(ar);
362         if (ar.size() == 0)
363                 os << "<mrow/>";
364         else if (ar.size() == 1)
365                 os << ar.begin()->nucleus();
366         else {
367                 os << MTag("mrow");
368                 for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) {
369                         MathInset const * p = it->nucleus();
370                         if (it + 1 != ar.end()) {
371                                 if (MathScriptInset const * q = asScript(it)) {
372                                         q->mathmlize(p, os);
373                                         ++it;   
374                                         continue;
375                                 }
376                         }
377                         p->mathmlize(os);
378                 }
379                 os << ETag("mrow");
380         }
381 }
382