Salome HOME
Merge multi-study removal branch.
[modules/yacs.git] / src / py2yacs / py2yacs.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 *-
3 # Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
4 #
5 # Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
6 # CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
7 #
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Lesser General Public
10 # License as published by the Free Software Foundation; either
11 # version 2.1 of the License, or (at your option) any later version.
12 #
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 # Lesser General Public License for more details.
17 #
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with this library; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21 #
22 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #
24 import ast
25
26 class FunctionProperties:
27   def __init__(self, function_name):
28     self.name = function_name
29     self.inputs=[]
30     self.outputs=None
31     self.errors=[]
32     self.imports=[]
33     pass
34   def __str__(self):
35     result = "Function:" + self.name + "\n"
36     result+= "  Inputs:" + str(self.inputs) + "\n"
37     result+= "  Outputs:"+ str(self.outputs) + "\n"
38     result+= "  Errors:" + str(self.errors) + "\n"
39     result+= "  Imports:"+ str(self.imports) + "\n"
40     return result
41
42 class v(ast.NodeVisitor):
43   def visit_Module(self, node):
44     #print type(node).__name__, ":"
45     accepted_tokens = ["Import", "ImportFrom", "FunctionDef", "ClassDef"]
46     #print "module body:"
47     self.global_errors=[]
48     for e in node.body:
49       type_name = type(e).__name__
50       if type_name not in accepted_tokens:
51         error="py2yacs error at line %s: not accepted statement '%s'." % (
52                e.lineno, type_name)
53         self.global_errors.append(error)
54       #print type_name
55     #print "------------------------------------------------------------------"
56     self.functions=[]
57     self.lastfn=""
58     self.infunc=False
59     self.inargs=False
60     self.generic_visit(node)
61     pass
62   def visit_FunctionDef(self, node):
63     #print type(node).__name__, ":", node.name
64     if not self.infunc:
65       self.lastfn = FunctionProperties(node.name)
66       self.functions.append(self.lastfn)
67       self.infunc=True
68       #
69       self.generic_visit(node)
70       #
71       self.lastfn = None
72       self.infunc=False
73     pass
74   def visit_arguments(self, node):
75     #print type(node).__name__, ":"
76     self.inargs=True
77     self.generic_visit(node)
78     self.inargs=False
79     pass
80   def visit_Name(self, node):
81     if self.inargs :
82       #print type(node).__name__, ":", node.id
83       self.lastname=node.id
84       self.generic_visit(node)
85     pass
86   def visit_Param(self, node):
87     #print type(node).__name__, ":", self.lastname
88     self.lastfn.inputs.append(self.lastname)
89     pass
90   def visit_Return(self, node):
91     #print type(node).__name__, ":", node.value
92     if self.lastfn.outputs is not None :
93       error="py2yacs error at line %s: multiple returns." % node.lineno
94       self.lastfn.errors.append(error)
95       return
96     self.lastfn.outputs = []
97     if node.value is None :
98       pass
99     elif 'Tuple' == type(node.value).__name__ :
100       for e in node.value.elts:
101         if 'Name' == type(e).__name__ :
102           self.lastfn.outputs.append(e.id)
103         else :
104           error="py2yacs error at line %s: invalid type returned '%s'." % (
105                   node.lineno, type(e).__name__)
106           self.lastfn.errors.append(error)
107     else:
108       if 'Name' == type(node.value).__name__ :
109         self.lastfn.outputs.append(node.value.id)
110       else :
111         error="py2yacs error at line %s: invalid type returned '%s'." %(
112                   node.lineno, type(node.value).__name__)
113         self.lastfn.errors.append(error)
114         pass
115       pass
116     pass
117
118   def visit_ClassDef(self, node):
119     # just ignore classes
120     pass
121
122   def visit_Import(self, node):
123     if self.infunc:
124       for n in node.names:
125         self.lastfn.imports.append(n.name)
126   def visit_ImportFrom(self, node):
127     if self.infunc:
128       m=node.module
129       for n in node.names:
130         self.lastfn.imports.append(m+"."+n.name)
131
132 class vtest(ast.NodeVisitor):
133   def generic_visit(self, node):
134     #print type(node).__name__
135     ast.NodeVisitor.generic_visit(self, node)
136
137 def create_yacs_schema(text, fn_name, fn_args, fn_returns, file_name):
138   import pilot
139   import SALOMERuntime
140   #import loader
141   SALOMERuntime.RuntimeSALOME_setRuntime()
142   runtime = pilot.getRuntime()
143   schema = runtime.createProc("schema")
144   node = runtime.createFuncNode("", "default_name")
145   schema.edAddChild(node)
146   fncall = "\n%s=%s(%s)\n"%(",".join(fn_returns),
147                             fn_name,
148                             ",".join(fn_args))
149   node.setScript(text+fncall)
150   node.setFname(fn_name)
151   td=schema.getTypeCode("double")
152   for p in fn_args:
153     node.edAddInputPort(p, td)
154   for p in fn_returns:
155     node.edAddOutputPort(p, td)
156   schema.saveSchema(file_name)
157
158 def get_properties(text_file):
159   bt=ast.parse(text_file)
160   w=v()
161   w.visit(bt)
162   return w.functions, w.global_errors
163
164 if __name__ == '__main__':
165   import argparse
166   parser = argparse.ArgumentParser(description="Generate a YACS schema from a python file containing a function to run.")
167   parser.add_argument("file", help='Path to the python file')
168   parser.add_argument("-o","--output",
169         help='Path to the output file (yacs_schema.xml by default)',
170         default='yacs_schema.xml')
171   parser.add_argument("-d","--def_name",
172         help='Name of the function to call in the yacs node (_exec by default)',
173         default='_exec')
174   args = parser.parse_args()
175   with open(args.file, 'r') as f:
176     text_file = f.read()
177   #bt=ast.parse(text_file)
178   #w=vtest()
179   #w=v()
180   #w.visit(bt)
181   #print "global errors:", w.global_errors
182   #for f in w.functions:
183   #  print f
184   
185   fn_name = args.def_name
186   functions,errors = get_properties(text_file)
187   print "global errors:", errors
188   for f in functions:
189     print f
190   
191   fn_properties = next((f for f in functions if f.name == fn_name), None)
192   if fn_properties is not None :
193     if not fn_properties.errors :
194       create_yacs_schema(text_file, fn_name,
195                        fn_properties.inputs, fn_properties.outputs,
196                        args.output)
197     else:
198       print "\n".join(fn_properties.errors)
199   else:
200     print "Function not found:", fn_name
201