2 # -*- coding: ISO-8859-1 -*-
5 # Copyright (C) 2002-2004 Jörg Lehmann <joergl@users.sourceforge.net>
6 # Copyright (C) 2003-2004 Michael Schindler <m-schindler@users.sourceforge.net>
7 # Copyright (C) 2002-2004 André Wobst <wobsta@users.sourceforge.net>
9 # This file is part of PyX (http://pyx.sourceforge.net/).
11 # PyX is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 2 of the License, or
14 # (at your option) any later version.
16 # PyX is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with PyX; if not, write to the Free Software
23 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 import string
, re
, math
30 __useparser__
= __oldparser__
31 #__useparser__ = __newparser__
33 if __useparser__
== __newparser__
:
35 import parser
as pythonparser
39 def __init__(self
, StrToParse
, Pos
= 0):
40 self
.StrToParse
= StrToParse
44 return "ParseStr('" + self
.StrToParse
+ "', " + str(self
.Pos
) + ")"
46 def __str__(self
, Indent
= ""):
48 for i
in range(self
.Pos
):
49 WhiteSpaces
= WhiteSpaces
+ " "
50 return Indent
+ self
.StrToParse
+ "\n" + Indent
+ WhiteSpaces
+ "^"
52 def NextNonWhiteSpace(self
, i
= None):
55 while self
.StrToParse
[i
] in string
.whitespace
:
59 def MatchStr(self
, Str
):
61 i
= self
.NextNonWhiteSpace()
62 if self
.StrToParse
[i
: i
+ len(Str
)] == Str
:
63 self
.Pos
= i
+ len(Str
)
68 def MatchStrParenthesis(self
, Str
):
70 i
= self
.NextNonWhiteSpace()
71 if self
.StrToParse
[i
: i
+ len(Str
)] == Str
:
73 i
= self
.NextNonWhiteSpace(i
)
74 if self
.StrToParse
[i
: i
+ 1] == "(":
80 def MatchPattern(self
, Pat
):
82 i
= self
.NextNonWhiteSpace()
83 Match
= Pat
.match(self
.StrToParse
[i
:])
85 self
.Pos
= i
+ Match
.end()
92 self
.NextNonWhiteSpace()
98 class ArgCountError(Exception): pass
99 class DerivativeError(Exception): pass
103 def __init__(self
, ArgCount
, *Args
):
104 self
.ArgCount
= ArgCount
109 def __repr__(self
, depth
= 0):
112 for i
in range(depth
):
113 indent
= indent
+ SingleIndent
114 result
= indent
+ self
.__class
__.__name
__ + "(\n"
115 for SubTree
in self
.Args
:
116 if isinstance(SubTree
, MathTree
):
117 result
= result
+ SubTree
.__repr
__(depth
+ 1)
119 result
= result
+ indent
+ SingleIndent
+ repr(SubTree
)
121 if SubTree
!= self
.Args
[-1]:
122 result
= result
+ ",\n"
124 result
= result
+ ")"
127 def AddArg(self
, Arg
, Last
=0, NotLast
=0):
128 if len(self
.Args
) == self
.ArgCount
:
130 self
.Args
.append(Arg
)
131 if NotLast
and len(self
.Args
) == self
.ArgCount
:
133 if Last
and len(self
.Args
) != self
.ArgCount
:
136 def DependOn(self
, arg
):
137 for Arg
in self
.Args
:
138 if Arg
.DependOn(arg
):
142 def Derivative(self
, arg
):
143 if not self
.DependOn(arg
):
144 return MathTreeValConst(0.0)
145 return self
.CalcDerivative(arg
)
149 for Arg
in self
.Args
:
150 newlist
= Arg
.VarList()
157 class MathTreeVal(MathTree
):
159 def __init__(self
, *args
):
160 MathTree
.__init
__(self
, 1, *args
)
163 return str(self
.Args
[0])
166 ConstPattern
= re
.compile(r
"-?\d*((\d\.?)|(\.?\d))\d*(E[+-]?\d+)?",
169 class MathTreeValConst(MathTreeVal
):
171 def InitByParser(self
, arg
):
172 Match
= arg
.MatchPattern(ConstPattern
)
174 self
.AddArg(string
.atof(Match
))
177 def CalcDerivative(self
, arg
):
178 raise DerivativeError("expression doesn't depend on \"%s\"" % arg
)
180 def Derivative(self
, arg
):
181 return MathTreeValConst(0.0)
183 def DependOn(self
, arg
):
189 def Calc(HIDDEN_self
, **args
):
190 return HIDDEN_self
.Args
[0]
193 VarPattern
= re
.compile(r
"[a-z_][a-z0-9_]*", re
.IGNORECASE
)
194 MathConst
= {"pi": math
.pi
, "e": math
.e
}
196 class MathTreeValVar(MathTreeVal
):
198 def InitByParser(self
, arg
):
199 Match
= arg
.MatchPattern(VarPattern
)
204 def CalcDerivative(self
, arg
):
205 if arg
!= self
.Args
[0]:
206 raise DerivativeError("expression doesn't depend on \"%s\"" % arg
)
207 return MathTreeValConst(1.0)
209 def DependOn(self
, arg
):
210 if arg
== self
.Args
[0]:
215 if self
.Args
[0] in MathConst
.keys():
217 return [self
.Args
[0]]
219 def Calc(HIDDEN_self
, **args
):
220 if HIDDEN_self
.Args
[0] in args
.keys():
221 return float(args
[HIDDEN_self
.Args
[0]])
222 return MathConst
[HIDDEN_self
.Args
[0]]
225 class MathTreeFunc(MathTree
):
227 def __init__(self
, name
, ArgCount
, *args
):
229 MathTree
.__init
__(self
, ArgCount
, *args
)
231 def InitByParser(self
, arg
):
232 return arg
.MatchStrParenthesis(self
.name
)
236 for SubTree
in self
.Args
:
237 args
= args
+ str(SubTree
)
238 if SubTree
!= self
.Args
[-1]:
240 return self
.name
+ "(" + args
+ ")"
243 class MathTreeFunc1(MathTreeFunc
):
245 def __init__(self
, name
, *args
):
246 MathTreeFunc
.__init
__(self
, name
, 1, *args
)
249 class MathTreeFunc1Neg(MathTreeFunc1
):
251 def __init__(self
, *args
):
252 MathTreeFunc1
.__init__(self
, "neg", *args
)
254 def CalcDerivative(self
, arg
):
255 return MathTreeFunc1Neg(self
.Args
[0].CalcDerivative(arg
))
257 def Calc(HIDDEN_self
, **args
):
258 return -HIDDEN_self
.Args
[0].Calc(**args
)
261 class MathTreeFunc1Abs(MathTreeFunc1
):
263 def __init__(self
, *args
):
264 MathTreeFunc1
.__init__(self
, "abs", *args
)
266 def CalcDerivative(self
, arg
):
267 return MathTreeOpMul(
268 MathTreeFunc1Sgn(self
.Args
[0]),
269 self
.Args
[0].CalcDerivative(arg
))
271 def Calc(HIDDEN_self
, **args
):
272 return abs(HIDDEN_self
.Args
[0].Calc(**args
))
275 class MathTreeFunc1Sgn(MathTreeFunc1
):
277 def __init__(self
, *args
):
278 MathTreeFunc1
.__init__(self
, "sgn", *args
)
280 def CalcDerivative(self
, arg
):
281 return MathTreeValConst(0.0)
283 def Calc(HIDDEN_self
, **args
):
284 if HIDDEN_self
.Args
[0].Calc(**args
) < 0:
289 class MathTreeFunc1Sqrt(MathTreeFunc1
):
291 def __init__(self
, *args
):
292 MathTreeFunc1
.__init__(self
, "sqrt", *args
)
294 def CalcDerivative(self
, arg
):
295 return MathTreeOpMul(
297 MathTreeValConst(0.5),
299 self
.Args
[0].CalcDerivative(arg
))
301 def Calc(HIDDEN_self
, **args
):
302 return math
.sqrt(HIDDEN_self
.Args
[0].Calc(**args
))
305 class MathTreeFunc1Exp(MathTreeFunc1
):
307 def __init__(self
, *args
):
308 MathTreeFunc1
.__init__(self
, "exp", *args
)
310 def CalcDerivative(self
, arg
):
311 return MathTreeOpMul(self
, self
.Args
[0].CalcDerivative(arg
))
313 def Calc(HIDDEN_self
, **args
):
314 return math
.exp(HIDDEN_self
.Args
[0].Calc(**args
))
317 class MathTreeFunc1Log(MathTreeFunc1
):
319 def __init__(self
, *args
):
320 MathTreeFunc1
.__init__(self
, "log", *args
)
322 def CalcDerivative(self
, arg
):
323 return MathTreeOpDiv(self
.Args
[0].CalcDerivative(arg
), self
.Args
[0])
325 def Calc(HIDDEN_self
, **args
):
326 return math
.log(HIDDEN_self
.Args
[0].Calc(**args
))
329 class MathTreeFunc1Sin(MathTreeFunc1
):
331 def __init__(self
, *args
):
332 MathTreeFunc1
.__init__(self
, "sin", *args
)
334 def CalcDerivative(self
, arg
):
335 return MathTreeOpMul(
336 MathTreeFunc1Cos(self
.Args
[0]),
337 self
.Args
[0].CalcDerivative(arg
))
339 def Calc(HIDDEN_self
, **args
):
340 return math
.sin(HIDDEN_self
.Args
[0].Calc(**args
))
343 class MathTreeFunc1Cos(MathTreeFunc1
):
345 def __init__(self
, *args
):
346 MathTreeFunc1
.__init__(self
, "cos", *args
)
348 def CalcDerivative(self
, arg
):
349 return MathTreeOpMul(
350 MathTreeFunc1Neg(MathTreeFunc1Sin(self
.Args
[0])),
351 self
.Args
[0].CalcDerivative(arg
))
353 def Calc(HIDDEN_self
, **args
):
354 return math
.cos(HIDDEN_self
.Args
[0].Calc(**args
))
357 class MathTreeFunc1Tan(MathTreeFunc1
):
359 def __init__(self
, *args
):
360 MathTreeFunc1
.__init__(self
, "tan", *args
)
362 def CalcDerivative(self
, arg
):
363 return MathTreeOpDiv(
364 self
.Args
[0].CalcDerivative(arg
),
366 MathTreeFunc1Cos(self
.Args
[0]),
367 MathTreeValConst(2.0)))
369 def Calc(HIDDEN_self
, **args
):
370 return math
.tan(HIDDEN_self
.Args
[0].Calc(**args
))
373 class MathTreeFunc1ASin(MathTreeFunc1
):
375 def __init__(self
, *args
):
376 MathTreeFunc1
.__init__(self
, "asin", *args
)
378 def CalcDerivative(self
, arg
):
379 return MathTreeOpDiv(
380 self
.Args
[0].CalcDerivative(arg
),
383 MathTreeValConst(1.0),
386 MathTreeValConst(2.0)))))
388 def Calc(HIDDEN_self
, **args
):
389 return math
.asin(HIDDEN_self
.Args
[0].Calc(**args
))
392 class MathTreeFunc1ACos(MathTreeFunc1
):
394 def __init__(self
, *args
):
395 MathTreeFunc1
.__init__(self
, "acos", *args
)
397 def CalcDerivate(self
, arg
):
398 return MathTreeOpDiv(
399 MathTreeFunc1Neg(self
.Args
[0].CalcDerivative(arg
)),
402 MathTreeValConst(1.0),
405 MathTreeValConst(2.0)))))
407 def Calc(HIDDEN_self
, **args
):
408 return math
.acos(HIDDEN_self
.Args
[0].Calc(**args
))
411 class MathTreeFunc1ATan(MathTreeFunc1
):
413 def __init__(self
, *args
):
414 MathTreeFunc1
.__init__(self
, "atan", *args
)
416 def CalcDerivate(self
, arg
):
417 return MathTreeOpDiv(
418 self
.Args
[0].CalcDerivative(arg
),
420 MathTreeValConst(1.0),
423 MathTreeValConst(2.0))))
425 def Calc(HIDDEN_self
, **args
):
426 return math
.atan(HIDDEN_self
.Args
[0].Calc(**args
))
429 class MathTreeFunc1SinD(MathTreeFunc1
):
431 def __init__(self
, *args
):
432 MathTreeFunc1
.__init__(self
, "sind", *args
)
434 def CalcDerivative(self
, arg
):
435 return MathTreeOpMul(
436 MathTreeFunc1CosD(self
.Args
[0]),
438 MathTreeValConst(math
.pi
/180.0),
439 self
.Args
[0].CalcDerivative(arg
)))
441 def Calc(HIDDEN_self
, **args
):
442 return math
.sin(math
.pi
/180.0*HIDDEN_self
.Args
[0].Calc(**args
))
445 class MathTreeFunc1CosD(MathTreeFunc1
):
447 def __init__(self
, *args
):
448 MathTreeFunc1
.__init__(self
, "cosd", *args
)
450 def CalcDerivative(self
, arg
):
451 return MathTreeOpMul(
452 MathTreeFunc1Neg(MathTreeFunc1Sin(self
.Args
[0])),
454 MathTreeValConst(math
.pi
/180.0),
455 self
.Args
[0].CalcDerivative(arg
)))
457 def Calc(HIDDEN_self
, **args
):
458 return math
.cos(math
.pi
/180.0*HIDDEN_self
.Args
[0].Calc(**args
))
461 class MathTreeFunc1TanD(MathTreeFunc1
):
463 def __init__(self
, *args
):
464 MathTreeFunc1
.__init__(self
, "tand", *args
)
466 def CalcDerivative(self
, arg
):
467 return MathTreeOpDiv(
469 MathTreeValConst(math
.pi
/180.0),
470 self
.Args
[0].CalcDerivative(arg
)),
472 MathTreeFunc1Cos(self
.Args
[0]),
473 MathTreeValConst(2.0)))
475 def Calc(HIDDEN_self
, **args
):
476 return math
.tan(math
.pi
/180.0*HIDDEN_self
.Args
[0].Calc(**args
))
479 class MathTreeFunc1ASinD(MathTreeFunc1
):
481 def __init__(self
, *args
):
482 MathTreeFunc1
.__init__(self
, "asind", *args
)
484 def CalcDerivative(self
, arg
):
485 return MathTreeOpDiv(
487 MathTreeValConst(180.0/math
.pi
),
488 self
.Args
[0].CalcDerivative(arg
)),
491 MathTreeValConst(1.0),
494 MathTreeValConst(2.0)))))
496 def Calc(HIDDEN_self
, **args
):
497 return 180.0/math
.pi
*math
.asin(HIDDEN_self
.Args
[0].Calc(**args
))
500 class MathTreeFunc1ACosD(MathTreeFunc1
):
502 def __init__(self
, *args
):
503 MathTreeFunc1
.__init__(self
, "acosd", *args
)
505 def CalcDerivate(self
, arg
):
506 return MathTreeOpDiv(
509 MathTreeValConst(180.0/math
.pi
),
510 self
.Args
[0].CalcDerivative(arg
))),
513 MathTreeValConst(1.0),
516 MathTreeValConst(2.0)))))
518 def Calc(HIDDEN_self
, **args
):
519 return 180.0/math
.pi
*math
.acos(HIDDEN_self
.Args
[0].Calc(**args
))
522 class MathTreeFunc1ATanD(MathTreeFunc1
):
524 def __init__(self
, *args
):
525 MathTreeFunc1
.__init__(self
, "atand", *args
)
527 def CalcDerivate(self
, arg
):
528 return MathTreeOpDiv(
530 MathTreeValConst(180.0/math
.pi
),
531 self
.Args
[0].CalcDerivative(arg
)),
533 MathTreeValConst(1.0),
536 MathTreeValConst(2.0))))
538 def Calc(HIDDEN_self
, **args
):
539 return 180.0/math
.pi
*math
.atan(HIDDEN_self
.Args
[0].Calc(**args
))
542 class MathTreeFunc2(MathTreeFunc
):
544 def __init__(self
, name
, *args
):
545 MathTreeFunc
.__init
__(self
, name
, 2, *args
)
548 class MathTreeFunc2Norm(MathTreeFunc2
):
550 def __init__(self
, *args
):
551 MathTreeFunc2
.__init__(self
, "norm", *args
)
553 def CalcDerivative(self
, arg
):
554 if self
.Args
[0].DependOn(arg
):
555 if self
.Args
[1].DependOn(arg
):
556 return MathTreeOpDiv(
560 self
.Args
[0].CalcDerivative(arg
)),
563 self
.Args
[1].CalcDerivative(arg
))),
566 return MathTreeOpDiv(
569 self
.Args
[0].CalcDerivative(arg
)),
572 if self
.Args
[1].DependOn(arg
):
573 return MathTreeOpDiv(
576 self
.Args
[1].CalcDerivative(arg
)),
579 def Calc(HIDDEN_self
, **args
):
580 return math
.sqrt(HIDDEN_self
.Args
[0].Calc(**args
) ** 2 +
581 HIDDEN_self
.Args
[1].Calc(**args
) ** 2)
584 FuncExternPattern
= re
.compile(r
"([a-z_][a-z0-9_]*)\s*\(", re
.IGNORECASE
)
586 class MathTreeFuncExtern(MathTreeFunc
):
588 def __init__(self
, *args
):
589 MathTreeFunc
.__init
__(self
, None, -1, *args
)
591 def InitByParser(self
, arg
):
592 Match
= arg
.MatchPattern(FuncExternPattern
)
594 self
.name
= Match
[:-1].strip()
597 def SetName(self
, arg
):
598 self
.name
= arg
.strip()
601 def Calc(HIDDEN_self
, **args
):
602 return args
[HIDDEN_self
.name
](*[arg
.Calc(**args
) for arg
in HIDDEN_self
.Args
])
605 class MathTreeOp(MathTree
):
607 def __init__(self
, level
, symbol
, *args
):
608 self
.ParenthesisBarrier
= 0
611 MathTree
.__init
__(self
, 2, *args
)
615 if isinstance(self
.Args
[0], MathTreeOp
) and\
616 self
.level
> self
.Args
[0].level
:
617 result
= result
+ "(" + str(self
.Args
[0]) + ")"
619 result
= result
+ str(self
.Args
[0])
620 result
= result
+ self
.symbol
621 if isinstance(self
.Args
[1], MathTreeOp
) and\
622 self
.level
>= self
.Args
[1].level
:
623 result
= result
+ "(" + str(self
.Args
[1]) + ")"
625 result
= result
+ str(self
.Args
[1])
628 def InitByParser(self
, arg
):
629 return arg
.MatchStr(self
.symbol
)
632 class MathTreeOpAdd(MathTreeOp
):
634 def __init__(self
, *args
):
635 MathTreeOp
.__init
__(self
, 1, "+", *args
)
637 def CalcDerivative(self
, arg
):
638 if self
.Args
[0].DependOn(arg
):
639 if self
.Args
[1].DependOn(arg
):
640 return MathTreeOpAdd(
641 self
.Args
[0].CalcDerivative(arg
),
642 self
.Args
[1].CalcDerivative(arg
))
644 return self
.Args
[0].CalcDerivative(arg
)
646 if self
.Args
[1].DependOn(arg
):
647 return self
.Args
[1].CalcDerivative(arg
)
649 def Calc(HIDDEN_self
, **args
):
650 return HIDDEN_self
.Args
[0].Calc(**args
) + HIDDEN_self
.Args
[1].Calc(**args
)
653 class MathTreeOpSub(MathTreeOp
):
655 def __init__(self
, *args
):
656 MathTreeOp
.__init
__(self
, 1, "-", *args
)
658 def CalcDerivative(self
, arg
):
659 if self
.Args
[0].DependOn(arg
):
660 if self
.Args
[1].DependOn(arg
):
661 return MathTreeOpSub(
662 self
.Args
[0].CalcDerivative(arg
),
663 self
.Args
[1].CalcDerivative(arg
))
665 return self
.Args
[0].CalcDerivative(arg
)
667 if self
.Args
[1].DependOn(arg
):
668 return MathTreeFunc1Neg(self
.Args
[1].CalcDerivative(arg
))
670 def Calc(HIDDEN_self
, **args
):
671 return HIDDEN_self
.Args
[0].Calc(**args
) - HIDDEN_self
.Args
[1].Calc(**args
)
674 class MathTreeOpMul(MathTreeOp
):
676 def __init__(self
, *args
):
677 MathTreeOp
.__init
__(self
, 2, "*", *args
)
679 def CalcDerivative(self
, arg
):
680 if self
.Args
[0].DependOn(arg
):
681 if self
.Args
[1].DependOn(arg
):
682 return MathTreeOpAdd(
685 self
.Args
[1].CalcDerivative(arg
)),
687 self
.Args
[0].CalcDerivative(arg
),
690 return MathTreeOpMul(
691 self
.Args
[0].CalcDerivative(arg
),
694 if self
.Args
[1].DependOn(arg
):
695 return MathTreeOpMul(
697 self
.Args
[1].CalcDerivative(arg
))
699 def Calc(HIDDEN_self
, **args
):
700 return HIDDEN_self
.Args
[0].Calc(**args
) * HIDDEN_self
.Args
[1].Calc(**args
)
703 class MathTreeOpDiv(MathTreeOp
):
705 def __init__(self
, *args
):
706 MathTreeOp
.__init
__(self
, 2, "/", *args
)
708 def CalcDerivative(self
, arg
):
709 if self
.Args
[0].DependOn(arg
):
710 if self
.Args
[1].DependOn(arg
):
711 return MathTreeOpMul(
714 self
.Args
[0].CalcDerivative(arg
),
718 self
.Args
[1].CalcDerivative(arg
))),
721 MathTreeValConst(-2.0)))
723 return MathTreeOpDiv(
724 self
.Args
[0].CalcDerivative(arg
),
727 if self
.Args
[1].DependOn(arg
):
728 return MathTreeOpMul(
730 MathTreeFunc1Neg(self
.Args
[0]),
733 MathTreeValConst(-2.0))),
734 self
.Args
[1].CalcDerivative(arg
))
736 def Calc(HIDDEN_self
, **args
):
737 return HIDDEN_self
.Args
[0].Calc(**args
) / HIDDEN_self
.Args
[1].Calc(**args
)
740 class MathTreeOpPow(MathTreeOp
):
742 def __init__(self
, *args
):
743 MathTreeOp
.__init
__(self
, 3, "^", *args
)
745 def InitByParser(self
, arg
):
746 pos
= arg
.MatchStr("^")
750 return arg
.MatchStr("**")
752 def CalcDerivative(self
, arg
):
753 if self
.Args
[0].DependOn(arg
):
754 if self
.Args
[1].DependOn(arg
):
755 return MathTreeOpMul(
761 MathTreeFunc1Log(self
.Args
[0]),
762 self
.Args
[1].CalcDerivative(arg
)),
766 self
.Args
[0].CalcDerivative(arg
),
769 return MathTreeOpMul(
776 MathTreeValConst(1.0))),
777 self
.Args
[0].CalcDerivative(arg
)))
779 if self
.Args
[1].DependOn(arg
):
780 return MathTreeOpMul(
785 MathTreeFunc1Log(self
.Args
[0])),
786 self
.Args
[1].CalcDerivative(arg
))
788 def Calc(HIDDEN_self
, **args
):
789 return HIDDEN_self
.Args
[0].Calc(**args
) ** HIDDEN_self
.Args
[1].Calc(**args
)
793 class UndefinedMathTreeParseError(Exception):
795 def __init__(self
, ParseStr
, MathTree
):
796 self
.ParseStr
= ParseStr
797 self
.MathTree
= MathTree
800 return "\n" + str(self
.ParseStr
)
803 class RightParenthesisExpectedMathTreeParseError(UndefinedMathTreeParseError
): pass
804 class RightParenthesisFoundMathTreeParseError(UndefinedMathTreeParseError
): pass
805 class CommaExpectedMathTreeParseError(UndefinedMathTreeParseError
): pass
806 class CommaFoundMathTreeParseError(UndefinedMathTreeParseError
): pass
807 class OperatorExpectedMathTreeParseError(UndefinedMathTreeParseError
): pass
808 class OperandExpectedMathTreeParseError(UndefinedMathTreeParseError
): pass
811 DefaultMathTreeOps
= (MathTreeOpPow
, MathTreeOpDiv
, MathTreeOpMul
, MathTreeOpSub
, MathTreeOpAdd
)
812 DefaultMathTreeFuncs
= (MathTreeFunc1Neg
, MathTreeFunc1Abs
, MathTreeFunc1Sgn
, MathTreeFunc1Sqrt
,
813 MathTreeFunc1Exp
, MathTreeFunc1Log
,
814 MathTreeFunc1Sin
, MathTreeFunc1Cos
, MathTreeFunc1Tan
,
815 MathTreeFunc1ASin
, MathTreeFunc1ACos
, MathTreeFunc1ATan
,
816 MathTreeFunc1SinD
, MathTreeFunc1CosD
, MathTreeFunc1TanD
,
817 MathTreeFunc1ASinD
, MathTreeFunc1ACosD
, MathTreeFunc1ATanD
,
820 DefaultMathTreeVals
= (MathTreeValConst
, MathTreeValVar
)
824 def __init__(self
, MathTreeOps
=DefaultMathTreeOps
,
825 MathTreeFuncs
=DefaultMathTreeFuncs
,
826 MathTreeVals
=DefaultMathTreeVals
):
827 self
.MathTreeOps
= MathTreeOps
828 self
.MathTreeFuncs
= MathTreeFuncs
829 self
.MathTreeVals
= MathTreeVals
832 def parse(self
, str):
833 if __useparser__
== __oldparser__
:
834 return self
.old_parse(str)
835 elif __useparser__
== __newparser__
:
836 return self
.new_parse(str)
838 RuntimeError("invalid __useparser__")
840 def old_parse(self
, str):
841 return self
.ParseMathTree(ParseStr(str))
843 def new_parse(self
, str):
844 # prepare raw string:
846 thestr
= re
.sub("^\s*", "", str)
847 thestr
= re
.sub("\^","**", thestr
) # to be removed <joergl>
848 thestr
= re
.sub("\$","_col_", thestr
)
849 return self
.astseq2mtree(pythonparser
.expr(thestr
).totuple())
851 def ParseMathTree(self
, arg
):
853 #Match = arg.MatchPattern(re.compile(r"\s*-(?![0-9\.])"))
854 Match
= arg
.MatchPattern(re
.compile(r
"\s*-")) # XXX another quick workaround
856 #Tree = MathTreeFunc1Neg()
857 Tree
= MathTreeOpSub(MathTreeValConst(0)) # XXX quick workaround
859 i
= arg
.MatchStr("(")
862 self
.ParseMathTree(arg
)
863 raise RightParenthesisExpectedMathTreeParseError(arg
, Tree
)
864 except RightParenthesisFoundMathTreeParseError
, e
:
865 if isinstance(e
.MathTree
, MathTreeOp
):
866 e
.MathTree
.ParenthesisBarrier
= 1
868 SubTree
= Tree
# XXX: four lines code dublication
869 while isinstance(SubTree
, MathTreeOp
) and len(SubTree
.Args
) == 2:
870 SubTree
= SubTree
.Args
[1]
871 SubTree
.AddArg(e
.MathTree
)
875 for FuncClass
in self
.MathTreeFuncs
:
877 if Func
.InitByParser(arg
):
879 SubTree
= Tree
# XXX: four lines code dublication
880 while isinstance(SubTree
, MathTreeOp
) and len(SubTree
.Args
) == 2:
881 SubTree
= SubTree
.Args
[1]
887 self
.ParseMathTree(arg
)
888 raise RightParenthesisExpectedMathTreeParseError(arg
, Tree
)
889 except CommaFoundMathTreeParseError
, e
:
891 Func
.AddArg(e
.MathTree
, NotLast
=1)
892 except ArgCountError
:
893 raise RightParenthesisExpectedMathTreeParseError(arg
, Tree
)
895 except RightParenthesisFoundMathTreeParseError
, e
:
897 Func
.AddArg(e
.MathTree
, Last
=1)
898 except ArgCountError
:
899 raise CommaExpectedMathTreeParseError(arg
, Tree
)
903 FuncExtern
= MathTreeFuncExtern()
904 if FuncExtern
.InitByParser(arg
):
906 SubTree
= Tree
# XXX: four lines code dublication
907 while isinstance(SubTree
, MathTreeOp
) and len(SubTree
.Args
) == 2:
908 SubTree
= SubTree
.Args
[1]
909 SubTree
.AddArg(FuncExtern
)
914 self
.ParseMathTree(arg
)
915 raise RightParenthesisExpectedMathTreeParseError(arg
, Tree
)
916 except CommaFoundMathTreeParseError
, e
:
917 FuncExtern
.AddArg(e
.MathTree
)
919 except RightParenthesisFoundMathTreeParseError
, e
:
920 FuncExtern
.AddArg(e
.MathTree
)
923 for ValClass
in self
.MathTreeVals
:
925 if Val
.InitByParser(arg
):
927 SubTree
= Tree
# XXX: four lines code dublication
928 while isinstance(SubTree
, MathTreeOp
) and len(SubTree
.Args
) == 2:
929 SubTree
= SubTree
.Args
[1]
935 raise OperandExpectedMathTreeParseError(arg
, Tree
)
938 i
= arg
.MatchStr(")")
940 raise RightParenthesisFoundMathTreeParseError(arg
, Tree
)
941 i
= arg
.MatchStr(",")
943 raise CommaFoundMathTreeParseError(arg
, Tree
)
944 for OpClass
in self
.MathTreeOps
:
946 if Op
.InitByParser(arg
):
949 while isinstance(SubTree
, MathTreeOp
) and\
950 Op
.level
> SubTree
.level
and\
951 not SubTree
.ParenthesisBarrier
:
952 SubTreeRoot
= SubTree
953 SubTree
= SubTree
.Args
[1]
956 SubTreeRoot
.Args
[1] = Op
962 raise OperatorExpectedMathTreeParseError(arg
, Tree
)
965 def astseq2mtree(self
, astseq
, isfunc
=0):
966 # astseq has to be a sequence!
969 if token
.ISTERMINAL(astseq
[0]):
972 if astseq
[0] == symbol
.arith_expr
: # {{{
974 # 1. arith_expr "PLUS" term
975 if astseq
[-2][0] == token
.PLUS
:
976 tree
= MathTreeOpAdd(
977 self
.astseq2mtree(astseq
[:-2], isfunc
=isfunc
),
978 self
.astseq2mtree(astseq
[-1], isfunc
=isfunc
))
979 # 2. arith_expr "MINUS" term
980 elif astseq
[-2][0] == token
.MINUS
:
981 tree
= MathTreeOpSub(
982 self
.astseq2mtree(astseq
[:-2], isfunc
=isfunc
),
983 self
.astseq2mtree(astseq
[-1], isfunc
=isfunc
))
988 tree
= self
.astseq2mtree(astseq
[1], isfunc
=isfunc
)
991 if astseq
[0] == symbol
.term
: # {{{
993 # 1. term "STAR" factor
994 if astseq
[-2][0] == token
.STAR
:
995 tree
= MathTreeOpMul(
996 self
.astseq2mtree(astseq
[:-2], isfunc
=isfunc
),
997 self
.astseq2mtree(astseq
[-1], isfunc
=isfunc
))
998 # 2. term "SLASH" factor
999 elif astseq
[-2][0] == token
.SLASH
:
1000 tree
= MathTreeOpDiv(
1001 self
.astseq2mtree(astseq
[:-2], isfunc
=isfunc
),
1002 self
.astseq2mtree(astseq
[-1], isfunc
=isfunc
))
1007 tree
= self
.astseq2mtree(astseq
[1], isfunc
=isfunc
)
1010 if astseq
[0] == symbol
.factor
: # {{{
1011 if len(astseq
) == 3:
1013 if astseq
[1][0] == token
.PLUS
:
1014 tree
= self
.astseq2mtree(astseq
[2], isfunc
=isfunc
)
1016 elif astseq
[1][0] == token
.MINUS
:
1017 tree
= MathTreeFunc1Neg(self
.astseq2mtree(astseq
[2], isfunc
=isfunc
))
1019 raise Exception("unknown factor")
1020 elif len(astseq
) == 2:
1022 tree
= self
.astseq2mtree(astseq
[1], isfunc
=isfunc
)
1024 raise Exception("wrong length of factor")
1027 if astseq
[0] == symbol
.power
: # {{{
1029 # 1. "DOUBLESTAR" factor
1030 if astseq
[-2][0] == token
.DOUBLESTAR
:
1031 tree
= MathTreeOpPow(
1032 self
.astseq2mtree(astseq
[:-2], isfunc
=isfunc
),
1033 self
.astseq2mtree(astseq
[-1], isfunc
=isfunc
))
1037 # 2. atom + [trailer]
1038 if len(astseq
) == 3:
1039 # we have a function call atom + "LPAR" + argumentlist + "RPAR"
1040 if astseq
[2][0] != symbol
.trailer
or \
1041 astseq
[2][1][0] != token
.LPAR
or \
1042 astseq
[2][2][0] != symbol
.arglist
or \
1043 astseq
[2][3][0] != token
.RPAR
:
1044 raise Exception("wrong function call")
1045 tree
= self
.astseq2mtree(astseq
[1], isfunc
=1)
1046 for subtree
in self
.astseq2mtree(astseq
[2][2], isfunc
=0):
1047 tree
.AddArg(subtree
)
1049 tree
= self
.astseq2mtree(astseq
[1], isfunc
=0)
1053 if astseq
[0] == symbol
.atom
: # {{{
1054 # only one nontrivial term:
1055 if len(astseq
) == 2:
1056 if astseq
[1][0] == token
.NUMBER
:
1058 # XXX: for evaluation of brackets we will need integers as well
1059 tree
= MathTreeValConst(string
.atof(astseq
[1][1]))
1060 elif astseq
[1][0] == token
.NAME
:
1064 for funcclass
in self
.MathTreeFuncs
:
1065 func
= funcclass() # ist das guenstig, da jedesmal eine Instanz zu erzeugen?
1066 # doofe Frage, nein! <wobsta>
1067 if func
.name
== astseq
[1][1]:
1069 # an unknown function
1070 tree
= MathTreeFuncExtern()
1071 tree
.SetName(astseq
[1][1])
1073 # 3. a named constant
1074 for const
in MathConst
.keys():
1075 # XXX: change to self.MathConstants
1076 if const
== astseq
[1][1]:
1077 return MathTreeValConst(MathConst
[const
])
1079 return MathTreeValVar(astseq
[1][1])
1080 elif len(astseq
) == 4:
1081 # parentheses or brackets for structuring an atom
1082 if (astseq
[1][0] == token
.LPAR
and astseq
[3][0] == token
.RPAR
) or \
1083 (astseq
[1][0] == token
.LSQB
and astseq
[3][0] == token
.RSQB
):
1084 tree
= self
.astseq2mtree(astseq
[2], isfunc
=isfunc
)
1086 raise Exception("symbol.atom with unknown number of arguments")
1089 if astseq
[0] == symbol
.arglist
: # {{{
1091 for arg
in astseq
[1:]:
1092 if arg
[0] == token
.COMMA
:
1094 elif arg
[0] == symbol
.argument
:
1095 treelist
.append(self
.astseq2mtree(arg
, isfunc
=isfunc
))
1096 return treelist
# }}}
1098 if astseq
[0] == symbol
.testlist
: # {{{
1100 for arg
in astseq
[1:]:
1101 if arg
[0] == token
.COMMA
:
1103 elif arg
[0] == symbol
.test
:
1104 treelist
.append(self
.astseq2mtree(arg
, isfunc
=isfunc
))
1105 if len(treelist
) == 1: return treelist
[0]
1106 else: return treelist
# }}}
1108 return self
.astseq2mtree(astseq
[1], isfunc
=isfunc
)