Initial SymPy benchmark suite
[sympy.git] / sympy / core / ast_parser.py
blobcc7f2c25904a97f0565d5752a97dff12a7b93026
1 import compiler
2 import parser
3 from compiler.transformer import Transformer
4 from compiler.visitor import ASTVisitor
5 from compiler.ast import CallFunc, Name, Const, Tuple
6 from compiler.pycodegen import ExpressionCodeGenerator
7 import re
9 from basic import Basic
10 from function import FunctionClass
11 from symbol import Symbol
13 ###################################################3
14 # HELPERS
15 ###################################################3
17 _is_integer = re.compile(r'\A\d+(l|L)?\Z').match
19 int_types = (int, long)
20 float_types = (float)
21 complex_types = (complex)
22 string_types = (str) # XXX: unicode?
23 classes = Basic
25 ###################################################3
26 # CODE
27 ###################################################3
29 class SymPyTransformer(Transformer):
30 def __init__(self, local_dict, global_dict):
31 Transformer.__init__(self)
33 self.symbol_class = 'Symbol'
35 self.local_dict = local_dict
36 self.global_dict = global_dict
38 def atom_number(self, nodelist):
39 n = Transformer.atom_number(self, nodelist)
40 number, lineno = nodelist[0][1:]
41 if _is_integer(number):
42 n = Const(long(number), lineno)
43 return CallFunc(Name('Integer'), [n])
44 if number.endswith('j'):
45 n = Const(complex(number), lineno)
46 return CallFunc(Name('sympify'), [n])
47 n = Const(number, lineno)
48 return CallFunc(Name('Real'), [n])
50 def atom_name(self, nodelist):
51 name, lineno = nodelist[0][1:]
53 if self.local_dict.has_key(name):
54 name_obj = self.local_dict[name]
55 return Const(name_obj, lineno=lineno)
56 elif self.global_dict.has_key(name):
57 name_obj = self.global_dict[name]
59 if isinstance(name_obj, (Basic, type)) or callable(name_obj):
60 return Const(name_obj, lineno=lineno)
61 elif name in ['True', 'False']:
62 return Const(eval(name), lineno=lineno)
64 symbol_obj = Symbol(name)
65 self.local_dict[name] = symbol_obj
67 return Const(symbol_obj, lineno=lineno)
69 def lambdef(self, nodelist):
70 #this is python stdlib symbol, not SymPy symbol:
71 from sympy import stdlib_symbol
72 if nodelist[2][0] == stdlib_symbol.varargslist:
73 names, defaults, flags = self.com_arglist(nodelist[2][1:])
74 else:
75 names = defaults = ()
76 flags = 0
78 lineno = nodelist[1][2]
79 code = self.com_node(nodelist[-1])
81 assert not defaults,`defaults` # sympy.Lambda does not support optional arguments
82 assert len(names) <= 1
84 if len(names) > 0:
85 argument = CallFunc( Name('Symbol'), [Const(names[0], lineno=lineno)])
86 else:
87 argument = CallFunc( Name('Symbol'), [Const('x')])
89 return CallFunc(Name('Lambda'),[argument, code])
92 class SymPyParser:
93 def __init__(self, local_dict={}): #Contents of local_dict change, but it has proper effect only in global scope
94 global_dict = {}
95 exec 'from sympy import *' in global_dict
97 self.r_transformer = SymPyTransformer(local_dict, global_dict)
98 self.local_dict = local_dict
99 self.global_dict = global_dict
101 def parse_expr(self, ws_expression):
102 expression = ws_expression.strip() #in case of " x"
103 ast_tree = parser.expr(expression)
104 ast_tree = self.r_transformer.transform(ast_tree)
106 compiler.misc.set_filename('<sympify>', ast_tree)
107 code = ExpressionCodeGenerator(ast_tree).getCode()
109 parsed_expr = eval(code, self.local_dict, self.global_dict) #Changed order to prefer sympy objects to user defined
111 return parsed_expr