cvsuser     04/07/31 02:10:53

  Modified:    .        MANIFEST
  Added:       languages/python ast2past.py
  Log:
  ast2past.py - convert python AST to PAST
  
  Revision  Changes    Path
  1.711     +1 -0      parrot/MANIFEST
  
  Index: MANIFEST
  ===================================================================
  RCS file: /cvs/public/parrot/MANIFEST,v
  retrieving revision 1.710
  retrieving revision 1.711
  diff -u -w -r1.710 -r1.711
  --- MANIFEST  24 Jul 2004 10:26:39 -0000      1.710
  +++ MANIFEST  31 Jul 2004 09:10:50 -0000      1.711
  @@ -2261,6 +2261,7 @@
   languages/perl6/t/var/scalar/string/qq.t          [perl6]
   languages/python/Makefile                         []
   languages/python/README                           []
  +languages/python/ast2past.py                      []
   languages/python/python.bnf                       []
   languages/python/python.prd                       []
   languages/python/mdis.py                          []
  
  
  
  1.1                  parrot/languages/python/ast2past.py
  
  Index: ast2past.py
  ===================================================================
  #!/usr/bin/env python
  """
  Convert Python AST to a textual representation called PAST, which is
  Parrot AST as Simple Text.
  
  usage: ast2past [-d] [-D] [-o] [-l] [-p "..."] file.py
         -d debug
         -D dump Python AST
         -o output to stdout, don't run parrot (default currently)
         -l add line info
         -p parrot options
         -r run parrot (default, except for -o)  N/Y
         -s add source comments"""
  
  
  # parts of this program are stolen from Michal Wallace's pirate.py
  # LocalNameFinder is copied from Lib/compiler/pycodegen.py and
  # modified a bit
  
  # the rest is hacked together by leo
  
  import os
  import compiler
  import traceback
  from compiler import ast
  
  class imclist(list):
      def __init__(self):
        self._verbose = False
        self._indent = 1
  
      def append(self, line):
        line = " " * self._indent + line
          super(imclist, self).append(line)
  
      def begin(self, line):
        self.append(line)
        self._indent += 1
  
      def end(self, line):
        self._indent -= 1
        self.append(line)
  
  
  class LocalNameFinder:
      """Find local names in scope"""
      def __init__(self, names=()):
          self.names = {}
          self.globals = {}
        self.calls = 0
          for name in names:
              self.names[name] = name
  
      # XXX list comprehensions and for loops
  
      def getLocals(self):
          for elt in self.globals.keys():
              if elt in self.names:
                  del self.names[elt]
          return self.names
  
      def visitDict(self, node):
          pass
  
      def visitGlobal(self, node):
          for name in node.names:
              self.globals[name] = name
  
      def visitFunction(self, node):
        self.calls += 1
          self.names[node.name] = node.name
  
      def visitLambda(self, node):
        self.calls += 1
  
      def visitImport(self, node):
          for name, alias in node.names:
            n = alias or name
              self.names[n] = n
  
      def visitFrom(self, node):
          for name, alias in node.names:
            n = alias or name
              self.names[n] = n
  
      def visitClass(self, node):
          self.names[node.name] = node.name
  
      def visitAssName(self, node):
          self.names[node.name] = node.name
  
      def visitAssign(self, node):
        # .nodes .expr
        # mark the expressions so that it assigns to
        # nodes[-1] directly if possible
        node.expr._assign_to = node.nodes[-1]
        self.visit(node.expr)
        for n in node.nodes:
            self.visit(n)
  
  class PirateVisitor(object):
      def __init__(self, name, counter=None, depth=None):
          self.name = name
          self._last_lineno = None
          self.lines = imclist()
          self.loops = []
          self.counter = counter or {}
          self.subs = []
          self.vars = {}        # parrot known vars
          self.depth = depth or 0 # lexical scope depth
          self.globals = {}
          self.locals = {}
          self.classKnown = [] # only make one constructor per class
          self.classStack = [] # the class we're looking at right now
  
  
      def getCode(self):
        res = "\n".join(self.lines)
          res += "\n".join([s.getCode() for s in self.subs])
          return res
  
      def set_lineno (self, node):
          if (node.lineno is not None and
              node.lineno != self._last_lineno):
              self._last_lineno = node.lineno
            self.lines._verbose = self._verbose
            if self._print_source:
                if not hasattr(self, "_src_list"):
                    self._src_list = src.split("\n")
                self.append("Src_Line(" +
                    `self._src_list[node.lineno - 1]` + ")")
            if self._lines:
                self.append('Line_no(%i)' % node.lineno)
  
      def append(self, line):
          self.lines.append(line)
  
      def begin(self, line):
          self.lines.begin(line)
  
      def end(self, line):
          self.lines.end(line)
  
      # visitor methods in alphabetical order
  
      # Python Library Reference
      # 19.3.1 AST nodes
  
      def find_locals(self, node):
          lnf = compiler.visitor.walk(node, LocalNameFinder())
        for n in lnf.getLocals():
            self.locals[n] = n
            self.append("Py_Local(%s)" % n)
  
      def binary(self, node, op):
        # .left .right
        self.set_lineno(node)
        self.begin("Binary(")
        self.append("Op('%s')" % op)
        self.visit(node.left)
        self.visit(node.right)
        self.end(") # Binary")
  
      def visitAdd(self, node):
        self.binary(node, '+')
  
      def expr_helper(self, nodes, txt, op=None):
        """Convert the lhs tuple to a series of expressions"""
        self.begin("%s(" % txt)
        l = nodes[0]
        r = nodes[1]
        if op:
            self.append("Op(%s)" % `op`)
        self.visit(l)
        n = nodes[1:]
        if len(n) >= 2:
            self.expr_helper(n, txt, op)
        else:
            self.visit(r)
        self.end(") # %s" % txt)
  
      def visitAnd(self, node):
        # .nodes
        self.set_lineno(node)
        self.expr_helper(node.nodes, "And")
  
      def visitAssAttr(self, node):
        # .expr
        # .attrname
        # .flags TODO
        self.set_lineno(node)
        self.begin("AssAttr(")
        self.visit(node.expr)
        self.append("Attr(%s)" % node.attrname)
        self.end(") # AssAttr")
  
      def visitAssName(self, node):
        # .name .flags TODO
        self.set_lineno(node)
        self.append("AssName(" + node.name + ")")
  
      def visitAssList(self, node):
        # .nodes
        self.set_lineno(node)
        self.begin("AssList(")
        for n in node.nodes:
            self.visit(n)
        self.end(") # AssList")
  
      def visitAssTuple(self, node):
        # .nodes
        self.set_lineno(node)
        self.begin("AssTuple(")
        for n in node.nodes:
            self.visit(n)
        self.end(") # AssTuple")
  
      def visitAssert(self, node):
        # .test .fail
        self.set_lineno(node)
        self.begin("Assert(")
        self.visit(node.test)
        if node.fail:
            self.visit(node.fail)
        self.end(") # Assert")
  
      def visitAssign(self, node):
        # .nodes, .expr
        self.set_lineno(node)
        nodes = node.nodes
        nodes.append(node.expr)
        self.expr_helper(nodes, "Assign")
  
      def visitAugAssign(self, node):
        # .node, .op .expr
        self.set_lineno(node)
        self.begin("AugAssign(")
        self.visit(node.node)
        self.append("Op(%s)" % node.op)
        self.visit(node.expr)
        self.end(") # AugAssign")
  
      def visitBackquote(self, node):
        self.begin("Backquote(")
        self.visit(node.expr)
        self.end(") # Backquote")
  
      def visitBitand(self, node):
        # .nodes
        self.set_lineno(node)
        self.expr_helper(node.nodes, "Binary", '&')
  
      def visitBitor(self, node):
        # .nodes
        self.set_lineno(node)
        self.expr_helper(node.nodes, "Binary", '|')
  
      def visitBitxor(self, node):
        # .nodes
        self.set_lineno(node)
        self.expr_helper(node.nodes, "Binary", '^')
  
      def visitBreak(self, node):
        self.set_lineno(node)
        self.append("Break()")
  
      def visitCallFunc(self, node):
        # .node (callee)
        # .args
        # .star_args
        # .dstar_args
        self.set_lineno(node)
        self.begin("Py_Call(")
        self.visit(node.node)
        self.begin("Args(")
        for n in node.args:
            self.visit(n)
        self.end(") # Args")
        if node.star_args:
            self.begin("Star_Args(")
            self.visit(node.star_args)
            self.end(") # StarArgs")
        if node.dstar_args:
            self.begin("DStar_Args(")
            self.visit(node.dstar_args)
            self.end(") # DStarArgs")
        self.end(") # Py_Call")
  
      def visitClass(self, node):
        # .name .bases .doc .code
        self.set_lineno(node)
        self.append("")
        self.begin("Py_Class(")
        self.append("Name(%s)" % `node.name`)
        if node.doc:
            self.append("Py_doc(" + `node.doc` + ")")
        self.begin("BaseClasses(")
        for n in node.bases:
            self.visit(n)
        self.end(") # BaseClasses")
        self.find_locals(node.code)
        self.visit(node.code)
        self.end(") # Py_class")
        self.append("")
  
      def visitCompare(self, node):
        # .expr .ops
        # x < y <= z   :=   x < y and y <= z
        self.set_lineno(node)
        self.begin("Compare(")
        self.visit(node.expr)   # lhs
        for op, n in node.ops:
            self.append("Op(%s)" % op)
            self.visit(n)
        self.end(") # Compare")
  
      def visitConst(self, node):
        # .value
        self.set_lineno(node)
        self.append("Const(" + `node.value` + ")")
  
      def visitContinue(self, node):
        self.set_lineno(node)
        self.append("Continue()")
  
      def visitDict(self, node):
        # .items
        self.set_lineno(node)
        self.begin("Dict(")
        for k, v in node.items:
            self.visit(k)
            self.visit(v)
        self.end(") # Dict")
  
      def visitDiscard(self, node):
        # .expr
        self.set_lineno(node)
        self.begin("Void(")
        self.visit(node.expr)
        self.end(") # Void")
  
      def visitDiv(self, node):
        # .left .right
        self.binary(node, '/')
  
      def visitEllipsis(self, node):
        self.set_lineno(node)
        self.append("Ellipsis()")
  
      def visitExec(self, node):
        # .expr .locals .globals TODO
        self.set_lineno(node)
        self.begin("Exec(")
        self.visit(node.expr)
        self.end(") # Exec")
  
      def visitFor(self, node):
        # .assign .list .body .else_
        self.set_lineno(node)
        self.begin("Py_For(")
        self.visit(node.assign)
        self.visit(node.list)
        self.visit(node.body)
        if node.else_:
            self.visit(node.else_)
        else:
            self.append("_()")
        self.end(") # Py_for")
  
      def visitFrom(self, node):
        # .modname .names
        self.set_lineno(node)
        self.begin("Py_Import(")
        self.append("py_module(%s)" % node.modname)
          for name, alias in node.names:
            self.append("py_import(%s, %s)" % (name, alias))
        self.end(") # Py_Import")
  
      def function(self, node, is_lambda):
        self.append("")
        self.set_lineno(node)
        self.begin("Function(")
        if not is_lambda:
            self.append("Name(%s)" % `node.name`)
            if node.doc:
                self.append("Py_doc(" + `node.doc` + ")")
        self.begin("Params(")
        for n in node.argnames:
            self.append("Name(%s)" % n)
        self.begin("Defaults(")
        for n in node.defaults:
            self.visit(n)
        self.end(") # Defaults")
        if node.varargs:
            self.append("py_var_args(1)")
        if node.kwargs:
            self.append("py_kw_args(1)")
        self.end(") # Params")
        self.find_locals(node.code)
        self.visit(node.code)
        self.end(") # Function")
        self.append("")
  
      def visitFunction(self, node):
        # .name .argnames .defaults .flags .doc .code
        self.function(node, 0)
  
      def visitGetattr(self, node):
        # .expr
        # .attrname
        self.set_lineno(node)
        self.begin("GetAttr(")
        self.visit(node.expr)
        self.append("Attr(%s)" % node.attrname)
        self.end(") # GetAttr")
  
      def visitGlobal(self, node):
        # .names
        self.set_lineno(node)
        self.begin("Global(")
          for n in node.names:
            self.append("Name(%s)" % n)
        self.end(") # Global")
  
      def visitIf(self, node):
        # .tests .else_
        self.set_lineno(node)
        self.begin("If(")
        self.begin("Tests(")
          for test, suite in node.tests:
            self.visit(test)
            self.visit(suite)
        self.end(") # Tests")
        if node.else_:
            self.visit(node.else_)
        else:
            self.append("_()")
        self.end(") # If")
  
      def visitImport(self, node):
        # .names
        self.set_lineno(node)
        self.begin("Py_Import(")
          for name, alias in node.names:
            self.append("py_import(%s, %s)" % (name, alias))
        self.end(") # Py_Import")
  
      def visitInvert(self, node):
        # .expr
        self.set_lineno(node)
        self.begin("Unary(")
        self.append("Op('~')")
        self.visit(node.expr)
        self.end(") # Unary")
  
      def visitKeyword(self, node):
        # .name .expr
        # f(x=y)
        self.set_lineno(node)
        self.begin("Kw_arg(")
        self.append("Name(%s)" % node.name)
        self.visit(node.expr)
        self.end(") # Kw_arg")
  
      def visitLamda(self, node):
        # .argnames .defaults .flags .code
        self.function(node, 1)
  
      def visitLeftShift(self, node):
        self.binary(node, '<<')
  
      def visitList(self, node):
        # .nodes
        self.set_lineno(node)
        self.begin("List(")
        for n in node.nodes:
            self.visit(n)
        self.end(") # List")
  
      def visitListComp(self, node):
        assert(0)       # TODO
      def visitListCompFor(self, node):
        assert(0)       # TODO
      def visitListCompIf(self, node):
        assert(0)       # TODO
  
      def visitMod(self, node):
        self.binary(node, '%')
  
      def visitModule(self, node):
        self.set_lineno(node)
        # walk through and collect some information first
        self.begin("Py_Module(")
        if node.doc:
            self.append("Py_doc(" + `node.doc` + ")")
        self.find_locals(node.node)
        self.visit(node.node)
        self.end(") # Py_Module")
  
      def visitMul(self, node):
        self.binary(node, '*')
  
      def visitName(self, node):
        # .name
        self.set_lineno(node)
        self.append("Name(" + node.name + ")")
  
      def visitNot(self, node):
        # .expr
        self.set_lineno(node)
        self.begin("Unary(")
        self.append("Op('!')")
        self.visit(node.expr)
        self.end(") # Unary")
  
      def visitOr(self, node):
        self.set_lineno(node)
        self.expr_helper(node.nodes, "Or")
  
      def visitPass(self, node):
        pass
  
      def visitPow(self, node):
        self.binary(node, '**')
  
      def visitPrint(self, node):
        # .nodes .dest
        self.set_lineno(node)
        pio = ""
        self.set_lineno(node)
        self.begin("Py_Print(")
        if node.dest:
            self.append("Handle(")
            self.visit(node.dest)
            self.append(") # Handle")
        for n in node.nodes:
            self.visit(n)
        self.end(") # Py_Print")
  
      def visitPrintnl(self, node):
        self.set_lineno(node)
        self.visitPrint(node)
        self.append("Py_Print_nl()")
  
      def visitRaise(self, node):
        # .expr1 .expr2 .expr2
        self.set_lineno(node)
        self.begin("Raise(")
        self.visit(node.expr1)
        if node.expr2:
            self.visit(node.expr2)
            if node.expr3:
                self.visit(node.expr3)
        self.end(") # Raise")
  
      def visitReturn(self, node):
        # .value
        self.set_lineno(node)
        self.begin("Return(")
        self.visit(node.value)
        self.end(") # Return")
  
      def visitRightShift(self, node):
        self.binary(node, '>>')
  
      def visitSlice(self, node):
        # .expr .flags .lower .upper
        self.set_lineno(node)
        self.begin("Slice(")
        self.visit(node.expr)
        if node.lower:
            self.visit(node.lower)
        else:
            self.append("_()")
        if node.upper:
            self.visit(node.upper)
        else:
            self.append("_()")
        self.end(") # Slice")
  
      def visitSliceobj(self, node):
        # .nodes
        assert(0)       # TODO
  
      def visitStmt(self, node):
        # .nodes
        self.set_lineno(node)
        self.begin("Stmts(")
        for n in node.nodes:
            self.visit(n)
        self.end(") # Stmts")
  
      def visitSub(self, node):
        self.binary(node, '-')
  
      def visitSubscript(self, node):
        # .expr .flags .subs
        self.set_lineno(node)
        self.begin("Subscript(")        # TODO flags
        self.visit(node.expr)
        for n in node.subs:
            self.visit(n)
        self.end(") # Subscript")
  
      def visitTryExcept(self, node):
        # .body .handlers .else_
        self.set_lineno(node)
        self.begin("TryExcept(")
        self.visit(node.body)
        self.begin("Handler(")
        for expr, target, body in node.handlers:
            self.visit(expr)
            if target:
                self.visit(target)
            else:
                self.append("_()")
            self.visit(body)
        self.end(") # Handler")
        if node.else_:
            self.visit(node.else_)
        else:
            self.append("_()")
  
        self.end(") # TryExcept")
  
      def visitTryFinally(self, node):
        # .body .final
        self.set_lineno(node)
        self.begin("TryFinally(")
        self.visit(node.body)
        self.visit(node.final)
        self.end(") # TryFinally")
  
      def visitTuple(self, node):
        # .nodes
        self.set_lineno(node)
        self.begin("Tuple(")
        for n in node.nodes:
            self.visit(n)
        self.end(") # Tuple")
  
      def visitUnaryAdd(self, node):
        # .expr
        self.set_lineno(node)
        self.begin("Unary(")
        self.append("Op('+')")
        self.visit(node.expr)
        self.end(") # UnaryAdd")
  
      def visitUnarySub(self, node):
        # .expr
        self.set_lineno(node)
        self.begin("Unary(")
        self.append("Op('-')")
        self.visit(node.expr)
        self.end(") # UnarySub")
  
      def visitWhile(self, node):
        # .test .body .else_
        self.set_lineno(node)
        self.begin("While(")
        self.visit(node.test)
        self.visit(node.body)
        if node.else_:
            self.visit(node.else_)
        else:
            self.append("_()")
        self.end(") # While")
  
      def visitYield(self, node):
        # .value
        self.set_lineno(node)
        self.begin("Yield(")
        self.visit(node.value)
        self.end(") # Yield")
  
  
  #############################################
  
  import time
  HEAD=\
  '''
  # generated by pie-rate on %s
  ''' % time.asctime()
  
  def compile(src, fn, name="__main__", dump=False, debug=False,
      lines=False, source = False, verbose = False):
      ast = compiler.parse(src)
      if dump:
        print "# " + `ast`
      vis = compiler.visitor.ExampleASTVisitor()
      # vis.preorder(ast, pir)
      pir = PirateVisitor(name)
      pir._debug = debug
      pir._lines = lines
      pir._verbose = verbose
      pir._src = src
      pir._print_source = source
      compiler.visitor.walk(ast, pir, vis, 1)
      pir.append("# end")
      [EMAIL PROTECTED]: refactor this mess:
      if name=="__main__":
          lines = [ "Src_File(\"%s\")" % fn
                  ]
  
          pir.lines = lines + pir.lines
      code =  pir.getCode()
      return code
  
  def invoke(code, options=""):
      i,o = os.popen4("parrot %s -" % options)
      print >> i, HEAD
      print >> i, code
      i.close()
      return o.read()
  
  if __name__=="__main__":
      import sys
      import getopt
  
      if len(sys.argv) > 1:
        try:
            opts, args = getopt.getopt(sys.argv[1:], 'dDlop:rsv')
        except getopt.GetoptError:
            print __doc__
            sys.exit()
          # file or stdin?
        if args[0] == '-':
            src = sys.stdin.read()
            fn = "<stdin>"
        else:
            fn = args[0]
            src = open(fn).read()
        lines = debug = dump = out = source = verbose = 0
        run = 0 # N/Y
        out = 1
        parrot_options = ""
        for o, a in opts:
            if o == "-D":
                dump = 1
            if o == "-d":
                debug = 1
            if o == "-l":
                lines = 1
            if o == "-o":
                out = 1
                run -= 1
            if o == "-r":
                run += 1
            if o == "-s":
                source = 1
            if o == "-v":
                verbose = 1
            if o == "-p":
                parrot_options = a
        code = compile(src, fn, dump=dump, debug=debug, lines=lines,
            source=source, verbose=verbose)
          # dump or run?
        if out:
              print HEAD
              print code
          if run:
              sys.stdout.write(invoke(code, parrot_options))
      else:
          print __doc__
          sys.exit()
  
  # vim: sw=4 tw=70:
  
  
  

Reply via email to