source: sasmodels/sasmodels/py2c.py @ 1ddb794

Last change on this file since 1ddb794 was 1ddb794, checked in by Paul Kienzle <pkienzle@…>, 6 years ago

python 2/3 compatibility

  • Property mode set to 100644
File size: 38.4 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            # CRUFT: 2.7 uses arg.id, 3.x uses arg.arg
246            try:
247                arg_name = arg.arg
248            except AttributeError:
249                arg_name = arg.id
250            self.arguments.append(arg_name)
251
252        padding = [None] *(len(node.args) - len(node.defaults))
253        for arg, default in zip(node.args, padding + node.defaults):
254            if default is not None:
255                # CRUFT: 2.7 uses arg.id, 3.x uses arg.arg
256                # CRUFT: 2.7 uses arg.id, 3.x uses arg.arg
257                try:
258                    arg_name = arg.arg
259                except AttributeError:
260                    arg_name = arg.id
261                w_str = ("Default Parameters are unknown to C: '%s = %s"
262                         % arg_name, str(default.n))
263                self.warnings.append(w_str)
264#                self.write_python('=')
265#                self.visit(default)
266
267    def decorators(self, node):
268        for decorator in node.decorator_list:
269            self.newline(decorator)
270            self.write_python('@')
271            self.visit(decorator)
272
273    # Statements
274
275    def visit_Assert(self, node):
276        self.newline(node)
277        self.write_c('assert ')
278        self.visit(node.test)
279        if node.msg is not None:
280            self.write_python(', ')
281            self.visit(node.msg)
282
283    def define_C_Vars(self, target):
284        if(hasattr(target, 'id')):
285# a variable is considered an array if it apears in the agrument list
286# and being assigned to. For example, the variable p in the following
287# sniplet is a pointer, while q is not
288# def somefunc(p, q):
289#  p = q + 1
290#  return
291#
292            if(target.id not in self.C_Vars):
293                if(target.id in self.arguments):
294                    idx = self.arguments.index(target.id)
295                    new_target = self.arguments[idx] + "[0]"
296                    if(new_target not in self.C_Pointers):
297                        target.id = new_target
298                        self.C_Pointers.append(self.arguments[idx])
299                else:
300                    self.C_Vars.append(target.id)
301
302    def add_semi_colon(self):
303        semi_pos = self.current_statement.find(';')
304        if(semi_pos > 0.0):
305            self.current_statement = self.current_statement.replace(';','')
306        self.write_c(';')
307
308    def visit_Assign(self, node):
309        self.add_current_line()
310        for idx, target in enumerate(node.targets): # multi assign, as in 'a = b = c = 7'
311            if idx:
312                self.write_c(' = ')
313            self.define_C_Vars(target)
314            self.visit(target)
315        if(len(self.Tuples) > 0):
316            tplTargets = list(self.Tuples)
317            del self.Tuples[:]
318        self.write_c(' = ')
319        self.is_sequence = False
320        self.visited_args = False
321        self.visit(node.value)
322        self.add_semi_colon()
323#        self.write_c(';')
324        self.add_current_line()
325        for n, item in enumerate(self.Tuples):
326            self.visit(tplTargets[n])
327            self.write_c(' = ')
328            self.visit(item)
329            self.add_semi_colon()
330            self.add_current_line()
331        if((self.is_sequence) and (not self.visited_args)):
332            for target in node.targets:
333                if(hasattr(target, 'id')):
334                    if((target.id in self.C_Vars) and(target.id not in self.C_DclPointers)):
335                        if(target.id not in self.C_DclPointers):
336                            self.C_DclPointers.append(target.id)
337                            if(target.id in self.C_Vars):
338                                self.C_Vars.remove(target.id)
339        self.current_statement = ''
340
341    def visit_AugAssign(self, node):
342        if(node.target.id not in self.C_Vars):
343            if(node.target.id not in self.arguments):
344                self.C_Vars.append(node.target.id)
345        self.visit(node.target)
346        self.write_c(' ' + BINOP_SYMBOLS[type(node.op)] + '= ')
347        self.visit(node.value)
348        self.add_semi_colon()
349#        self.write_c(';')
350        self.add_current_line()
351
352    def visit_ImportFrom(self, node):
353        self.newline(node)
354        self.write_python('from %s%s import ' %('.' * node.level, node.module))
355        for idx, item in enumerate(node.names):
356            if idx:
357                self.write_python(', ')
358            self.write_python(item)
359
360    def visit_Import(self, node):
361        self.newline(node)
362        for item in node.names:
363            self.write_python('import ')
364            self.visit(item)
365
366    def visit_Expr(self, node):
367        self.newline(node)
368        self.generic_visit(node)
369
370    def listToDeclare(self, Vars):
371        s = ''
372        if(len(Vars) > 0):
373            s = ",".join(Vars)
374        return(s)
375
376    def write_C_Pointers(self, start_var):
377        if(len(self.C_DclPointers) > 0):
378            vars = ""
379            for c_ptr in self.C_DclPointers:
380                if(len(vars) > 0):
381                    vars += ", "
382                if(c_ptr not in self.arguments):
383                    vars += "*" + c_ptr
384                if(c_ptr in self.C_Vars):
385                    if(c_ptr in self.C_Vars):
386                        self.C_Vars.remove(c_ptr)
387            if(len(vars) > 0):
388                c_dcl = "    double " + vars + ";"
389                self.c_proc.insert(start_var, c_dcl + "\n")
390                start_var += 1
391        return start_var
392
393    def insert_C_Vars(self, start_var):
394        fLine = False
395        start_var = self.write_C_Pointers(start_var)
396        if(len(self.C_IntVars) > 0):
397            for var in self.C_IntVars:
398                if(var in self.C_Vars):
399                    self.C_Vars.remove(var)
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
405        if(len(self.C_Vars) > 0):
406            s = self.listToDeclare(self.C_Vars)
407            self.c_proc.insert(start_var, "    double " + s + ";\n")
408            fLine = True
409            start_var += 1
410#        if(len(self.C_IntVars) > 0):
411#            s = self.listToDeclare(self.C_IntVars)
412#            self.c_proc.insert(start_var, "    int " + s + ";\n")
413#            fLine = True
414#            start_var += 1
415        if(len(self.C_Vectors) > 0):
416            s = self.listToDeclare(self.C_Vectors)
417            for n in range(len(self.C_Vectors)):
418                name = "vec" + str(n+1)
419                c_dcl = "    double " + name + "[] = {" + self.C_Vectors[n] + "};"
420                self.c_proc.insert(start_var, c_dcl + "\n")
421                start_var += 1
422        del self.C_Vars[:]
423        del self.C_IntVars[:]
424        del self.C_Vectors[:]
425        del self.C_Pointers[:]
426        self.C_DclPointers
427        if(fLine == True):
428            self.c_proc.insert(start_var, "\n")
429        return
430        s = ''
431        for n in range(len(self.C_Vars)):
432            s += str(self.C_Vars[n])
433            if n < len(self.C_Vars) - 1:
434                s += ", "
435        if(len(s) > 0):
436            self.c_proc.insert(start_var, "    double " + s + ";\n")
437            self.c_proc.insert(start_var + 1, "\n")
438
439    def ListToString(self, strings):
440        s = ''
441        for n in range(len(strings)):
442            s += strings[n]
443            if(n < (len(strings) - 1)):
444                s += ", "
445        return(s)
446
447    def getMethodSignature(self):
448#        args_str = ListToString(self.arguments)
449        args_str = ''
450        for n in range(len(self.arguments)):
451            args_str += "double " + self.arguments[n]
452            if(n < (len(self.arguments) - 1)):
453                args_str += ", "
454        return(args_str)
455#        self.strMethodSignature = 'double ' + self.name + '(' + args_str + ")"
456
457    def InsertSignature(self):
458        args_str = ''
459        for n in range(len(self.arguments)):
460            args_str += "double " + self.arguments[n]
461            if(self.arguments[n] in self.C_Pointers):
462                args_str += "[]"
463            if(n < (len(self.arguments) - 1)):
464                args_str += ", "
465        self.strMethodSignature = 'double ' + self.name + '(' + args_str + ")"
466        if(self.signature_line >= 0):
467            self.c_proc.insert(self.signature_line, self.strMethodSignature)
468
469    def visit_FunctionDef(self, node):
470        self.newline(extra=1)
471        self.decorators(node)
472        self.newline(node)
473        self.arguments = []
474        self.name = node.name
475#        if self.name not in self.required_functions[0]:
476#           return
477        print("Parsing '" + self.name + "'")
478        args_str = ""
479
480        self.visit(node.args)
481        self.getMethodSignature()
482# for C
483        self.signature_line = len(self.c_proc)
484#        self.add_c_line(self.strMethodSignature)
485        self.add_c_line("\n{")
486        start_vars = len(self.c_proc) + 1
487        self.body(node.body)
488        self.add_c_line("}\n")
489        self.InsertSignature()
490        self.insert_C_Vars(start_vars)
491        self.C_Pointers = []
492
493    def visit_ClassDef(self, node):
494        have_args = []
495        def paren_or_comma():
496            if have_args:
497                self.write_python(', ')
498            else:
499                have_args.append(True)
500                self.write_python('(')
501
502        self.newline(extra=2)
503        self.decorators(node)
504        self.newline(node)
505        self.write_python('class %s' % node.name)
506        for base in node.bases:
507            paren_or_comma()
508            self.visit(base)
509        # XXX: the if here is used to keep this module compatible
510        #      with python 2.6.
511        if hasattr(node, 'keywords'):
512            for keyword in node.keywords:
513                paren_or_comma()
514                self.write_python(keyword.arg + '=')
515                self.visit(keyword.value)
516            if node.starargs is not None:
517                paren_or_comma()
518                self.write_python('*')
519                self.visit(node.starargs)
520            if node.kwargs is not None:
521                paren_or_comma()
522                self.write_python('**')
523                self.visit(node.kwargs)
524        self.write_python(have_args and '):' or ':')
525        self.body(node.body)
526
527    def visit_If(self, node):
528        self.write_c('if ')
529        self.visit(node.test)
530        self.write_c(' {')
531        self.body(node.body)
532        self.add_c_line('}')
533        while True:
534            else_ = node.orelse
535            if len(else_) == 0:
536                break
537#            elif hasattr(else_, 'orelse'):
538            elif len(else_) == 1 and isinstance(else_[0], ast.If):
539                node = else_[0]
540#                self.newline()
541                self.write_c('else if ')
542                self.visit(node.test)
543                self.write_c(' {')
544                self.body(node.body)
545                self.add_current_line()
546                self.add_c_line('}')
547#                break
548            else:
549                self.newline()
550                self.write_c('else {')
551                self.body(node.body)
552                self.add_c_line('}')
553                break
554
555    def getNodeLineNo(self, node):
556        line_number = -1
557        if(hasattr(node,'value')):
558            line_number = node.value.lineno
559        elif hasattr(node,'iter'):
560            if hasattr(node.iter,'lineno'):
561                line_number = node.iter.lineno
562        return(line_number)
563
564    def GetNodeAsString(self, node):
565        res = ''
566        if(hasattr(node, 'n')):
567            res = str(node.n)
568        elif(hasattr(node, 'id')):
569            res = node.id
570        return(res)
571
572    def GetForRange(self, node):
573        stop = ""
574        start = '0'
575        step = '1'
576        for_args = []
577        temp_statement = self.current_statement
578        self.current_statement = ''
579        for arg in node.iter.args:
580            self.visit(arg)
581            for_args.append(self.current_statement)
582            self.current_statement = ''
583        self.current_statement = temp_statement
584        if(len(for_args) == 1):
585            stop = for_args[0]
586        elif(len(for_args) == 2):
587            start = for_args[0]
588            stop = for_args[1]
589        elif(len(for_args) == 3):
590            start = for_args[0]
591            stop = for_args[1]
592            start = for_args[2]
593        else:
594            raise("Ilegal for loop parameters")
595        return(start, stop, step)
596
597    def visit_For(self, node):
598# node: for iterator is stored in node.target.
599# Iterator name is in node.target.id.
600        self.add_current_line()
601#        if(len(self.current_statement) > 0):
602#            self.add_c_line(self.current_statement)
603#            self.current_statement = ''
604        fForDone = False
605        self.current_statement = ''
606        if(hasattr(node.iter, 'func')):
607            if(hasattr(node.iter.func, 'id')):
608                if(node.iter.func.id == 'range'):
609                    self.visit(node.target)
610                    iterator = self.current_statement
611                    self.current_statement = ''
612                    if(iterator not in self.C_IntVars):
613                        self.C_IntVars.append(iterator)
614                    start, stop, step = self.GetForRange(node)
615                    self.write_c("for(" + iterator + "=" + str(start) + \
616                                  " ; " + iterator + " < " + str(stop) + \
617                                  " ; " + iterator + " += " + str(step) + ") {")
618                    self.body_or_else(node)
619                    self.write_c("}")
620                    fForDone = True
621        if(fForDone == False):
622            line_number = self.getNodeLineNo(node)
623            self.current_statement = ''
624            self.write_c('for ')
625            self.visit(node.target)
626            self.write_c(' in ')
627            self.visit(node.iter)
628            self.write_c(':')
629            errStr = "Conversion Error in function " + self.name + ", Line #" + str(line_number)
630            errStr += "\nPython for expression not supported: '" + self.current_statement + "'"
631            raise Exception(errStr)
632
633    def visit_While(self, node):
634        self.newline(node)
635        self.write_c('while ')
636        self.visit(node.test)
637        self.write_c(':')
638        self.body_or_else(node)
639
640    def visit_With(self, node):
641        self.newline(node)
642        self.write_python('with ')
643        self.visit(node.context_expr)
644        if node.optional_vars is not None:
645            self.write_python(' as ')
646            self.visit(node.optional_vars)
647        self.write_python(':')
648        self.body(node.body)
649
650    def visit_Pass(self, node):
651        self.newline(node)
652        self.write_python('pass')
653
654    def visit_Print(self, node):
655# XXX: python 2.6 only
656        self.newline(node)
657        self.write_c('print ')
658        want_comma = False
659        if node.dest is not None:
660            self.write_c(' >> ')
661            self.visit(node.dest)
662            want_comma = True
663        for value in node.values:
664            if want_comma:
665                self.write_c(', ')
666            self.visit(value)
667            want_comma = True
668        if not node.nl:
669            self.write_c(',')
670
671    def visit_Delete(self, node):
672        self.newline(node)
673        self.write_python('del ')
674        for idx, target in enumerate(node):
675            if idx:
676                self.write_python(', ')
677            self.visit(target)
678
679    def visit_TryExcept(self, node):
680        self.newline(node)
681        self.write_python('try:')
682        self.body(node.body)
683        for handler in node.handlers:
684            self.visit(handler)
685
686    def visit_TryFinally(self, node):
687        self.newline(node)
688        self.write_python('try:')
689        self.body(node.body)
690        self.newline(node)
691        self.write_python('finally:')
692        self.body(node.finalbody)
693
694    def visit_Global(self, node):
695        self.newline(node)
696        self.write_python('global ' + ', '.join(node.names))
697
698    def visit_Nonlocal(self, node):
699        self.newline(node)
700        self.write_python('nonlocal ' + ', '.join(node.names))
701
702    def visit_Return(self, node):
703        self.newline(node)
704        if node.value is None:
705            self.write_c('return')
706        else:
707            self.write_c('return(')
708            self.visit(node.value)
709        self.write_c(')')
710        self.add_semi_colon()
711        self.add_c_line(self.current_statement)
712        self.current_statement = ''
713
714    def visit_Break(self, node):
715        self.newline(node)
716        self.write_c('break')
717
718    def visit_Continue(self, node):
719        self.newline(node)
720        self.write_c('continue')
721
722    def visit_Raise(self, node):
723        # XXX: Python 2.6 / 3.0 compatibility
724        self.newline(node)
725        self.write_python('raise')
726        if hasattr(node, 'exc') and node.exc is not None:
727            self.write_python(' ')
728            self.visit(node.exc)
729            if node.cause is not None:
730                self.write_python(' from ')
731                self.visit(node.cause)
732        elif hasattr(node, 'type') and node.type is not None:
733            self.visit(node.type)
734            if node.inst is not None:
735                self.write_python(', ')
736                self.visit(node.inst)
737            if node.tback is not None:
738                self.write_python(', ')
739                self.visit(node.tback)
740
741    # Expressions
742
743    def visit_Attribute(self, node):
744        errStr = "Conversion Error in function " + self.name + ", Line #" + str(node.value.lineno)
745        errStr += "\nPython expression not supported: '" + node.value.id + "." + node.attr + "'"
746        raise Exception(errStr)
747        self.visit(node.value)
748        self.write_python('.' + node.attr)
749
750    def visit_Call(self, node):
751        want_comma = []
752        def write_comma():
753            if want_comma:
754                self.write_c(', ')
755            else:
756                want_comma.append(True)
757        if(hasattr(node.func, 'id')):
758            if(node.func.id not in self.C_Functions):
759                self.C_Functions.append(node.func.id)
760            if(node.func.id == 'abs'):
761                self.write_c("fabs ")
762            elif(node.func.id == 'int'):
763                self.write_c('(int) ')
764            elif(node.func.id == "SINCOS"):
765                self.WriteSincos(node)
766                return
767            else:
768                self.visit(node.func)
769        else:
770            self.visit(node.func)
771#self.C_Functions
772        self.write_c('(')
773        for arg in node.args:
774            write_comma()
775            self.visited_args = True
776            self.visit(arg)
777        for keyword in node.keywords:
778            write_comma()
779            self.write_c(keyword.arg + '=')
780            self.visit(keyword.value)
781        if hasattr(node, 'starargs'):
782            if node.starargs is not None:
783                write_comma()
784                self.write_c('*')
785                self.visit(node.starargs)
786        if hasattr(node, 'kwargs'):
787            if node.kwargs is not None:
788                write_comma()
789                self.write_c('**')
790                self.visit(node.kwargs)
791        self.write_c(');')
792
793    def visit_Name(self, node):
794        self.write_c(node.id)
795        if((node.id in self.C_Pointers) and(not self.SubRef)):
796            self.write_c("[0]")
797        name = ""
798        sub = node.id.find("[")
799        if(sub > 0):
800            name = node.id[0:sub].strip()
801        else:
802            name = node.id
803#       add variable to C_Vars if it ins't there yet, not an argument and not a number
804        if((name not in self.C_Functions) and (name not in self.C_Vars) and \
805            (name not in self.C_IntVars) and (name not in self.arguments) and \
806            (name.isdigit() == False)):
807            if(self.InSubscript):
808                self.C_IntVars.append(node.id)
809            else:
810                self.C_Vars.append(node.id)
811
812    def visit_Str(self, node):
813        self.write_c(repr(node.s))
814
815    def visit_Bytes(self, node):
816        self.write_c(repr(node.s))
817
818    def visit_Num(self, node):
819        self.write_c(repr(node.n))
820
821    def visit_Tuple(self, node):
822        for idx, item in enumerate(node.elts):
823            if idx:
824                self.Tuples.append(item)
825            else:
826                self.visit(item)
827
828    def sequence_visit(left, right):
829        def visit(self, node):
830            self.is_sequence = True
831            s = ""
832            for idx, item in enumerate(node.elts):
833                if((idx > 0) and(len(s) > 0)):
834                    s += ', '
835                if(hasattr(item, 'id')):
836                    s += item.id
837                elif(hasattr(item, 'n')):
838                    s += str(item.n)
839            if(len(s) > 0):
840                self.C_Vectors.append(s)
841                vec_name = "vec"  + str(len(self.C_Vectors))
842                self.write_c(vec_name)
843                vec_name += "#"
844        return visit
845
846    visit_List = sequence_visit('[', ']')
847    visit_Set = sequence_visit('{', '}')
848    del sequence_visit
849
850    def visit_Dict(self, node):
851        self.write_python('{')
852        for idx, (key, value) in enumerate(zip(node.keys, node.values)):
853            if idx:
854                self.write_python(', ')
855            self.visit(key)
856            self.write_python(': ')
857            self.visit(value)
858        self.write_python('}')
859
860    def get_special_power(self, string):
861        function_name = ''
862        is_negative_exp = False
863        if(isevaluable(str(self.current_statement))):
864            exponent = eval(string)
865            is_negative_exp = exponent < 0
866            abs_exponent = abs(exponent)
867            if(abs_exponent == 2):
868                function_name = "square"
869            elif(abs_exponent == 3):
870                function_name = "cube"
871            elif(abs_exponent == 0.5):
872                function_name = "sqrt"
873            elif(abs_exponent == 1.0/3.0):
874                function_name = "cbrt"
875        if(function_name == ''):
876            function_name = "pow"
877        return function_name, is_negative_exp
878
879    def translate_power(self, node):
880# get exponent by visiting the right hand argument.
881        function_name = "pow"
882        temp_statement = self.current_statement
883# 'visit' functions write the results to the 'current_statement' class memnber
884# Here, a temporary variable, 'temp_statement', is used, that enables the
885# use of the 'visit' function
886        self.current_statement = ''
887        self.visit(node.right)
888        exponent = self.current_statement.replace(' ', '')
889        function_name, is_negative_exp = self.get_special_power(self.current_statement)
890        self.current_statement = temp_statement
891        if(is_negative_exp):
892            self.write_c("1.0 /(")
893        self.write_c(function_name + "(")
894        self.visit(node.left)
895        if(function_name == "pow"):
896            self.write_c(", ")
897            self.visit(node.right)
898        self.write_c(")")
899        if(is_negative_exp):
900            self.write_c(")")
901        self.write_c(" ")
902
903    def translate_integer_divide(self, node):
904        self.write_c("(int)(")
905        self.visit(node.left)
906        self.write_c(") /(int)(")
907        self.visit(node.right)
908        self.write_c(")")
909
910    def visit_BinOp(self, node):
911        self.write_c("(")
912        if('%s' % BINOP_SYMBOLS[type(node.op)] == BINOP_SYMBOLS[ast.Pow]):
913            self.translate_power(node)
914        elif('%s' % BINOP_SYMBOLS[type(node.op)] == BINOP_SYMBOLS[ast.FloorDiv]):
915            self.translate_integer_divide(node)
916        else:
917            self.visit(node.left)
918            self.write_c(' %s ' % BINOP_SYMBOLS[type(node.op)])
919            self.visit(node.right)
920        self.write_c(")")
921
922#       for C
923    def visit_BoolOp(self, node):
924        self.write_c('(')
925        for idx, value in enumerate(node.values):
926            if idx:
927                self.write_c(' %s ' % BOOLOP_SYMBOLS[type(node.op)])
928            self.visit(value)
929        self.write_c(')')
930
931    def visit_Compare(self, node):
932        self.write_c('(')
933        self.visit(node.left)
934        for op, right in zip(node.ops, node.comparators):
935            self.write_c(' %s ' % CMPOP_SYMBOLS[type(op)])
936            self.visit(right)
937        self.write_c(')')
938
939    def visit_UnaryOp(self, node):
940        self.write_c('(')
941        op = UNARYOP_SYMBOLS[type(node.op)]
942        self.write_c(op)
943        if op == 'not':
944            self.write_c(' ')
945        self.visit(node.operand)
946        self.write_c(')')
947
948    def visit_Subscript(self, node):
949        if(node.value.id not in self.C_Pointers):
950            self.C_Pointers.append(node.value.id)
951        self.SubRef = True
952        self.visit(node.value)
953        self.SubRef = False
954        self.write_c('[')
955        self.InSubscript = True
956        self.visit(node.slice)
957        self.InSubscript = False
958        self.write_c(']')
959
960    def visit_Slice(self, node):
961        if node.lower is not None:
962            self.visit(node.lower)
963        self.write_python(':')
964        if node.upper is not None:
965            self.visit(node.upper)
966        if node.step is not None:
967            self.write_python(':')
968            if not(isinstance(node.step, Name) and node.step.id == 'None'):
969                self.visit(node.step)
970
971    def visit_ExtSlice(self, node):
972        for idx, item in node.dims:
973            if idx:
974                self.write_python(', ')
975            self.visit(item)
976
977    def visit_Yield(self, node):
978        self.write_python('yield ')
979        self.visit(node.value)
980
981    def visit_Lambda(self, node):
982        self.write_python('lambda ')
983        self.visit(node.args)
984        self.write_python(': ')
985        self.visit(node.body)
986
987    def visit_Ellipsis(self, node):
988        self.write_python('Ellipsis')
989
990    def generator_visit(left, right):
991        def visit(self, node):
992            self.write_python(left)
993            self.write_c(left)
994            self.visit(node.elt)
995            for comprehension in node.generators:
996                self.visit(comprehension)
997            self.write_c(right)
998#            self.write_python(right)
999        return visit
1000
1001    visit_ListComp = generator_visit('[', ']')
1002    visit_GeneratorExp = generator_visit('(', ')')
1003    visit_SetComp = generator_visit('{', '}')
1004    del generator_visit
1005
1006    def visit_DictComp(self, node):
1007        self.write_python('{')
1008        self.visit(node.key)
1009        self.write_python(': ')
1010        self.visit(node.value)
1011        for comprehension in node.generators:
1012            self.visit(comprehension)
1013        self.write_python('}')
1014
1015    def visit_IfExp(self, node):
1016        self.visit(node.body)
1017        self.write_c(' if ')
1018        self.visit(node.test)
1019        self.write_c(' else ')
1020        self.visit(node.orelse)
1021
1022    def visit_Starred(self, node):
1023        self.write_c('*')
1024        self.visit(node.value)
1025
1026    def visit_Repr(self, node):
1027        # XXX: python 2.6 only
1028        self.write_c('`')
1029        self.visit(node.value)
1030        self.write_python('`')
1031
1032    # Helper Nodes
1033
1034    def visit_alias(self, node):
1035        self.write_python(node.name)
1036        if node.asname is not None:
1037            self.write_python(' as ' + node.asname)
1038
1039    def visit_comprehension(self, node):
1040        self.write_c(' for ')
1041        self.visit(node.target)
1042        self.write_C(' in ')
1043#        self.write_python(' in ')
1044        self.visit(node.iter)
1045        if node.ifs:
1046            for if_ in node.ifs:
1047                self.write_python(' if ')
1048                self.visit(if_)
1049
1050#    def visit_excepthandler(self, node):
1051#        self.newline(node)
1052#        self.write_python('except')
1053#        if node.type is not None:
1054#            self.write_python(' ')
1055#            self.visit(node.type)
1056#            if node.name is not None:
1057#                self.write_python(' as ')
1058#                self.visit(node.name)
1059#        self.body(node.body)
1060
1061    def visit_arguments(self, node):
1062        self.signature(node)
1063
1064def Iq1(q, porod_scale, porod_exp, lorentz_scale, lorentz_length, peak_pos, lorentz_exp=17):
1065    z1 = z2 = z = abs(q - peak_pos) * lorentz_length
1066    if(q > p):
1067        q = p + 17
1068        p = q - 5
1069    z3 = -8
1070    inten = (porod_scale / q ** porod_exp
1071                + lorentz_scale /(1 + z ** lorentz_exp))
1072    return inten
1073
1074def Iq(q, porod_scale, porod_exp, lorentz_scale, lorentz_length, peak_pos, lorentz_exp=17):
1075    z1 = z2 = z = abs(q - peak_pos) * lorentz_length
1076    if(q > p):
1077        q = p + 17
1078        p = q - 5
1079    elif(q == p):
1080        q = p * q
1081        q *= z1
1082        p = z1
1083    elif(q == 17):
1084        q = p * q - 17
1085    else:
1086        q += 7
1087    z3 = -8
1088    inten = (porod_scale / q ** porod_exp
1089                + lorentz_scale /(1 + z ** lorentz_exp))
1090    return inten
1091
1092def print_function(f=None):
1093    """
1094    Print out the code for the function
1095    """
1096    # Include some comments to see if they get printed
1097    import ast
1098    import inspect
1099    if f is not None:
1100        tree = ast.parse(inspect.getsource(f))
1101        tree_source = to_source(tree)
1102        print(tree_source)
1103
1104def translate(functions, constants=0):
1105    snippets = []
1106    for source, fname, line_no in functions:
1107        line_directive = '#line %d "%s"'%(line_no, fname.replace('\\','\\\\'))
1108        snippets.append(line_directive)
1109        tree = ast.parse(source)
1110        # in the future add filename, offset, constants
1111        c_code = to_source(tree, functions)
1112        snippets.append(c_code)
1113    return snippets
1114
1115def get_file_names():
1116    fname_in = ""
1117    fname_out = ""
1118    if(len(sys.argv) > 1):
1119        fname_in = sys.argv[1]
1120        fname_base = os.path.splitext(fname_in)
1121        if(len(sys.argv) == 2):
1122            fname_out = str(fname_base[0]) + '.c'
1123        else:
1124            fname_out = sys.argv[2]
1125        if(len(fname_in) > 0):
1126            python_file = open(sys.argv[1], "r")
1127            if(len(fname_out) > 0):
1128                file_out = open(fname_out, "w+")
1129    return len(sys.argv), fname_in, fname_out
1130
1131if __name__ == "__main__":
1132    import os
1133    print("Parsing...using Python" + sys.version)
1134    try:
1135        fname_in = ""
1136        fname_out = ""
1137        if(len(sys.argv) == 1):
1138            print("Usage:\npython parse01.py <infile> [<outfile>](if omitted, output file is '<infile>.c'")
1139        else:
1140            fname_in = sys.argv[1]
1141            fname_base = os.path.splitext(fname_in)
1142            if(len(sys.argv) == 2):
1143                fname_out = str(fname_base[0]) + '.c'
1144            else:
1145                fname_out = sys.argv[2]
1146            if(len(fname_in) > 0):
1147                python_file = open(sys.argv[1], "r")
1148                if(len(fname_out) > 0):
1149                    file_out = open(fname_out, "w+")
1150                functions = ["MultAsgn", "Iq41", "Iq2"]
1151                tpls = [functions, fname_in, 0]
1152                c_txt = translate(tpls)
1153                file_out.write(c_txt)
1154                file_out.close()
1155    except Exception as excp:
1156        print("Error:\n" + str(excp.args))
1157    print("...Done")
Note: See TracBrowser for help on using the repository browser.