source: sasmodels/sasmodels/py2c.py @ fa74acf

Last change on this file since fa74acf was fa74acf, checked in by Omer Eisenberg <omereis@…>, 6 years ago

modified to fix some pylint errors

  • Property mode set to 100644
File size: 38.2 KB
Line 
1
2"""
3    codegen
4    ~~~~~~~
5
6    Extension to ast that allow ast -> python code generation.
7
8    :copyright: Copyright 2008 by Armin Ronacher.
9    :license: BSD.
10"""
11"""
12    Variables definition in C
13    -------------------------
14    Defining variables within the Translate function is a bit of a guess work,
15    using following rules.
16    *   By default, a variable is a 'double'.
17    *   Variable in a for loop is an int.
18    *   Variable that is references with brackets is an array of doubles. The
19        variable within the brackets is integer. For example, in the
20        reference 'var1[var2]', var1 is a double array, and var2 is an integer.
21    *   Assignment to an argument makes that argument an array, and the index in
22        that assignment is 0.
23        For example, the following python code
24            def func(arg1, arg2):
25                arg2 = 17.
26        is translated to the following C code
27            double func(double arg1)
28            {
29                arg2[0] = 17.0;
30            }
31        For example, the following python code is translated to the following C code
32            def func(arg1, arg2):          double func(double arg1) {
33                arg2 = 17.                      arg2[0] = 17.0;
34                                            }
35    *   All functions are defined as double, even if there is no return statement.
36
37
38Update Notes
39============
4011/22 14:15, O.E.   Each 'visit_*' method is to build a C statement string. It
41                    shold insert 4 blanks per indentation level.
42                    The 'body' method will combine all the strings, by adding
43                    the 'current_statement' to the c_proc string list
44   11/2017, OE: variables, argument definition implemented.
45   Note: An argument is considered an array if it is the target of an
46        assignment. In that case it is translated to <var>[0]
4711/27/2017, OE: 'pow' basicly working
48  /12/2017, OE: Multiple assignment: a1,a2,...,an=b1,b2,...bn implemented
49  /12/2017, OE: Power function, including special cases of
50                square(x)(pow(x,2)) and cube(x)(pow(x,3)), implemented in
51                translate_power, called from visit_BinOp
5212/07/2017, OE: Translation of integer division, '\\' in python, implemented
53                in translate_integer_divide, called from visit_BinOp
5412/07/2017, OE: C variable definition handled in 'define_C_Vars'
55              : Python integer division, '//', translated to C in
56                'translate_integer_divide'
5712/15/2017, OE: Precedence maintained by writing opening and closing
58                parenthesesm '(',')', in procedure 'visit_BinOp'.
59"""
60import ast
61import sys
62from ast import NodeVisitor
63
64BINOP_SYMBOLS = {}
65BINOP_SYMBOLS[ast.Add] = '+'
66BINOP_SYMBOLS[ast.Sub] = '-'
67BINOP_SYMBOLS[ast.Mult] = '*'
68BINOP_SYMBOLS[ast.Div] = '/'
69BINOP_SYMBOLS[ast.Mod] = '%'
70BINOP_SYMBOLS[ast.Pow] = '**'
71BINOP_SYMBOLS[ast.LShift] = '<<'
72BINOP_SYMBOLS[ast.RShift] = '>>'
73BINOP_SYMBOLS[ast.BitOr] = '|'
74BINOP_SYMBOLS[ast.BitXor] = '^'
75BINOP_SYMBOLS[ast.BitAnd] = '&'
76BINOP_SYMBOLS[ast.FloorDiv] = '//'
77
78BOOLOP_SYMBOLS = {}
79BOOLOP_SYMBOLS[ast.And] = '&&'
80BOOLOP_SYMBOLS[ast.Or]  = '||'
81
82CMPOP_SYMBOLS = {}
83CMPOP_SYMBOLS[ast.Eq]    = '=='
84CMPOP_SYMBOLS[ast.NotEq] = '!='
85CMPOP_SYMBOLS[ast.Lt] = '<'
86CMPOP_SYMBOLS[ast.LtE] = '<='
87CMPOP_SYMBOLS[ast.Gt] = '>'
88CMPOP_SYMBOLS[ast.GtE] = '>='
89CMPOP_SYMBOLS[ast.Is] = 'is'
90CMPOP_SYMBOLS[ast.IsNot] = 'is not'
91CMPOP_SYMBOLS[ast.In] = 'in'
92CMPOP_SYMBOLS[ast.NotIn] = 'not in'
93
94UNARYOP_SYMBOLS = {}
95UNARYOP_SYMBOLS[ast.Invert] = '~'
96UNARYOP_SYMBOLS[ast.Not] = 'not'
97UNARYOP_SYMBOLS[ast.UAdd] = '+'
98UNARYOP_SYMBOLS[ast.USub] = '-'
99
100
101#def to_source(node, indent_with=' ' * 4, add_line_information=False):
102def to_source(node, func_name):
103    """This function can convert a node tree back into python sourcecode.
104    This is useful for debugging purposes, especially if you're dealing with
105    custom asts not generated by python itself.
106
107    It could be that the sourcecode is evaluable when the AST itself is not
108    compilable / evaluable.  The reason for this is that the AST contains some
109    more data than regular sourcecode does, which is dropped during
110    conversion.
111
112    Each level of indentation is replaced with `indent_with`.  Per default this
113    parameter is equal to four spaces as suggested by PEP 8, but it might be
114    adjusted to match the application's styleguide.
115
116    If `add_line_information` is set to `True` comments for the line numbers
117    of the nodes are added to the output.  This can be used to spot wrong line
118    number information of statement nodes.
119    """
120    generator = SourceGenerator(' ' * 4, False)
121#    generator.required_functions = func_name
122    generator.visit(node)
123
124#    return ''.join(generator.result)
125    return ''.join(generator.c_proc)
126
127def isevaluable(s):
128    try:
129        eval(s)
130        return True
131    except:
132        return False
133
134class SourceGenerator(NodeVisitor):
135    """This visitor is able to transform a well formed syntax tree into python
136    sourcecode.  For more details have a look at the docstring of the
137    `node_to_source` function.
138    """
139
140    def __init__(self, indent_with, add_line_information=False):
141        self.result = []
142        self.indent_with = indent_with
143        self.add_line_information = add_line_information
144        self.indentation = 0
145        self.new_lines = 0
146        self.c_proc = []
147# for C
148        self.signature_line = 0
149        self.arguments = []
150        self.name = ""
151        self.warnings = []
152        self.Statements = []
153        self.current_statement = ""
154        self.strMethodSignature = ""
155        self.C_Vars = []
156        self.C_IntVars = []
157        self.MathIncludeed = False
158        self.C_Pointers = []
159        self.C_DclPointers = []
160        self.C_Functions = []
161        self.C_Vectors = []
162        self.SubRef = False
163        self.InSubscript = False
164        self.Tuples = []
165        self.required_functions = []
166        self.is_sequence = False
167        self.visited_args = False
168
169    def write_python(self, x):
170        if self.new_lines:
171            if self.result:
172                self.result.append('\n' * self.new_lines)
173            self.result.append(self.indent_with * self.indentation)
174            self.new_lines = 0
175        self.result.append(x)
176
177    def write_c(self, x):
178        self.current_statement += x
179
180    def add_c_line(self, x):
181        string = ''
182        for i in range(self.indentation):
183            string += ("    ")
184        string += str(x)
185        self.c_proc.append(str(string + "\n"))
186        x = ''
187
188    def add_current_line(self):
189        if(len(self.current_statement) > 0):
190            self.add_c_line(self.current_statement)
191            self.current_statement = ''
192
193    def AddUniqueVar(self, new_var):
194        if((new_var not in self.C_Vars)):
195            self.C_Vars.append(str(new_var))
196
197    def WriteSincos(self, node):
198        angle = str(node.args[0].id)
199        self.write_c(node.args[1].id + " = sin(" + angle + ");")
200        self.add_current_line()
201        self.write_c(node.args[2].id + " = cos(" + angle + ");")
202        self.add_current_line()
203        for arg in node.args:
204            self.AddUniqueVar(arg.id)
205
206    def newline(self, node=None, extra=0):
207        self.new_lines = max(self.new_lines, 1 + extra)
208        if node is not None and self.add_line_information:
209            self.write_c('# line: %s' % node.lineno)
210            self.new_lines = 1
211        if(len(self.current_statement)):
212            self.Statements.append(self.current_statement)
213            self.current_statement = ''
214
215    def body(self, statements):
216        if(len(self.current_statement)):
217            self.add_current_line()
218        self.new_line = True
219        self.indentation += 1
220        for stmt in statements:
221            target_name = ''
222            if(hasattr(stmt, 'targets')):
223                if(hasattr(stmt.targets[0], 'id')):
224                    target_name = stmt.targets[0].id # target name needed for debug only
225            self.visit(stmt)
226        self.add_current_line() # just for breaking point. to be deleted.
227        self.indentation -= 1
228
229    def body_or_else(self, node):
230        self.body(node.body)
231        if node.orelse:
232            self.newline()
233            self.write_c('else:')
234            self.body(node.orelse)
235
236    def signature(self, node):
237        want_comma = []
238        def write_comma():
239            if want_comma:
240                self.write_c(', ')
241            else:
242                want_comma.append(True)
243# for C
244        for arg in node.args:
245            self.arguments.append(arg.arg)
246
247        padding = [None] *(len(node.args) - len(node.defaults))
248        for arg, default in zip(node.args, padding + node.defaults):
249            if default is not None:
250                self.warnings.append("Default Parameter unknown to C")
251                w_str = "Default Parameters are unknown to C: '" + arg.arg + \
252                        " = " + str(default.n) + "'"
253                self.warnings.append(w_str)
254#                self.write_python('=')
255#                self.visit(default)
256
257    def decorators(self, node):
258        for decorator in node.decorator_list:
259            self.newline(decorator)
260            self.write_python('@')
261            self.visit(decorator)
262
263    # Statements
264
265    def visit_Assert(self, node):
266        self.newline(node)
267        self.write_c('assert ')
268        self.visit(node.test)
269        if node.msg is not None:
270            self.write_python(', ')
271            self.visit(node.msg)
272
273    def define_C_Vars(self, target):
274        if(hasattr(target, 'id')):
275# a variable is considered an array if it apears in the agrument list
276# and being assigned to. For example, the variable p in the following
277# sniplet is a pointer, while q is not
278# def somefunc(p, q):
279#  p = q + 1
280#  return
281#
282            if(target.id not in self.C_Vars):
283                if(target.id in self.arguments):
284                    idx = self.arguments.index(target.id)
285                    new_target = self.arguments[idx] + "[0]"
286                    if(new_target not in self.C_Pointers):
287                        target.id = new_target
288                        self.C_Pointers.append(self.arguments[idx])
289                else:
290                    self.C_Vars.append(target.id)
291
292    def add_semi_colon(self):
293        semi_pos = self.current_statement.find(';')
294        if(semi_pos < 0):
295            self.write_c(';')
296
297    def visit_Assign(self, node):
298        self.add_current_line()
299        for idx, target in enumerate(node.targets): # multi assign, as in 'a = b = c = 7'
300            if idx:
301                self.write_c(' = ')
302            self.define_C_Vars(target)
303            self.visit(target)
304        if(len(self.Tuples) > 0):
305            tplTargets = list(self.Tuples)
306            self.Tuples.clear()
307        self.write_c(' = ')
308        self.is_sequence = False
309        self.visited_args = False
310        self.visit(node.value)
311        self.add_semi_colon()
312#        self.write_c(';')
313        self.add_current_line()
314        for n, item in enumerate(self.Tuples):
315            self.visit(tplTargets[n])
316            self.write_c(' = ')
317            self.visit(item)
318            self.add_semi_colon()
319            self.add_current_line()
320        if((self.is_sequence) and (not self.visited_args)):
321            for target in node.targets:
322                if(hasattr(target, 'id')):
323                    if((target.id in self.C_Vars) and(target.id not in self.C_DclPointers)):
324                        if(target.id not in self.C_DclPointers):
325                            self.C_DclPointers.append(target.id)
326                            if(target.id in self.C_Vars):
327                                self.C_Vars.remove(target.id)
328        self.current_statement = ''
329
330    def visit_AugAssign(self, node):
331        if(node.target.id not in self.C_Vars):
332            if(node.target.id not in self.arguments):
333                self.C_Vars.append(node.target.id)
334        self.visit(node.target)
335        self.write_c(' ' + BINOP_SYMBOLS[type(node.op)] + '= ')
336        self.visit(node.value)
337        self.add_semi_colon()
338#        self.write_c(';')
339        self.add_current_line()
340
341    def visit_ImportFrom(self, node):
342        self.newline(node)
343        self.write_python('from %s%s import ' %('.' * node.level, node.module))
344        for idx, item in enumerate(node.names):
345            if idx:
346                self.write_python(', ')
347            self.write_python(item)
348
349    def visit_Import(self, node):
350        self.newline(node)
351        for item in node.names:
352            self.write_python('import ')
353            self.visit(item)
354
355    def visit_Expr(self, node):
356        self.newline(node)
357        self.generic_visit(node)
358
359    def listToDeclare(self, Vars):
360        s = ''
361        if(len(Vars) > 0):
362            s = ",".join(Vars)
363        return(s)
364
365    def write_C_Pointers(self, start_var):
366        if(len(self.C_DclPointers) > 0):
367            vars = ""
368            for c_ptr in self.C_DclPointers:
369                if(len(vars) > 0):
370                    vars += ", "
371                if(c_ptr not in self.arguments):
372                    vars += "*" + c_ptr
373                if(c_ptr in self.C_Vars):
374                    if(c_ptr in self.C_Vars):
375                        self.C_Vars.remove(c_ptr)
376            if(len(vars) > 0):
377                c_dcl = "    double " + vars + ";"
378                self.c_proc.insert(start_var, c_dcl + "\n")
379                start_var += 1
380        return start_var
381
382    def insert_C_Vars(self, start_var):
383        fLine = False
384        start_var = self.write_C_Pointers(start_var)
385        if(len(self.C_IntVars) > 0):
386            for var in self.C_IntVars:
387                if(var in self.C_Vars):
388                    self.C_Vars.remove(var)
389            s = self.listToDeclare(self.C_IntVars)
390            self.c_proc.insert(start_var, "    int " + s + ";\n")
391            fLine = True
392            start_var += 1
393
394        if(len(self.C_Vars) > 0):
395            s = self.listToDeclare(self.C_Vars)
396            self.c_proc.insert(start_var, "    double " + s + ";\n")
397            fLine = True
398            start_var += 1
399#        if(len(self.C_IntVars) > 0):
400#            s = self.listToDeclare(self.C_IntVars)
401#            self.c_proc.insert(start_var, "    int " + s + ";\n")
402#            fLine = True
403#            start_var += 1
404        if(len(self.C_Vectors) > 0):
405            s = self.listToDeclare(self.C_Vectors)
406            for n in range(len(self.C_Vectors)):
407                name = "vec" + str(n+1)
408                c_dcl = "    double " + name + "[] = {" + self.C_Vectors[n] + "};"
409                self.c_proc.insert(start_var, c_dcl + "\n")
410                start_var += 1
411        self.C_Vars.clear()
412        self.C_IntVars.clear()
413        self.C_Vectors.clear()
414        self.C_Pointers.clear()
415        self.C_DclPointers
416        if(fLine == True):
417            self.c_proc.insert(start_var, "\n")
418        return
419        s = ''
420        for n in range(len(self.C_Vars)):
421            s += str(self.C_Vars[n])
422            if n < len(self.C_Vars) - 1:
423                s += ", "
424        if(len(s) > 0):
425            self.c_proc.insert(start_var, "    double " + s + ";\n")
426            self.c_proc.insert(start_var + 1, "\n")
427
428    def writeInclude(self):
429        if(self.MathIncludeed == False):
430            self.add_c_line("#include <math.h>\n")
431            self.add_c_line("static double pi = 3.14159265359;\n")
432            self.MathIncludeed = True
433
434    def ListToString(self, strings):
435        s = ''
436        for n in range(len(strings)):
437            s += strings[n]
438            if(n < (len(strings) - 1)):
439                s += ", "
440        return(s)
441
442    def getMethodSignature(self):
443#        args_str = ListToString(self.arguments)
444        args_str = ''
445        for n in range(len(self.arguments)):
446            args_str += "double " + self.arguments[n]
447            if(n < (len(self.arguments) - 1)):
448                args_str += ", "
449        return(args_str)
450#        self.strMethodSignature = 'double ' + self.name + '(' + args_str + ")"
451
452    def InsertSignature(self):
453        args_str = ''
454        for n in range(len(self.arguments)):
455            args_str += "double " + self.arguments[n]
456            if(self.arguments[n] in self.C_Pointers):
457                args_str += "[]"
458            if(n < (len(self.arguments) - 1)):
459                args_str += ", "
460        self.strMethodSignature = 'double ' + self.name + '(' + args_str + ")"
461        if(self.signature_line >= 0):
462            self.c_proc.insert(self.signature_line, self.strMethodSignature)
463
464    def visit_FunctionDef(self, node):
465        self.newline(extra=1)
466        self.decorators(node)
467        self.newline(node)
468        self.arguments = []
469        self.name = node.name
470#        if self.name not in self.required_functions[0]:
471#           return
472        print("Parsing '" + self.name + "'")
473        args_str = ""
474
475        self.visit(node.args)
476# for C
477        self.writeInclude()
478        self.getMethodSignature()
479# for C
480        self.signature_line = len(self.c_proc)
481#        self.add_c_line(self.strMethodSignature)
482        self.add_c_line("\n{")
483        start_vars = len(self.c_proc) + 1
484        self.body(node.body)
485        self.add_c_line("}\n")
486        self.InsertSignature()
487        self.insert_C_Vars(start_vars)
488        self.C_Pointers = []
489
490    def visit_ClassDef(self, node):
491        have_args = []
492        def paren_or_comma():
493            if have_args:
494                self.write_python(', ')
495            else:
496                have_args.append(True)
497                self.write_python('(')
498
499        self.newline(extra=2)
500        self.decorators(node)
501        self.newline(node)
502        self.write_python('class %s' % node.name)
503        for base in node.bases:
504            paren_or_comma()
505            self.visit(base)
506        # XXX: the if here is used to keep this module compatible
507        #      with python 2.6.
508        if hasattr(node, 'keywords'):
509            for keyword in node.keywords:
510                paren_or_comma()
511                self.write_python(keyword.arg + '=')
512                self.visit(keyword.value)
513            if node.starargs is not None:
514                paren_or_comma()
515                self.write_python('*')
516                self.visit(node.starargs)
517            if node.kwargs is not None:
518                paren_or_comma()
519                self.write_python('**')
520                self.visit(node.kwargs)
521        self.write_python(have_args and '):' or ':')
522        self.body(node.body)
523
524    def visit_If(self, node):
525        self.write_c('if ')
526        self.visit(node.test)
527        self.write_c(' {')
528        self.body(node.body)
529        self.add_c_line('}')
530        while True:
531            else_ = node.orelse
532            if len(else_) == 0:
533                break
534#            elif hasattr(else_, 'orelse'):
535            elif len(else_) == 1 and isinstance(else_[0], ast.If):
536                node = else_[0]
537#                self.newline()
538                self.write_c('else if ')
539                self.visit(node.test)
540                self.write_c(' {')
541                self.body(node.body)
542                self.add_current_line()
543                self.add_c_line('}')
544#                break
545            else:
546                self.newline()
547                self.write_c('else {')
548                self.body(node.body)
549                self.add_c_line('}')
550                break
551
552    def getNodeLineNo(self, node):
553        line_number = -1
554        if(hasattr(node,'value')):
555            line_number = node.value.lineno
556        elif hasattr(node,'iter'):
557            if hasattr(node.iter,'lineno'):
558                line_number = node.iter.lineno
559        return(line_number)
560
561    def GetNodeAsString(self, node):
562        res = ''
563        if(hasattr(node, 'n')):
564            res = str(node.n)
565        elif(hasattr(node, 'id')):
566            res = node.id
567        return(res)
568
569    def GetForRange(self, node):
570        stop = ""
571        start = '0'
572        step = '1'
573        for_args = []
574        temp_statement = self.current_statement
575        self.current_statement = ''
576        for arg in node.iter.args:
577            self.visit(arg)
578            for_args.append(self.current_statement)
579            self.current_statement = ''
580        self.current_statement = temp_statement
581        if(len(for_args) == 1):
582            stop = for_args[0]
583        elif(len(for_args) == 2):
584            start = for_args[0]
585            stop = for_args[1]
586        elif(len(for_args) == 3):
587            start = for_args[0]
588            stop = for_args[1]
589            start = for_args[2]
590        else:
591            raise("Ilegal for loop parameters")
592        return(start, stop, step)
593
594    def visit_For(self, node):
595# node: for iterator is stored in node.target.
596# Iterator name is in node.target.id.
597        self.add_current_line()
598#        if(len(self.current_statement) > 0):
599#            self.add_c_line(self.current_statement)
600#            self.current_statement = ''
601        fForDone = False
602        self.current_statement = ''
603        if(hasattr(node.iter, 'func')):
604            if(hasattr(node.iter.func, 'id')):
605                if(node.iter.func.id == 'range'):
606                    self.visit(node.target)
607                    iterator = self.current_statement
608                    self.current_statement = ''
609                    if(iterator not in self.C_IntVars):
610                        self.C_IntVars.append(iterator)
611                    start, stop, step = self.GetForRange(node)
612                    self.write_c("for(" + iterator + "=" + str(start) + \
613                                  " ; " + iterator + " < " + str(stop) + \
614                                  " ; " + iterator + " += " + str(step) + ") {")
615                    self.body_or_else(node)
616                    self.write_c("}")
617                    fForDone = True
618        if(fForDone == False):
619            line_number = self.getNodeLineNo(node)
620            self.current_statement = ''
621            self.write_c('for ')
622            self.visit(node.target)
623            self.write_c(' in ')
624            self.visit(node.iter)
625            self.write_c(':')
626            errStr = "Conversion Error in function " + self.name + ", Line #" + str(line_number)
627            errStr += "\nPython for expression not supported: '" + self.current_statement + "'"
628            raise Exception(errStr)
629
630    def visit_While(self, node):
631        self.newline(node)
632        self.write_c('while ')
633        self.visit(node.test)
634        self.write_c(':')
635        self.body_or_else(node)
636
637    def visit_With(self, node):
638        self.newline(node)
639        self.write_python('with ')
640        self.visit(node.context_expr)
641        if node.optional_vars is not None:
642            self.write_python(' as ')
643            self.visit(node.optional_vars)
644        self.write_python(':')
645        self.body(node.body)
646
647    def visit_Pass(self, node):
648        self.newline(node)
649        self.write_python('pass')
650
651    def visit_Print(self, node):
652# XXX: python 2.6 only
653        self.newline(node)
654        self.write_c('print ')
655        want_comma = False
656        if node.dest is not None:
657            self.write_c(' >> ')
658            self.visit(node.dest)
659            want_comma = True
660        for value in node.values:
661            if want_comma:
662                self.write_c(', ')
663            self.visit(value)
664            want_comma = True
665        if not node.nl:
666            self.write_c(',')
667
668    def visit_Delete(self, node):
669        self.newline(node)
670        self.write_python('del ')
671        for idx, target in enumerate(node):
672            if idx:
673                self.write_python(', ')
674            self.visit(target)
675
676    def visit_TryExcept(self, node):
677        self.newline(node)
678        self.write_python('try:')
679        self.body(node.body)
680        for handler in node.handlers:
681            self.visit(handler)
682
683    def visit_TryFinally(self, node):
684        self.newline(node)
685        self.write_python('try:')
686        self.body(node.body)
687        self.newline(node)
688        self.write_python('finally:')
689        self.body(node.finalbody)
690
691    def visit_Global(self, node):
692        self.newline(node)
693        self.write_python('global ' + ', '.join(node.names))
694
695    def visit_Nonlocal(self, node):
696        self.newline(node)
697        self.write_python('nonlocal ' + ', '.join(node.names))
698
699    def visit_Return(self, node):
700        self.newline(node)
701        if node.value is None:
702            self.write_c('return')
703        else:
704            self.write_c('return(')
705            self.visit(node.value)
706        self.write_c(');')
707#      self.add_current_statement(self)
708        self.add_c_line(self.current_statement)
709        self.current_statement = ''
710
711    def visit_Break(self, node):
712        self.newline(node)
713        self.write_c('break')
714
715    def visit_Continue(self, node):
716        self.newline(node)
717        self.write_c('continue')
718
719    def visit_Raise(self, node):
720        # XXX: Python 2.6 / 3.0 compatibility
721        self.newline(node)
722        self.write_python('raise')
723        if hasattr(node, 'exc') and node.exc is not None:
724            self.write_python(' ')
725            self.visit(node.exc)
726            if node.cause is not None:
727                self.write_python(' from ')
728                self.visit(node.cause)
729        elif hasattr(node, 'type') and node.type is not None:
730            self.visit(node.type)
731            if node.inst is not None:
732                self.write_python(', ')
733                self.visit(node.inst)
734            if node.tback is not None:
735                self.write_python(', ')
736                self.visit(node.tback)
737
738    # Expressions
739
740    def visit_Attribute(self, node):
741        errStr = "Conversion Error in function " + self.name + ", Line #" + str(node.value.lineno)
742        errStr += "\nPython expression not supported: '" + node.value.id + "." + node.attr + "'"
743        raise Exception(errStr)
744        self.visit(node.value)
745        self.write_python('.' + node.attr)
746
747    def visit_Call(self, node):
748        want_comma = []
749        def write_comma():
750            if want_comma:
751                self.write_c(', ')
752            else:
753                want_comma.append(True)
754        if(hasattr(node.func, 'id')):
755            if(node.func.id not in self.C_Functions):
756                self.C_Functions.append(node.func.id)
757            if(node.func.id == 'abs'):
758                self.write_c("fabs ")
759            elif(node.func.id == 'int'):
760                self.write_c('(int) ')
761            elif(node.func.id == "SINCOS"):
762                self.WriteSincos(node)
763                return
764            else:
765                self.visit(node.func)
766        else:
767            self.visit(node.func)
768#self.C_Functions
769        self.write_c('(')
770        for arg in node.args:
771            write_comma()
772            self.visited_args = True
773            self.visit(arg)
774        for keyword in node.keywords:
775            write_comma()
776            self.write_c(keyword.arg + '=')
777            self.visit(keyword.value)
778        if hasattr(node, 'starargs'):
779            if node.starargs is not None:
780                write_comma()
781                self.write_c('*')
782                self.visit(node.starargs)
783        if hasattr(node, 'kwargs'):
784            if node.kwargs is not None:
785                write_comma()
786                self.write_c('**')
787                self.visit(node.kwargs)
788        self.write_c(');')
789
790    def visit_Name(self, node):
791        self.write_c(node.id)
792        if((node.id in self.C_Pointers) and(not self.SubRef)):
793            self.write_c("[0]")
794        name = ""
795        sub = node.id.find("[")
796        if(sub > 0):
797            name = node.id[0:sub].strip()
798        else:
799            name = node.id
800#       add variable to C_Vars if it ins't there yet, not an argument and not a number
801        if((name not in self.C_Functions) and (name not in self.C_Vars) and \
802            (name not in self.C_IntVars) and (name not in self.arguments) and \
803            (name.isnumeric() == False)):
804            if(self.InSubscript):
805                self.C_IntVars.append(node.id)
806            else:
807                self.C_Vars.append(node.id)
808
809    def visit_Str(self, node):
810        self.write_c(repr(node.s))
811
812    def visit_Bytes(self, node):
813        self.write_c(repr(node.s))
814
815    def visit_Num(self, node):
816        self.write_c(repr(node.n))
817
818    def visit_Tuple(self, node):
819        for idx, item in enumerate(node.elts):
820            if idx:
821                self.Tuples.append(item)
822            else:
823                self.visit(item)
824
825    def sequence_visit(left, right):
826        def visit(self, node):
827            self.is_sequence = True
828            s = ""
829            for idx, item in enumerate(node.elts):
830                if((idx > 0) and(len(s) > 0)):
831                    s += ', '
832                if(hasattr(item, 'id')):
833                    s += item.id
834                elif(hasattr(item, 'n')):
835                    s += str(item.n)
836            if(len(s) > 0):
837                self.C_Vectors.append(s)
838                vec_name = "vec"  + str(len(self.C_Vectors))
839                self.write_c(vec_name)
840                vec_name += "#"
841        return visit
842
843    visit_List = sequence_visit('[', ']')
844    visit_Set = sequence_visit('{', '}')
845    del sequence_visit
846
847    def visit_Dict(self, node):
848        self.write_python('{')
849        for idx, (key, value) in enumerate(zip(node.keys, node.values)):
850            if idx:
851                self.write_python(', ')
852            self.visit(key)
853            self.write_python(': ')
854            self.visit(value)
855        self.write_python('}')
856
857    def get_special_power(self, string):
858        function_name = ''
859        is_negative_exp = False
860        if(isevaluable(str(self.current_statement))):
861            exponent = eval(string)
862            is_negative_exp = exponent < 0
863            abs_exponent = abs(exponent)
864            if(abs_exponent == 2):
865                function_name = "square"
866            elif(abs_exponent == 3):
867                function_name = "cube"
868            elif(abs_exponent == 0.5):
869                function_name = "sqrt"
870            elif(abs_exponent == 1.0/3.0):
871                function_name = "cbrt"
872        if(function_name == ''):
873            function_name = "pow"
874        return function_name, is_negative_exp
875
876    def translate_power(self, node):
877# get exponent by visiting the right hand argument.
878        function_name = "pow"
879        temp_statement = self.current_statement
880# 'visit' functions write the results to the 'current_statement' class memnber
881# Here, a temporary variable, 'temp_statement', is used, that enables the
882# use of the 'visit' function
883        self.current_statement = ''
884        self.visit(node.right)
885        exponent = self.current_statement.replace(' ', '')
886        function_name, is_negative_exp = self.get_special_power(self.current_statement)
887        self.current_statement = temp_statement
888        if(is_negative_exp):
889            self.write_c("1.0 /(")
890        self.write_c(function_name + "(")
891        self.visit(node.left)
892        if(function_name == "pow"):
893            self.write_c(", ")
894            self.visit(node.right)
895        self.write_c(")")
896        if(is_negative_exp):
897            self.write_c(")")
898        self.write_c(" ")
899
900    def translate_integer_divide(self, node):
901        self.write_c("(int)(")
902        self.visit(node.left)
903        self.write_c(") /(int)(")
904        self.visit(node.right)
905        self.write_c(")")
906
907    def visit_BinOp(self, node):
908        self.write_c("(")
909        if('%s' % BINOP_SYMBOLS[type(node.op)] == BINOP_SYMBOLS[ast.Pow]):
910            self.translate_power(node)
911        elif('%s' % BINOP_SYMBOLS[type(node.op)] == BINOP_SYMBOLS[ast.FloorDiv]):
912            self.translate_integer_divide(node)
913        else:
914            self.visit(node.left)
915            self.write_c(' %s ' % BINOP_SYMBOLS[type(node.op)])
916            self.visit(node.right)
917        self.write_c(")")
918
919#       for C
920    def visit_BoolOp(self, node):
921        self.write_c('(')
922        for idx, value in enumerate(node.values):
923            if idx:
924                self.write_c(' %s ' % BOOLOP_SYMBOLS[type(node.op)])
925            self.visit(value)
926        self.write_c(')')
927
928    def visit_Compare(self, node):
929        self.write_c('(')
930        self.visit(node.left)
931        for op, right in zip(node.ops, node.comparators):
932            self.write_c(' %s ' % CMPOP_SYMBOLS[type(op)])
933            self.visit(right)
934        self.write_c(')')
935
936    def visit_UnaryOp(self, node):
937        self.write_c('(')
938        op = UNARYOP_SYMBOLS[type(node.op)]
939        self.write_c(op)
940        if op == 'not':
941            self.write_c(' ')
942        self.visit(node.operand)
943        self.write_c(')')
944
945    def visit_Subscript(self, node):
946        if(node.value.id not in self.C_Pointers):
947            self.C_Pointers.append(node.value.id)
948        self.SubRef = True
949        self.visit(node.value)
950        self.SubRef = False
951        self.write_c('[')
952        self.InSubscript = True
953        self.visit(node.slice)
954        self.InSubscript = False
955        self.write_c(']')
956
957    def visit_Slice(self, node):
958        if node.lower is not None:
959            self.visit(node.lower)
960        self.write_python(':')
961        if node.upper is not None:
962            self.visit(node.upper)
963        if node.step is not None:
964            self.write_python(':')
965            if not(isinstance(node.step, Name) and node.step.id == 'None'):
966                self.visit(node.step)
967
968    def visit_ExtSlice(self, node):
969        for idx, item in node.dims:
970            if idx:
971                self.write_python(', ')
972            self.visit(item)
973
974    def visit_Yield(self, node):
975        self.write_python('yield ')
976        self.visit(node.value)
977
978    def visit_Lambda(self, node):
979        self.write_python('lambda ')
980        self.visit(node.args)
981        self.write_python(': ')
982        self.visit(node.body)
983
984    def visit_Ellipsis(self, node):
985        self.write_python('Ellipsis')
986
987    def generator_visit(left, right):
988        def visit(self, node):
989            self.write_python(left)
990            self.write_c(left)
991            self.visit(node.elt)
992            for comprehension in node.generators:
993                self.visit(comprehension)
994            self.write_c(right)
995#            self.write_python(right)
996        return visit
997
998    visit_ListComp = generator_visit('[', ']')
999    visit_GeneratorExp = generator_visit('(', ')')
1000    visit_SetComp = generator_visit('{', '}')
1001    del generator_visit
1002
1003    def visit_DictComp(self, node):
1004        self.write_python('{')
1005        self.visit(node.key)
1006        self.write_python(': ')
1007        self.visit(node.value)
1008        for comprehension in node.generators:
1009            self.visit(comprehension)
1010        self.write_python('}')
1011
1012    def visit_IfExp(self, node):
1013        self.visit(node.body)
1014        self.write_c(' if ')
1015        self.visit(node.test)
1016        self.write_c(' else ')
1017        self.visit(node.orelse)
1018
1019    def visit_Starred(self, node):
1020        self.write_c('*')
1021        self.visit(node.value)
1022
1023    def visit_Repr(self, node):
1024        # XXX: python 2.6 only
1025        self.write_c('`')
1026        self.visit(node.value)
1027        self.write_python('`')
1028
1029    # Helper Nodes
1030
1031    def visit_alias(self, node):
1032        self.write_python(node.name)
1033        if node.asname is not None:
1034            self.write_python(' as ' + node.asname)
1035
1036    def visit_comprehension(self, node):
1037        self.write_c(' for ')
1038        self.visit(node.target)
1039        self.write_C(' in ')
1040#        self.write_python(' in ')
1041        self.visit(node.iter)
1042        if node.ifs:
1043            for if_ in node.ifs:
1044                self.write_python(' if ')
1045                self.visit(if_)
1046
1047#    def visit_excepthandler(self, node):
1048#        self.newline(node)
1049#        self.write_python('except')
1050#        if node.type is not None:
1051#            self.write_python(' ')
1052#            self.visit(node.type)
1053#            if node.name is not None:
1054#                self.write_python(' as ')
1055#                self.visit(node.name)
1056#        self.body(node.body)
1057
1058    def visit_arguments(self, node):
1059        self.signature(node)
1060
1061def Iq1(q, porod_scale, porod_exp, lorentz_scale, lorentz_length, peak_pos, lorentz_exp=17):
1062    z1 = z2 = z = abs(q - peak_pos) * lorentz_length
1063    if(q > p):
1064        q = p + 17
1065        p = q - 5
1066    z3 = -8
1067    inten = (porod_scale / q ** porod_exp
1068                + lorentz_scale /(1 + z ** lorentz_exp))
1069    return inten
1070
1071def Iq(q, porod_scale, porod_exp, lorentz_scale, lorentz_length, peak_pos, lorentz_exp=17):
1072    z1 = z2 = z = abs(q - peak_pos) * lorentz_length
1073    if(q > p):
1074        q = p + 17
1075        p = q - 5
1076    elif(q == p):
1077        q = p * q
1078        q *= z1
1079        p = z1
1080    elif(q == 17):
1081        q = p * q - 17
1082    else:
1083        q += 7
1084    z3 = -8
1085    inten = (porod_scale / q ** porod_exp
1086                + lorentz_scale /(1 + z ** lorentz_exp))
1087    return inten
1088
1089def print_function(f=None):
1090    """
1091    Print out the code for the function
1092    """
1093    # Include some comments to see if they get printed
1094    import ast
1095    import inspect
1096    if f is not None:
1097        tree = ast.parse(inspect.getsource(f))
1098        tree_source = to_source(tree)
1099        print(tree_source)
1100
1101def translate(functions, constants=0):
1102    sniplets = []
1103    fname = functions[1]
1104    python_file = open(fname, "r")
1105    source = python_file.read()
1106    python_file.close()
1107    tree = ast.parse(source)
1108    sniplet = to_source(tree, functions) # in the future add filename, offset, constants
1109    sniplets.append(sniplet)
1110    return("\n".join(sniplets))
1111
1112def get_file_names():
1113    fname_in = ""
1114    fname_out = ""
1115    if(len(sys.argv) > 1):
1116        fname_in = sys.argv[1]
1117        fname_base = os.path.splitext(fname_in)
1118        if(len(sys.argv) == 2):
1119            fname_out = str(fname_base[0]) + '.c'
1120        else:
1121            fname_out = sys.argv[2]
1122        if(len(fname_in) > 0):
1123            python_file = open(sys.argv[1], "r")
1124            if(len(fname_out) > 0):
1125                file_out = open(fname_out, "w+")
1126    return len(sys.argv), fname_in, fname_out
1127
1128if __name__ == "__main__":
1129    import os
1130    print("Parsing...using Python" + sys.version)
1131    try:
1132        fname_in = ""
1133        fname_out = ""
1134        if(len(sys.argv) == 1):
1135            print("Usage:\npython parse01.py <infile> [<outfile>](if omitted, output file is '<infile>.c'")
1136        else:
1137            fname_in = sys.argv[1]
1138            fname_base = os.path.splitext(fname_in)
1139            if(len(sys.argv) == 2):
1140                fname_out = str(fname_base[0]) + '.c'
1141            else:
1142                fname_out = sys.argv[2]
1143            if(len(fname_in) > 0):
1144                python_file = open(sys.argv[1], "r")
1145                if(len(fname_out) > 0):
1146                    file_out = open(fname_out, "w+")
1147                functions = ["MultAsgn", "Iq41", "Iq2"]
1148                tpls = [functions, fname_in, 0]
1149                c_txt = translate(tpls)
1150                file_out.write(c_txt)
1151                file_out.close()
1152    except Exception as excp:
1153        print("Error:\n" + str(excp.args))
1154    print("...Done")
Note: See TracBrowser for help on using the repository browser.