2 // This file contains most of the magic that extracts "context
3 // information" from the unstructered layout-oriented stuff in an
8 #include "math_charinset.h"
9 #include "math_deliminset.h"
10 #include "math_exfuncinset.h"
11 #include "math_exintinset.h"
12 #include "math_funcinset.h"
13 #include "math_matrixinset.h"
14 #include "math_mathmlstream.h"
15 #include "math_scriptinset.h"
16 #include "math_stringinset.h"
17 #include "math_symbolinset.h"
21 std::ostream & operator<<(std::ostream & os, MathArray const & ar)
29 MathScriptInset const * asScript(MathArray::const_iterator it)
31 if (it->nucleus()->asScriptInset())
36 return it->nucleus()->asScriptInset();
41 // returns sequence of char with same code starting at it up to end
42 // it might be less, though...
43 string charSequence(MathArray::const_iterator it, MathArray::const_iterator end)
46 MathCharInset const * p = it->nucleus()->asCharInset();
48 for (MathTextCodes c = p->code(); it != end; ++it) {
49 p = it->nucleus()->asCharInset();
50 if (!p || p->code() != c)
59 void extractStrings(MathArray & dat)
61 //lyxerr << "\nStrings from: " << ar << "\n";
63 MathArray::const_iterator it = dat.begin();
64 while (it != dat.end()) {
65 if (it->nucleus() && it->nucleus()->asCharInset()) {
66 string s = charSequence(it, dat.end());
67 MathTextCodes c = it->nucleus()->asCharInset()->code();
68 ar.push_back(MathAtom(new MathStringInset(s, c)));
76 //lyxerr << "\nStrings to: " << ar << "\n";
80 MathInset * singleItem(MathArray & ar)
82 return ar.size() == 1 ? ar.begin()->nucleus() : 0;
86 void extractMatrices(MathArray & ar)
88 lyxerr << "\nMatrices from: " << ar << "\n";
89 for (MathArray::iterator it = ar.begin(); it != ar.end(); ++it) {
90 MathDelimInset * del = (*it)->asDelimInset();
93 MathInset * arr = singleItem(del->cell(0));
94 if (!arr || !arr->asArrayInset())
96 *it = MathAtom(new MathMatrixInset(*(arr->asArrayInset())));
97 lyxerr << "\nMatrices to: " << ar << "\n";
101 // convert this inset somehow to a string
102 string extractString(MathInset * p)
104 if (p && p->getChar())
105 return string(1, p->getChar());
106 if (p && p->asStringInset())
107 return p->asStringInset()->str();
112 // define a function for tests
113 typedef bool TestItemFunc(MathInset *);
115 // define a function for replacing subexpressions
116 typedef MathInset * ReplaceArgumentFunc(const MathArray & ar);
119 // search end of nested sequence
120 MathArray::iterator endNestSearch(
121 MathArray::iterator it,
122 MathArray::iterator last,
123 TestItemFunc testOpen,
124 TestItemFunc testClose
127 for (int level = 0; it != last; ++it) {
128 if (testOpen(it->nucleus()))
130 if (testClose(it->nucleus()))
139 // replace nested sequences by a real Insets
142 TestItemFunc testOpen,
143 TestItemFunc testClose,
144 ReplaceArgumentFunc replaceArg
147 // use indices rather than iterators for the loop because we are going
148 // to modify the array.
149 for (MathArray::size_type i = 0; i < ar.size(); ++i) {
150 // check whether this is the begin of the sequence
151 MathArray::iterator it = ar.begin() + i;
152 if (!testOpen(it->nucleus()))
155 // search end of sequence
156 MathArray::iterator jt = endNestSearch(it, ar.end(), testOpen, testClose);
160 // create a proper inset as replacement
161 MathInset * p = replaceArg(MathArray(it + 1, jt));
163 // replace the original stuff by the new inset
164 ar.erase(it + 1, jt + 1);
171 // search deliminiters
174 bool openParanTest(MathInset * p)
176 return extractString(p) == "(";
180 bool closeParanTest(MathInset * p)
182 return extractString(p) == ")";
186 MathInset * delimReplacement(const MathArray & ar)
188 MathDelimInset * del = new MathDelimInset("(", ")");
194 // replace '('...')' sequences by a real MathDelimInset
195 void extractDelims(MathArray & ar) {
196 lyxerr << "\nDelims from: " << ar << "\n";
197 replaceNested(ar, openParanTest, closeParanTest, delimReplacement);
198 lyxerr << "\nDelims to: " << ar << "\n";
204 // search well-known functions
208 // replace 'f' '(...)' and 'f' '^n' '(...)' sequences by a real MathExFuncInset
209 // assume 'extractDelims' ran before
210 void extractFunctions(MathArray & ar)
212 // we need at least two items...
216 lyxerr << "\nFunctions from: " << ar << "\n";
217 for (MathArray::size_type i = 0; i < ar.size() - 1; ++i) {
218 MathArray::iterator it = ar.begin() + i;
220 // is this a function name?
221 MathFuncInset * func = (*it)->asFuncInset();
225 // do we have an exponent?
226 // simply skippping the postion does the right thing:
227 // 'sin' '^2' 'x' -> 'sin(x)' '^2'
228 MathArray::iterator jt = it + 1;
229 if (MathScriptInset * script = (*jt)->asScriptInset()) {
230 // allow superscripts only
231 if (script->hasDown())
238 // jt points now to the "argument". Since we had run "extractDelims"
239 // before, this could be a single argument only. Get hold of this.
241 MathDelimInset * del = (*jt)->asDelimInset();
242 if (del && del->isParanthesis())
247 // replace the function name by a real function inset
248 (*it).reset(new MathExFuncInset(func->name(), arg));
250 // remove the source of the argument from the array
252 lyxerr << "\nFunctions to: " << ar << "\n";
261 bool intSymbolTest(MathInset * p)
263 return p->asSymbolInset() && p->asSymbolInset()->name() == "int";
267 bool differentialTest(MathInset * p)
269 return extractString(p) == "d";
273 // replace '\int' ['_^'] x 'd''x'(...)' sequences by a real MathExIntInset
274 // assume 'extractDelims' ran before
275 void extractIntegrals(MathArray & ar)
277 // we need at least three items...
281 lyxerr << "\nIntegrals from: " << ar << "\n";
282 for (MathArray::size_type i = 0; i < ar.size() - 1; ++i) {
283 MathArray::iterator it = ar.begin() + i;
285 // is this a integral name?
286 if (!intSymbolTest(it->nucleus()))
290 MathArray::iterator jt =
291 endNestSearch(it, ar.end(), intSymbolTest, differentialTest);
293 // something sensible found?
297 // create a proper inset as replacement
298 MathExIntInset * p = new MathExIntInset("int");
301 MathArray::iterator st = it + 1;
302 if ((*st)->asScriptInset()) {
304 p->core(MathArray(st + 1, jt));
306 p->core(MathArray(st, jt));
309 // use the atom behind the 'd' as differential
311 if (jt + 1 != ar.end()) {
312 ind.push_back(*(jt + 1));
315 ar.erase(it + 1, jt + 1);
320 lyxerr << "\nIntegrals to: " << ar << "\n";
328 bool sumSymbolTest(MathInset * p)
330 return p->asSymbolInset() && p->asSymbolInset()->name() == "sum";
334 bool equalSign(MathInset * p)
336 return extractString(p) == "=";
340 bool equalSign1(MathAtom const & at)
342 return equalSign(at.nucleus());
347 // replace '\sum' ['_^'] f(x) sequences by a real MathExIntInset
348 // assume 'extractDelims' ran before
349 void extractSums(MathArray & ar)
351 // we need at least two items...
355 lyxerr << "\nSums from: " << ar << "\n";
356 for (MathArray::size_type i = 0; i < ar.size() - 1; ++i) {
357 MathArray::iterator it = ar.begin() + i;
359 // is this a sum name?
360 if (!sumSymbolTest(it->nucleus()))
363 // create a proper inset as replacement
364 MathExIntInset * p = new MathExIntInset("sum");
367 MathArray::iterator st = it + 1;
368 if (st != ar.end() && (*st)->asScriptInset()) {
372 // try to figure out the summation index from the subscript
373 MathScriptInset * script = p->scripts()->asScriptInset();
374 if (script->hasDown()) {
375 MathArray & ar = script->down().data_;
376 MathArray::iterator it =
377 std::find_if(ar.begin(), ar.end(), &equalSign1);
378 if (it != ar.end()) {
379 // we found a '=', use everything in front of that as index,
380 // and everything behind as start value
381 p->index(MathArray(ar.begin(), it));
382 ar.erase(ar.begin(), it + 1);
384 // use everything as summation index
386 p->scripts().reset(0);
391 // use the atom behind the script as core
393 if (st != ar.end()) {
399 ar.erase(it + 1, st);
402 lyxerr << "\nSums to: " << ar << "\n";
406 void extractStructure(MathArray & ar)
410 extractFunctions(ar);
411 extractIntegrals(ar);
417 void write(MathArray const & dat, WriteStream & wi)
421 for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) {
422 MathInset const * p = it->nucleus();
423 if (it + 1 != ar.end()) {
424 if (MathScriptInset const * q = asScript(it)) {
435 void normalize(MathArray const & ar, NormalStream & os)
437 for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it)
438 (*it)->normalize(os);
442 void octavize(MathArray const & dat, OctaveStream & os)
445 extractStructure(ar);
446 for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) {
447 MathInset const * p = it->nucleus();
448 if (it + 1 != ar.end()) {
449 if (MathScriptInset const * q = asScript(it)) {
460 void maplize(MathArray const & dat, MapleStream & os)
463 extractStructure(ar);
464 for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) {
465 MathInset const * p = it->nucleus();
466 if (it + 1 != ar.end()) {
467 if (MathScriptInset const * q = asScript(it)) {
478 void mathmlize(MathArray const & dat, MathMLStream & os)
481 extractStructure(ar);
484 else if (ar.size() == 1)
485 os << ar.begin()->nucleus();
488 for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) {
489 MathInset const * p = it->nucleus();
490 if (it + 1 != ar.end()) {
491 if (MathScriptInset const * q = asScript(it)) {