[pypy-svn] r6270 - pypy/branch/pypy-genc/translator

arigo at codespeak.net arigo at codespeak.net
Thu Sep 2 17:43:22 CEST 2004


Author: arigo
Date: Thu Sep  2 17:43:22 2004
New Revision: 6270

Modified:
   pypy/branch/pypy-genc/translator/genc.h
   pypy/branch/pypy-genc/translator/genc.py
   pypy/branch/pypy-genc/translator/typer.py
Log:
- Support for constant string objects.
- Factored bits of constant_representation() to can_convert_to_pyobj().
    It's still quite big, though.
- Support for built-in functions in genc.py.
- New macro syntax CALL_funcname_typecodes in genc.h for typed built-in calls.
- In typer.py, replaced an infinite recursion with an error message (always a
    good idea).



Modified: pypy/branch/pypy-genc/translator/genc.h
==============================================================================
--- pypy/branch/pypy-genc/translator/genc.h	(original)
+++ pypy/branch/pypy-genc/translator/genc.h	Thu Sep  2 17:43:22 2004
@@ -91,5 +91,11 @@
 	}
 
 
+/* a few built-in functions */
+
+#define CALL_len_oi(o,r,err)  if ((r=PyObject_Size(o))<0) goto err;
+#define CALL_pow_iii(x,y,r)   { int i=y; r=1; while (--i>=0) r*=x; } /*slow*/
+
+
 /************************************************************/
  /***  The rest is produced by genc.py                     ***/

