text: from bgenOutput import *
  from bgenType import *
  from bgenVariable import *
  
  
  Error = "bgenGenerator.Error"
  
  DEBUG=0
  
  # Strings to specify argument transfer modes in generator calls
  IN = "in"
  OUT = "out"
  INOUT = IN_OUT = "in-out"
  
  
  class BaseFunctionGenerator:
  
      def __init__(self, name, condition=None, callname=None, modifiers=None):
          if DEBUG: print "<--", name
          self.name = name
          if callname:
              self.callname = callname
          else:
              self.callname = name
          self.prefix = name
          self.objecttype = "PyObject" # Type of _self argument to function
          self.condition = condition
          self.modifiers = modifiers
  
      def setprefix(self, prefix):
          self.prefix = prefix
  
      def checkgenerate(self):
          return True
  
      def generate(self):
          if not self.checkgenerate():
              return
          if DEBUG: print "-->", self.name
          if self.condition:
              Output()
              Output(self.condition)
          self.functionheader()
          self.functionbody()
          self.functiontrailer()
          if self.condition:
              Output("#endif")
  
      def functionheader(self):
          Output()
          Output("static PyObject *%s_%s(%s *_self, PyObject *_args)",
                 self.prefix, self.name, self.objecttype)
          OutLbrace()
          Output("PyObject *_res = NULL;")
  
      def functionbody(self):
          Output("/* XXX To be provided */")
  
      def functiontrailer(self):
          OutRbrace()
  
      def reference(self, name = None):
          if not self.checkgenerate():
              return
          if name is None:
              name = self.name
          docstring = self.docstring()
          if self.condition:
              Output()
              Output(self.condition)
          Output("{\"%s\", (PyCFunction)%s_%s, 1,", name, self.prefix, self.name)
          Output(" PyDoc_STR(%s)},", stringify(docstring))
          if self.condition:
              Output("#endif")
  
      def docstring(self):
          return None
  
      def __cmp__(self, other):
          if not hasattr(other, 'name'):
              return cmp(id(self), id(other))
          return cmp(self.name, other.name)
  
  _stringify_map = {'\n': '\\n', '\t': '\\t', '\r': '\\r', '\b': '\\b',
                    '\e': '\\e', '\a': '\\a', '\f': '\\f', '"': '\\"'}
  def stringify(str):
      if str is None: return "NULL"
      res = '"'
      map = _stringify_map
      for c in str:
          if map.has_key(c): res = res + map[c]
          elif ' ' <= c <= '~': res = res + c
          else: res = res + '\\%03o' % ord(c)
      res = res + '"'
      return res
  
  
  class ManualGenerator(BaseFunctionGenerator):
  
      def __init__(self, name, body, condition=None):
          BaseFunctionGenerator.__init__(self, name, condition=condition)
          self.body = body
  
      def functionbody(self):
          Output("%s", self.body)
  
      def setselftype(self, selftype, itselftype):
          self.objecttype = selftype
          self.itselftype = itselftype
  
  
  class FunctionGenerator(BaseFunctionGenerator):
  
      def __init__(self, returntype, name, *argumentList, **conditionlist):
          BaseFunctionGenerator.__init__(self, name, **conditionlist)
          self.returntype = returntype
          self.argumentList = []
          self.setreturnvar()
          self.parseArgumentList(argumentList)
          self.prefix     = "XXX"    # Will be changed by setprefix() call
          self.itselftype = None     # Type of _self->ob_itself, if defined
  
      def setreturnvar(self):
          if self.returntype:
              self.rv = self.makereturnvar()
              self.argumentList.append(self.rv)
          else:
              self.rv = None
  
      def makereturnvar(self):
          return Variable(self.returntype, "_rv", OutMode)
  
      def setselftype(self, selftype, itselftype):
          self.objecttype = selftype
          self.itselftype = itselftype
  
      def parseArgumentList(self, argumentList):
          iarg = 0
          for type, name, mode in argumentList:
              iarg = iarg + 1
              if name is None: name = "_arg%d" % iarg
              arg = Variable(type, name, mode)
              self.argumentList.append(arg)
  
      def docstring(self):
          input = []
          output = []
          for arg in self.argumentList:
              if arg.flags == ErrorMode or arg.flags == SelfMode:
                  continue
              if arg.type is None:
                  str = 'void'
              else:
                  if hasattr(arg.type, 'typeName'):
                      typeName = arg.type.typeName
                      if typeName is None: # Suppressed type
                          continue
                  else:
                      typeName = "?"
                      print "Nameless type", arg.type
  
                  str = typeName + ' ' + arg.name
              if arg.mode in (InMode, InOutMode):
                  input.append(str)
              if arg.mode in (InOutMode, OutMode):
                  output.append(str)
          if not input:
              instr = "()"
          else:
              instr = "(%s)" % ", ".join(input)
          if not output or output == ["void"]:
              outstr = "None"
          else:
              outstr = "(%s)" % ", ".join(output)
          return instr + " -> " + outstr
  
      def functionbody(self):
          self.declarations()
          self.precheck()
          self.getargs()
          self.callit()
          self.checkit()
          self.returnvalue()
  
      def declarations(self):
          for arg in self.argumentList:
              arg.declare()
  
      def getargs(self):
          sep = ",\n" + ' '*len("if (!PyArg_ParseTuple(")
          fmt, lst = self.getargsFormatArgs(sep)
          Output("if (!PyArg_ParseTuple(_args, \"%s\"%s))", fmt, lst)
          IndentLevel()
          Output("return NULL;")
          DedentLevel()
          for arg in self.argumentList:
              if arg.flags == SelfMode:
                  continue
              if arg.mode in (InMode, InOutMode):
                  arg.getargsCheck()
  
      def getargsFormatArgs(self, sep):
          fmt = ""
          lst = ""
          for arg in self.argumentList:
              if arg.flags == SelfMode:
                  continue
              if arg.mode in (InMode, InOutMode):
                  arg.getargsPreCheck()
                  fmt = fmt + arg.getargsFormat()
                  args = arg.getargsArgs()
                  if args:
                      lst = lst + sep + args
          return fmt, lst
  
      def precheck(self):
          pass
  
      def beginallowthreads(self):
          pass
  
      def endallowthreads(self):
          pass
  
      def callit(self):
          args = ""
          s = "%s%s(" % (self.getrvforcallit(), self.callname)
          sep = ",\n" + ' '*len(s)
          for arg in self.argumentList:
              if arg is self.rv:
                  continue
              s = arg.passArgument()
              if args: s = sep + s
              args = args + s
          self.beginallowthreads()
          Output("%s%s(%s);",
                 self.getrvforcallit(), self.callname, args)
          self.endallowthreads()
  
      def getrvforcallit(self):
          if self.rv:
              return "%s = " % self.rv.name
          else:
              return ""
  
      def checkit(self):
          for arg in self.argumentList:
              arg.errorCheck()
  
      def returnvalue(self):
          sep = ",\n" + ' '*len("return Py_BuildValue(")
          fmt, lst = self.mkvalueFormatArgs(sep)
          if fmt == "":
              Output("Py_INCREF(Py_None);")
              Output("_res = Py_None;");
          else:
              Output("_res = Py_BuildValue(\"%s\"%s);", fmt, lst)
          tmp = self.argumentList[:]
          tmp.reverse()
          for arg in tmp:
              if not arg: continue
              arg.cleanup()
          Output("return _res;")
  
      def mkvalueFormatArgs(self, sep):
          fmt = ""
          lst = ""
          for arg in self.argumentList:
              if not arg: continue
              if arg.flags == ErrorMode: continue
              if arg.mode in (OutMode, InOutMode):
                  arg.mkvaluePreCheck()
                  fmt = fmt + arg.mkvalueFormat()
                  lst = lst + sep + arg.mkvalueArgs()
          return fmt, lst
  
  class MethodGenerator(FunctionGenerator):
  
      def parseArgumentList(self, args):
          a0, args = args[0], args[1:]
          t0, n0, m0 = a0
          if m0 != InMode:
              raise ValueError, "method's 'self' must be 'InMode'"
          self.itself = Variable(t0, "_self->ob_itself", SelfMode)
          self.argumentList.append(self.itself)
          FunctionGenerator.parseArgumentList(self, args)
  
  def _test():
      void = None
      eggs = FunctionGenerator(void, "eggs",
                   (stringptr, 'cmd', InMode),
                   (int, 'x', InMode),
                   (double, 'y', InOutMode),
                   (int, 'status', ErrorMode),
                   )
      eggs.setprefix("spam")
      print "/* START */"
      eggs.generate()
  
  
  if __name__ == "__main__":
      _test()
  