Modified: pypy/branch/pypy-genc/translator/genc.py
==============================================================================
--- pypy/branch/pypy-genc/translator/genc.py	(original)
+++ pypy/branch/pypy-genc/translator/genc.py	Thu Sep  2 17:43:22 2004
@@ -2,10 +2,10 @@
 Generate a C source file from the flowmodel.
 
 """
-import autopath, os, re
+import autopath, os, re, types, __builtin__
 from pypy.objspace.flow.model import Variable, Constant, UndefinedConstant
 from pypy.objspace.flow.model import Block, Link, traverse
-from pypy.translator.typer import LLFunction, LLOp, LLConst
+from pypy.translator.typer import LLFunction, LLOp, LLConst, TypingError
 from pypy.annotation import model as annmodel
 
 
@@ -24,10 +24,6 @@
             return '<C: %s>' % ' + '.join(self.impl)
 
 
-class TypingError(Exception):
-    pass
-
-
 class CTypeSet:
     "A (small) set of C types that typer.LLFunction can manipulate."
 
@@ -72,10 +68,12 @@
         return hltype.impl
 
     def typingerror(self, opname, hltypes):
-        # build operations with a variable number of argument on demand
+        # build operations with a variable number of arguments on demand
         if opname == 'OP_NEWLIST':
             opnewlist = self.lloperations.setdefault('OP_NEWLIST', {})
             sig = (self.R_OBJECT,) * len(hltypes)
+            if sig in opnewlist:
+                return False
             def writer(*stuff):
                 content = stuff[:-2]
                 result = stuff[-2]
@@ -87,8 +85,23 @@
                         result, i, content[i], content[i]))
                 return '\n'.join(ls)
             opnewlist[sig] = writer, True
-            return   # retry
-        raise TypingError((opname,) + hltypes)
+            return True   # retry
+        if opname == 'OP_SIMPLE_CALL' and hltypes:
+            opsimplecall = self.lloperations.setdefault('OP_SIMPLE_CALL', {})
+            sig = (self.R_OBJECT,) * len(hltypes)
+            if sig in opsimplecall:
+                return False
+            def writer(func, *stuff):
+                args = stuff[:-2]
+                result = stuff[-2]
+                err = stuff[-1]
+                format = 'O' * len(args)
+                return ('if (!(%s = PyObject_CallFunction(%s, "%s", %s)))'
+                        ' goto %s;' % (result, func, format,
+                                       ', '.join(args), err))
+            opsimplecall[sig] = writer, True
+            return True   # retry
+        return False
 
     def knownanswer(self, llname):
         if hasattr(llname, 'known_answer'):
@@ -131,25 +144,17 @@
                 conv[r, self.R_INT] = writer, False
                 writer.known_answer = [LLConst(self.R_INT, '%d' % value)]
                 # can convert the constant to a PyObject*
-                def writer(z, err):
-                    return 'convert_io(%d, %s, %s)' % (value, z, err)
-                conv[r, self.R_OBJECT] = writer, True
-                llconst = LLConst('PyObject*', 'g_IntObject_%d' % value)
-                writer.known_answer = [llconst]
-                writer.globaldefs_decl = [llconst]
-                writer.globaldefs_impl = ['%s = PyInt_FromLong(%d);' %
-                                          (llconst.name, value)]
+                self.can_convert_to_pyobj(r, 'PyInt_FromLong(%d)' % value,
+                                          'g_IntObj_%d' % value)
             elif isinstance(value, str):
                 # can convert the constant to a PyObject*
-                def writer(z, err):
-                    return 'convert_so(%s, %d, %s, %s)' % (
-                        (c_str(value), len(value), z, err))
-                conv[r, self.R_OBJECT] = writer, True
+                self.can_convert_to_pyobj(r,
+                    'PyString_FromStringAndSize(%s, %d)' % (c_str(value),
+                                                            len(value)),
+                    'g_StrObj_%s' % manglestr(value))
             elif value is None:
                 # can convert the constant to Py_None
-                def writer(z):
-                    return 'convert_vo(%s)' % (z,)
-                conv[r, self.R_OBJECT] = writer, False
+                self.can_convert_to_pyobj(r, 'Py_None')
             elif callable(value) and value in self.genc.llfunctions:
                 # another Python function: can be called with OP_SIMPLE_CALL
                 llfunc = self.genc.llfunctions[value]
@@ -176,10 +181,42 @@
                 else:
                     XXX("to do")
                 ops[tuple(sig)] = writer, True
+            elif (isinstance(value, types.BuiltinFunctionType) and
+                  value is getattr(__builtin__, value.__name__, None)):
+                # a function from __builtin__: can convert to PyObject*
+                self.can_convert_to_pyobj(r,
+                    'PyMapping_GetItemString(PyEval_GetBuiltins(), %s)' % (
+                    c_str(value.__name__)),
+                    'g_Builtin_%s' % manglestr(value.__name__))
+                # if the function is defined in genc.h, import its definition
+                # by copying the operation CALL_xxx to OP_SIMPLE_CALL with
+                # a first argument which is the constant function xxx.
+                opname = 'CALL_' + value.__name__
+                if opname in self.lloperations:
+                    ops = self.lloperations.setdefault('OP_SIMPLE_CALL', {})
+                    for sig, ll in self.lloperations[opname].items():
+                        sig = (r,) + sig
+                        ops[sig] = ll
             else:
                 print "// XXX not implemented: constant", key
             return r
 
+    def can_convert_to_pyobj(self, r, initexpr, globalname=None):
+        conv = self.lloperations['convert']
+        if globalname is not None:
+            def writer(z, err):
+                return 'if (!(%s = %s)) goto %s;' % (z, initexpr, err)
+            conv[r, self.R_OBJECT] = writer, True
+            llconst = LLConst('PyObject*', globalname)
+            writer.globaldefs_decl = [llconst]
+            writer.globaldefs_impl = ['%s = %s;' % (llconst.name, initexpr)]
+        else:
+            def writer(z):
+                return '%s = %s; Py_INCREF(%s);' % (z, initexpr, z)
+            conv[r, self.R_OBJECT] = writer, False
+            llconst = LLConst('PyObject*', initexpr)
+        writer.known_answer = [llconst]
+
     def parse_operation_templates(self):
         # parse the genc.h header to figure out which macros are implemented
         codes = ''.join(self.REPR_BY_CODE.keys())
@@ -209,6 +246,18 @@
         s = '"' + s[1:-1].replace('"', r'\"') + '"'
     return s
 
+def manglestr(s):
+    "Return an identifier name unique for the string 's'."
+    l = []
+    for c in s:
+        if not ('a' <= c <= 'z' or 'A' <= c <= 'Z' or '0' <= c <= '9'):
+            if c == '_':
+                c = '__'
+            else:
+                c = '_%02x' % ord(c)
+        l.append(c)
+    return ''.join(l)
+
 # ____________________________________________________________
 
 

Modified: pypy/branch/pypy-genc/translator/typer.py
==============================================================================
--- pypy/branch/pypy-genc/translator/typer.py	(original)
+++ pypy/branch/pypy-genc/translator/typer.py	Thu Sep  2 17:43:22 2004
@@ -23,6 +23,9 @@
         self.args = args    # list of LLVars
         self.errtarget = errtarget  # label to jump to in case of error
 
+class TypingError(Exception):
+    pass
+
 
 # ____________________________________________________________
 #
@@ -54,8 +57,8 @@
 #
 #   def typingerror(self, opname, hltypes):
 #       Called when no match is found in lloperations.  This function must
-#       either extend lloperations and return (to retry), or raise an
-#       exception (to stop).
+#       either extend lloperations and return True to retry, or return
+#       False to fail.
 #
 #   def knownanswer(self, llname):
 #       Optionally returns a list of LLVars that give the well-known, constant
@@ -235,12 +238,17 @@
                 llname, can_fail = llsigs[sig]
                 break
         else:
-            self.typingerror(opname, tuple(args_t))
+            retry = self.typingerror(opname, tuple(args_t))
             # if 'typingerror' did not raise an exception, try again.
             # infinite recursion here means that 'typingerror' did not
             # correctly extend 'lloperations'.
-            self.operation(opname, args, result, errlabel, resulttype)
-            return
+            if retry:
+                try:
+                    self.operation(opname, args, result, errlabel, resulttype)
+                    return
+                except RuntimeError:   # infinite recursion
+                    pass
+            raise TypingError([opname] + args_t)
         # check if the answer has an existing well-known answer
         if resulttype is not None:  # if we are allowed to patch self.llreprs
             llrepr = self.knownanswer(llname)



More information about the Pypy-commit mailing list